diff options
764 files changed, 26252 insertions, 21714 deletions
diff --git a/.gitignore b/.gitignore index b3b13694af..b1de1d79d8 100644 --- a/.gitignore +++ b/.gitignore @@ -141,14 +141,9 @@ uptime-*.json /src/common/libor-ctime.a /src/common/libor-ctime-testing.a /src/common/libor-ctime.lib -/src/common/libor-crypto.a -/src/common/libor-crypto-testing.a -/src/common/libor-crypto.lib /src/common/libor-event.a /src/common/libor-event-testing.a /src/common/libor-event.lib -/src/common/libcurve25519_donna.a -/src/common/libcurve25519_donna.lib # /src/config/ /src/config/Makefile @@ -166,6 +161,62 @@ uptime-*.json /src/ext/keccak-tiny/libkeccak-tiny.a /src/ext/keccak-tiny/libkeccak-tiny.lib +# /src/lib +/src/lib/libcurve25519_donna.a +/src/lib/libtor-compress.a +/src/lib/libtor-compress-testing.a +/src/lib/libtor-container.a +/src/lib/libtor-container-testing.a +/src/lib/libtor-crypt-ops.a +/src/lib/libtor-crypt-ops-testing.a +/src/lib/libtor-ctime.a +/src/lib/libtor-ctime-testing.a +/src/lib/libtor-encoding.a +/src/lib/libtor-encoding-testing.a +/src/lib/libtor-err.a +/src/lib/libtor-err-testing.a +/src/lib/libtor-fdio.a +/src/lib/libtor-fdio-testing.a +/src/lib/libtor-fs.a +/src/lib/libtor-fs-testing.a +/src/lib/libtor-intmath.a +/src/lib/libtor-intmath-testing.a +/src/lib/libtor-lock.a +/src/lib/libtor-lock-testing.a +/src/lib/libtor-log.a +/src/lib/libtor-log-testing.a +/src/lib/libtor-malloc.a +/src/lib/libtor-malloc-testing.a +/src/lib/libtor-math.a +/src/lib/libtor-math-testing.a +/src/lib/libtor-memarea.a +/src/lib/libtor-memarea-testing.a +/src/lib/libtor-meminfo.a +/src/lib/libtor-meminfo-testing.a +/src/lib/libtor-net.a +/src/lib/libtor-net-testing.a +/src/lib/libtor-osinfo.a +/src/lib/libtor-osinfo-testing.a +/src/lib/libtor-process.a +/src/lib/libtor-process-testing.a +/src/lib/libtor-sandbox.a +/src/lib/libtor-sandbox-testing.a +/src/lib/libtor-string.a +/src/lib/libtor-string-testing.a +/src/lib/libtor-smartlist-core.a +/src/lib/libtor-smartlist-core-testing.a +/src/lib/libtor-term.a +/src/lib/libtor-term-testing.a +/src/lib/libtor-thread.a +/src/lib/libtor-thread-testing.a +/src/lib/libtor-time.a +/src/lib/libtor-time-testing.a +/src/lib/libtor-tls.a +/src/lib/libtor-tls-testing.a +/src/lib/libtor-trace.a +/src/lib/libtor-wallclock.a +/src/lib/libtor-wallclock-testing.a + # /src/or/ /src/or/Makefile /src/or/Makefile.in @@ -173,8 +224,8 @@ uptime-*.json /src/or/tor.exe /src/or/tor-cov /src/or/tor-cov.exe -/src/or/libtor.a -/src/or/libtor-testing.a +/src/or/libtor-app.a +/src/or/libtor-app-testing.a /src/or/libtor.lib # /src/rust @@ -1,3 +1,72 @@ +Changes in version 0.3.4.3-alpha - 2018-06-26 + Tor 0.3.4.3-alpha fixes several bugs in earlier versions, including + one that was causing stability issues on directory authorities. + + o Major bugfixes (directory authority): + - Stop leaking memory on directory authorities when planning to + vote. This bug was crashing authorities by exhausting their + memory. Fixes bug 26435; bugfix on 0.3.3.6. + + o Major bugfixes (rust, testing): + - Make sure that failing tests in Rust will actually cause the build + to fail: previously, they were ignored. Fixes bug 26258; bugfix + on 0.3.3.4-alpha. + + o Minor feature (directory authorities): + - Stop warning about incomplete bw lines before the first complete + bw line has been found, so that additional header lines can be + ignored. Fixes bug 25960; bugfix on 0.2.2.1-alpha + + o Minor features (relay, diagnostic): + - Add several checks to detect whether Tor relays are uploading + their descriptors without specifying why they regenerated them. + Diagnostic for ticket 25686. + + o Minor features (unit tests): + - Test complete bandwidth measurements files, and test that + incomplete bandwidth lines only give warnings when the end of the + header has not been detected. Fixes bug 25947; bugfix + on 0.2.2.1-alpha + + o Minor bugfixes (compilation): + - Refrain from compiling unit testing related object files when + --disable-unittests is set to configure script. Fixes bug 24891; + bugfix on 0.2.5.1-alpha. + - When linking the libtor_testing.a library, only include the + dirauth object files once. Previously, they were getting added + twice. Fixes bug 26402; bugfix on 0.3.4.1-alpha. + - The --enable-fatal-warnings flag now affects Rust code as well. + Closes ticket 26245. + + o Minor bugfixes (onion services): + - Recompute some consensus information after detecting a clock jump, + or after transitioning from a non-live consensus to a live + consensus. We do this to avoid having an outdated state, and + miscalculating the index for next-generation onion services. Fixes + bug 24977; bugfix on 0.3.2.1-alpha. + + o Minor bugfixes (relay): + - Relays now correctly block attempts to re-extend to the previous + relay by Ed25519 identity. Previously they would warn in this + case, but not actually reject the attempt. Fixes bug 26158; bugfix + on 0.3.0.1-alpha. + + o Minor bugfixes (testing): + - Fix compilation of the doctests in the Rust crypto crate. Fixes + bug 26415; bugfix on 0.3.4.1-alpha. + - Instead of trying to read the geoip configuration files from + within the unit tests, instead create our own ersatz files with + just enough geoip data in the format we expect. Trying to read + from the source directory created problems on Windows with mingw, + where the build system's paths are not the same as the platform's + paths. Fixes bug 25787; bugfix on 0.3.4.1-alpha. + - Refrain from trying to get an item from an empty smartlist in + test_bridges_clear_bridge_list. Set DEBUG_SMARTLIST in unit tests + to catch improper smartlist usage. Furthermore, enable + DEBUG_SMARTLIST globally when build is configured with fragile + hardening. Fixes bug 26196; bugfix on 0.3.4.1-alpha. + + Changes in version 0.3.3.7 - 2018-06-12 Tor 0.3.3.7 backports several changes from the 0.3.4.x series, including fixes for bugs affecting compatibility and stability. @@ -28476,4 +28545,3 @@ Changes in version 0.0.2pre13 - 2003-10-19 - If --DebugLogFile is specified, log to it at -l debug - If --LogFile is specified, use it instead of commandline - If --RunAsDaemon is set, tor forks and backgrounds on startup - @@ -13,7 +13,7 @@ Tor is distributed under this license: Copyright (c) 2001-2004, Roger Dingledine Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson -Copyright (c) 2007-2017, The Tor Project, Inc. +Copyright (c) 2007-2018, The Tor Project, Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/Makefile.am b/Makefile.am index 58ff9fb3e8..8fa6f9970f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ # Copyright (c) 2001-2004, Roger Dingledine # Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson -# Copyright (c) 2007-2017, The Tor Project, Inc. +# Copyright (c) 2007-2018, The Tor Project, Inc. # See LICENSE for licensing information ACLOCAL_AMFLAGS = -I m4 @@ -15,7 +15,12 @@ TESTS= noinst_PROGRAMS= DISTCLEANFILES= bin_SCRIPTS= -AM_CPPFLAGS= +AM_CPPFLAGS=\ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/ext \ + -I$(top_srcdir)/src/ext/trunnel \ + -I$(top_srcdir)/src/trunnel + AM_CFLAGS=@TOR_SYSTEMD_CFLAGS@ @CFLAGS_BUGTRAP@ @TOR_LZMA_CFLAGS@ @TOR_ZSTD_CFLAGS@ SHELL=@SHELL@ @@ -32,6 +37,99 @@ else rust_ldadd= endif +# "Common" libraries used to link tor's utility code. +TOR_UTIL_LIBS = \ + src/common/libor.a \ + src/lib/libtor-process.a \ + src/lib/libtor-time.a \ + src/lib/libtor-fs.a \ + src/lib/libtor-encoding.a \ + src/lib/libtor-sandbox.a \ + src/lib/libtor-container.a \ + src/lib/libtor-net.a \ + src/lib/libtor-thread.a \ + src/lib/libtor-memarea.a \ + src/lib/libtor-math.a \ + src/lib/libtor-meminfo.a \ + src/lib/libtor-osinfo.a \ + src/lib/libtor-log.a \ + src/lib/libtor-lock.a \ + src/lib/libtor-fdio.a \ + src/lib/libtor-string.a \ + src/lib/libtor-term.a \ + src/lib/libtor-smartlist-core.a \ + src/lib/libtor-malloc.a \ + src/lib/libtor-wallclock.a \ + src/lib/libtor-err.a \ + src/lib/libtor-intmath.a \ + src/lib/libtor-ctime.a + +# Variants of the above for linking the testing variant of tor (for coverage +# and tests) +TOR_UTIL_TESTING_LIBS = \ + src/common/libor-testing.a \ + src/lib/libtor-process-testing.a \ + src/lib/libtor-time-testing.a \ + src/lib/libtor-fs-testing.a \ + src/lib/libtor-encoding-testing.a \ + src/lib/libtor-sandbox-testing.a \ + src/lib/libtor-container-testing.a \ + src/lib/libtor-net-testing.a \ + src/lib/libtor-thread-testing.a \ + src/lib/libtor-memarea-testing.a \ + src/lib/libtor-math-testing.a \ + src/lib/libtor-meminfo-testing.a \ + src/lib/libtor-osinfo-testing.a \ + src/lib/libtor-term-testing.a \ + src/lib/libtor-log-testing.a \ + src/lib/libtor-lock-testing.a \ + src/lib/libtor-fdio-testing.a \ + src/lib/libtor-string-testing.a \ + src/lib/libtor-smartlist-core-testing.a \ + src/lib/libtor-malloc-testing.a \ + src/lib/libtor-wallclock-testing.a \ + src/lib/libtor-err-testing.a \ + src/lib/libtor-intmath.a \ + src/lib/libtor-ctime-testing.a + +# Internal crypto libraries used in Tor +TOR_CRYPTO_LIBS = \ + src/lib/libtor-tls.a \ + src/lib/libtor-crypt-ops.a \ + $(LIBKECCAK_TINY) \ + $(LIBDONNA) + +# Variants of the above for linking the testing variant of tor (for coverage +# and tests) +TOR_CRYPTO_TESTING_LIBS = \ + src/lib/libtor-tls-testing.a \ + src/lib/libtor-crypt-ops-testing.a \ + $(LIBKECCAK_TINY) \ + $(LIBDONNA) + +# All static libraries used to link tor. +TOR_INTERNAL_LIBS = \ + src/or/libtor-app.a \ + src/lib/libtor-compress.a \ + $(TOR_CRYPTO_LIBS) \ + $(TOR_UTIL_LIBS) \ + src/common/libor-event.a \ + src/trunnel/libor-trunnel.a \ + src/lib/libtor-trace.a + +# Variants of the above for linking the testing variant of tor (for coverage +# and tests) +TOR_INTERNAL_TESTING_LIBS = \ + src/or/libtor-app-testing.a \ + src/lib/libtor-compress-testing.a \ + $(TOR_CRYPTO_TESTING_LIBS) \ + $(TOR_UTIL_TESTING_LIBS) \ + src/common/libor-event-testing.a \ + src/trunnel/libor-trunnel-testing.a \ + src/lib/libtor-trace.a + +# All libraries used to link tor-cov + include src/include.am include doc/include.am include contrib/include.am @@ -44,6 +142,7 @@ EXTRA_DIST+= \ Makefile.nmake \ README \ ReleaseNotes \ + scripts/maint/checkIncludes.py \ scripts/maint/checkSpace.pl ## This tells etags how to find mockable function definitions. @@ -205,12 +304,19 @@ check-spaces: if USE_PERL $(PERL) $(top_srcdir)/scripts/maint/checkSpace.pl -C \ $(top_srcdir)/src/common/*.[ch] \ + $(top_srcdir)/src/lib/*/*.[ch] \ $(top_srcdir)/src/or/*.[ch] \ + $(top_srcdir)/src/or/*/*.[ch] \ $(top_srcdir)/src/test/*.[ch] \ $(top_srcdir)/src/test/*/*.[ch] \ $(top_srcdir)/src/tools/*.[ch] endif +check-includes: +if USEPYTHON + $(top_srcdir)/scripts/maint/checkIncludes.py +endif + check-docs: all $(PERL) $(top_builddir)/scripts/maint/checkOptionDocs.pl @@ -238,6 +344,20 @@ check-typos: echo "You can install the latest version of misspell here: https://github.com/client9/misspell#install"; \ fi +.PHONY: clippy +clippy: +if USE_RUST + @if test -x "`which cargo-clippy 2>&1;true`"; then \ + echo "Running cargo clippy ..."; \ + echo "Prepare yourself for the onslaught of suggestions ..."; \ + (cd "$(top_srcdir)/src/rust" && cargo clippy); \ + else \ + echo "Tor can use clippy to lint Rust code."; \ + echo "However, it seems that you don't have clippy installed."; \ + echo "You can install the latest version of clippy by following the directions here: https://github.com/rust-lang-nursery/rust-clippy"; \ + fi +endif + .PHONY: check-changes check-changes: if USEPYTHON diff --git a/acinclude.m4 b/acinclude.m4 index 49d4f14471..c9cfc3f014 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -2,7 +2,7 @@ dnl Helper macros for Tor configure.ac dnl Copyright (c) 2001-2004, Roger Dingledine dnl Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson dnl Copyright (c) 2007-2008, Roger Dingledine, Nick Mathewson -dnl Copyright (c) 2007-2017, The Tor Project, Inc. +dnl Copyright (c) 2007-2018, The Tor Project, Inc. dnl See LICENSE for licensing information AC_DEFUN([TOR_EXTEND_CODEPATH], diff --git a/changes/bug22156 b/changes/bug22156 new file mode 100644 index 0000000000..685f2a551b --- /dev/null +++ b/changes/bug22156 @@ -0,0 +1,3 @@ + o Minor features (development): + - Tor's makefile now supports running the "clippy" Rust style tool + on our Rust code. Closes ticket 22156. diff --git a/changes/bug25477 b/changes/bug25477 new file mode 100644 index 0000000000..0eac06137f --- /dev/null +++ b/changes/bug25477 @@ -0,0 +1,3 @@ + o Minor bugfixes (logging): + - Refrain from mentioning bug 21018, as it is already fixed. + Fixes bug 25477; bugfix on 0.2.9.8. diff --git a/changes/bug25886 b/changes/bug25886 new file mode 100644 index 0000000000..45f9a54069 --- /dev/null +++ b/changes/bug25886 @@ -0,0 +1,7 @@ + o Minor bugfixes (relay): + - In frac_nodes_with_descriptors(), add for_direct_connect, and replace + node_has_any_descriptor() with node_has_preferred_descriptor(). Also, + if we are using bridges and there is at least one bridge with a full + descriptor, set f_guard in compute_frac_paths_available() to 1.0. + Fixes bug 25886; bugfix on 0.3.5.1-alpha. Patch by Neel Chauhan. + diff --git a/changes/bug26152 b/changes/bug26152 new file mode 100644 index 0000000000..34fda09b25 --- /dev/null +++ b/changes/bug26152 @@ -0,0 +1,4 @@ + o Minor bugfixes (testing): + - When logging a version mismatch in our openssl_version tests, + report the actual offending version strings. Fixes bug 26152; bugfix on + 0.2.9.1-alpha. diff --git a/changes/bug26214 b/changes/bug26214 new file mode 100644 index 0000000000..4277b9c6ec --- /dev/null +++ b/changes/bug26214 @@ -0,0 +1,3 @@ + o Minor bugfixes (correctness, flow control): + - Upon receiving a stream-level SENDME cell, verify that our window has + not grown too large. Fixes bug 26214; bugfix on svn r54 (pre-0.0.1) diff --git a/changes/bug26282 b/changes/bug26282 new file mode 100644 index 0000000000..c278f0b60a --- /dev/null +++ b/changes/bug26282 @@ -0,0 +1,4 @@ + o Minor bugfixes (C correctness): + - Avoid casting smartlist index to int implicitly, as it may trigger + a warning (-Wshorten-64-to-32). Fixes bug 26282; bugfix on + 0.2.3.13-alpha, 0.2.7.1-alpha and 0.2.1.1-alpha. diff --git a/changes/feature8323 b/changes/feature8323 new file mode 100644 index 0000000000..6fbc972d26 --- /dev/null +++ b/changes/feature8323 @@ -0,0 +1,3 @@ + o Minor features (controller): + - Implement 'GETINFO md/all' controller command to enable + getting all known microdesriptors. Closes ticket 8323. diff --git a/changes/full_include_paths b/changes/full_include_paths new file mode 100644 index 0000000000..c0ac0a05d3 --- /dev/null +++ b/changes/full_include_paths @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Include paths to header files within Tor are now qualified by directory + within the top-level src directory. diff --git a/changes/iphplapi b/changes/iphplapi new file mode 100644 index 0000000000..806f71c3f3 --- /dev/null +++ b/changes/iphplapi @@ -0,0 +1,4 @@ + o Removed features: + - Tor no longer attempts to run on Windows environments without the + GetAdaptersAddresses() function. This function has existed since + Windows XP, which is itself already older than we support. diff --git a/changes/split_or_h b/changes/split_or_h new file mode 100644 index 0000000000..53d54ca6dd --- /dev/null +++ b/changes/split_or_h @@ -0,0 +1,5 @@ + o Code simplification and refactoring: + - Many structures have been removed from the centralized "or.h" header, + and moved into their own headers. This will allow us to reduce + the number of places in the code that rely on each structure's + contents and layout. Closes ticket 26383. diff --git a/changes/ticket19979 b/changes/ticket19979 new file mode 100644 index 0000000000..a6bf93f1a4 --- /dev/null +++ b/changes/ticket19979 @@ -0,0 +1,3 @@ + o Minor features (openssl): + - When possible, use RFC5869 HKDF implementation from OpenSSL. + Resolves ticket 19979. diff --git a/changes/ticket26426 b/changes/ticket26426 new file mode 100644 index 0000000000..05fa974943 --- /dev/null +++ b/changes/ticket26426 @@ -0,0 +1,4 @@ + o Removed features: + - Tor no longer supports building with the dmalloc library. For debugging + memory issues, we suggest using gperftools or msan instead. + Closes ticket 26426. diff --git a/changes/ticket26427 b/changes/ticket26427 new file mode 100644 index 0000000000..ff33f7bd4c --- /dev/null +++ b/changes/ticket26427 @@ -0,0 +1,6 @@ + o Minor features (code layout): + - Make a new lowest-level error-handling API for use by code invoked + from within the logging module. This interface it makes it so + the logging code is no longer at risk of calling into itself if + a failure occurs while trying to log something. + Closes ticket 26427. diff --git a/changes/ticket26510 b/changes/ticket26510 new file mode 100644 index 0000000000..f00457964d --- /dev/null +++ b/changes/ticket26510 @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Unify our bloom filter logic. Previously we had two copies of this + code: one for routerlist filtering, and one for address set + calculations. Closes ticket 26510. diff --git a/configure.ac b/configure.ac index f557faf1c6..38d4303699 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,10 @@ dnl Copyright (c) 2001-2004, Roger Dingledine dnl Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson -dnl Copyright (c) 2007-2017, The Tor Project, Inc. +dnl Copyright (c) 2007-2018, The Tor Project, Inc. dnl See LICENSE for licensing information AC_PREREQ([2.63]) -AC_INIT([tor],[0.3.4.3-alpha-dev]) +AC_INIT([tor],[0.3.5.0-alpha-dev]) AC_CONFIG_SRCDIR([src/or/main.c]) AC_CONFIG_MACRO_DIR([m4]) @@ -21,16 +21,6 @@ AC_CANONICAL_HOST PKG_PROG_PKG_CONFIG -if test -f "/etc/redhat-release"; then - if test -f "/usr/kerberos/include"; then - CPPFLAGS="$CPPFLAGS -I/usr/kerberos/include" - fi -fi - -# Not a no-op; we want to make sure that CPPFLAGS is set before we use -# the += operator on it in src/or/Makefile.am -CPPFLAGS="$CPPFLAGS -I\${top_srcdir}/src/common" - AC_ARG_ENABLE(openbsd-malloc, AS_HELP_STRING(--enable-openbsd-malloc, [use malloc code from OpenBSD. Linux only])) AC_ARG_ENABLE(static-openssl, @@ -432,7 +422,7 @@ AH_BOTTOM([ #endif ]) - +AM_CONDITIONAL(WIN32, test "x$bwin32" = "xtrue") AM_CONDITIONAL(BUILD_NT_SERVICES, test "x$bwin32" = "xtrue") AM_CONDITIONAL(BUILD_LIBTORRUNNER, test "x$bwin32" != "xtrue") @@ -1353,8 +1343,7 @@ AC_SUBST(CURVE25519_LIBS) dnl Make sure to enable support for large off_t if available. AC_SYS_LARGEFILE -AC_CHECK_HEADERS([assert.h \ - errno.h \ +AC_CHECK_HEADERS([errno.h \ fcntl.h \ signal.h \ string.h \ @@ -1767,26 +1756,6 @@ if test "$tor_cv_uint8_uchar" = "no"; then AC_MSG_ERROR([We assume that uint8_t is the same type as unsigned char, but your compiler disagrees.]) fi -# Whether we should use the dmalloc memory allocation debugging library. -AC_MSG_CHECKING(whether to use dmalloc (debug memory allocation library)) -AC_ARG_WITH(dmalloc, -AS_HELP_STRING(--with-dmalloc, [use debug memory allocation library]), -[if [[ "$withval" = "yes" ]]; then - dmalloc=1 - AC_MSG_RESULT(yes) -else - dmalloc=1 - AC_MSG_RESULT(no) -fi], [ dmalloc=0; AC_MSG_RESULT(no) ] -) - -if [[ $dmalloc -eq 1 ]]; then - AC_CHECK_HEADERS(dmalloc.h, , AC_MSG_ERROR(dmalloc header file not found. Do you have the development files for dmalloc installed?)) - AC_SEARCH_LIBS(dmalloc_malloc, [dmallocth dmalloc], , AC_MSG_ERROR(Libdmalloc library not found. If you enable it you better have it installed.)) - AC_DEFINE(USE_DMALLOC, 1, [Debug memory allocation library]) - AC_CHECK_FUNCS(dmalloc_strdup dmalloc_strndup) -fi - AC_ARG_WITH(tcmalloc, AS_HELP_STRING(--with-tcmalloc, [use tcmalloc memory allocation library]), [ tcmalloc=yes ], [ tcmalloc=no ]) diff --git a/contrib/win32build/tor-mingw.nsi.in b/contrib/win32build/tor-mingw.nsi.in index 32f1f23e7d..c9822790bb 100644 --- a/contrib/win32build/tor-mingw.nsi.in +++ b/contrib/win32build/tor-mingw.nsi.in @@ -8,7 +8,7 @@ !include "LogicLib.nsh" !include "FileFunc.nsh" !insertmacro GetParameters -!define VERSION "0.3.4.3-alpha-dev" +!define VERSION "0.3.5.0-alpha-dev" !define INSTALLER "tor-${VERSION}-win32.exe" !define WEBSITE "https://www.torproject.org/" !define LICENSE "LICENSE" diff --git a/doc/HACKING/CodingStandards.md b/doc/HACKING/CodingStandards.md index 3711f70198..b830ecea93 100644 --- a/doc/HACKING/CodingStandards.md +++ b/doc/HACKING/CodingStandards.md @@ -172,7 +172,6 @@ deviations from our C whitespace style. Generally, we use: - Unix-style line endings - K&R-style indentation - No space before newlines - - A blank line at the end of each file - Never more than one blank line in a row - Always spaces, never tabs - No more than 79-columns per line. @@ -185,6 +184,9 @@ deviations from our C whitespace style. Generally, we use: `puts (x)`. - Function declarations at the start of the line. +If you use an editor that has plugins for editorconfig.org, the file +`.editorconfig` will help you to conform this coding style. + We try hard to build without warnings everywhere. In particular, if you're using gcc, you should invoke the configure script with the option `--enable-fatal-warnings`. This will tell the compiler @@ -434,4 +436,3 @@ the functions that call your function rely on it doing something, then your function should mention that it does that something in the documentation. If you rely on a function doing something beyond what is in its documentation, then you should watch out, or it might do something else later. - diff --git a/doc/HACKING/HelpfulTools.md b/doc/HACKING/HelpfulTools.md index a0795076e0..eb068a91f3 100644 --- a/doc/HACKING/HelpfulTools.md +++ b/doc/HACKING/HelpfulTools.md @@ -25,16 +25,6 @@ Jenkins https://jenkins.torproject.org -Dmalloc -------- - -The dmalloc library will keep track of memory allocation, so you can find out -if we're leaking memory, doing any double-frees, or so on. - - dmalloc -l -/dmalloc.log - (run the commands it tells you) - ./configure --with-dmalloc - Valgrind -------- diff --git a/scripts/codegen/gen_server_ciphers.py b/scripts/codegen/gen_server_ciphers.py index 7ea39c540d..5b2eef07ef 100755 --- a/scripts/codegen/gen_server_ciphers.py +++ b/scripts/codegen/gen_server_ciphers.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright 2014-2017, The Tor Project, Inc +# Copyright 2014-2018, The Tor Project, Inc # See LICENSE for licensing information # This script parses openssl headers to find ciphersuite names, determines diff --git a/scripts/codegen/get_mozilla_ciphers.py b/scripts/codegen/get_mozilla_ciphers.py index 946957ac77..4f986daba9 100755 --- a/scripts/codegen/get_mozilla_ciphers.py +++ b/scripts/codegen/get_mozilla_ciphers.py @@ -1,6 +1,6 @@ #!/usr/bin/python # coding=utf-8 -# Copyright 2011-2017, The Tor Project, Inc +# Copyright 2011-2018, The Tor Project, Inc # original version by Arturo Filastò # See LICENSE for licensing information diff --git a/scripts/codegen/makedesc.py b/scripts/codegen/makedesc.py index 8d9d4edaaf..4ee8106f03 100644 --- a/scripts/codegen/makedesc.py +++ b/scripts/codegen/makedesc.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright 2014-2017, The Tor Project, Inc. +# Copyright 2014-2018, The Tor Project, Inc. # See LICENSE for license information # This is a kludgey python script that uses ctypes and openssl to sign diff --git a/scripts/maint/checkIncludes.py b/scripts/maint/checkIncludes.py new file mode 100755 index 0000000000..3c611675e4 --- /dev/null +++ b/scripts/maint/checkIncludes.py @@ -0,0 +1,72 @@ +#!/usr/bin/python3 +# Copyright 2018 The Tor Project, Inc. See LICENSE file for licensing info. + +import fnmatch +import os +import re +import sys + +trouble = False + +def err(msg): + global trouble + trouble = True + print(msg, file=sys.stderr) + +def fname_is_c(fname): + return fname.endswith(".h") or fname.endswith(".c") + +INCLUDE_PATTERN = re.compile(r'\s*#\s*include\s+"([^"]*)"') +RULES_FNAME = ".may_include" + +class Rules(object): + def __init__(self): + self.patterns = [] + + def addPattern(self, pattern): + self.patterns.append(pattern) + + def includeOk(self, path): + for pattern in self.patterns: + if fnmatch.fnmatchcase(path, pattern): + return True + return False + + def applyToLines(self, lines, context=""): + lineno = 0 + for line in lines: + lineno += 1 + m = INCLUDE_PATTERN.match(line) + if m: + include = m.group(1) + if not self.includeOk(include): + err("Forbidden include of {} on line {}{}".format( + include, lineno, context)) + + def applyToFile(self, fname): + with open(fname, 'r') as f: + #print(fname) + self.applyToLines(iter(f), " of {}".format(fname)) + +def load_include_rules(fname): + result = Rules() + with open(fname, 'r') as f: + for line in f: + line = line.strip() + if line.startswith("#") or not line: + continue + result.addPattern(line) + return result + +for dirpath, dirnames, fnames in os.walk("src"): + if ".may_include" in fnames: + rules = load_include_rules(os.path.join(dirpath, RULES_FNAME)) + for fname in fnames: + if fname_is_c(fname): + rules.applyToFile(os.path.join(dirpath,fname)) + +if trouble: + err( +"""To change which includes are allowed in a C file, edit the {} files in its +enclosing directory.""".format(RULES_FNAME)) + sys.exit(1) diff --git a/scripts/maint/checkSpace.pl b/scripts/maint/checkSpace.pl index 9929932cc5..633b47e314 100755 --- a/scripts/maint/checkSpace.pl +++ b/scripts/maint/checkSpace.pl @@ -16,12 +16,21 @@ if ($ARGV[0] =~ /^-/) { $C = ($lang eq '-C'); } +our %basenames = (); + for my $fn (@ARGV) { open(F, "$fn"); my $lastnil = 0; my $lastline = ""; my $incomment = 0; my $in_func_head = 0; + my $basename = $fn; + $basename =~ s#.*/##; + if ($basenames{$basename}) { + msg "Duplicate fnames: $fn and $basenames{$basename}.\n"; + } else { + $basenames{$basename} = $fn; + } while (<F>) { ## Warn about windows-style newlines. # (We insist on lines that end with a single LF character, not @@ -126,7 +135,7 @@ for my $fn (@ARGV) { ## Warn about double semi-colons at the end of a line. if (/;;$/) { msg " double semi-colons at the end of $. in $fn\n" - } + } ## Warn about multiple internal spaces. #if (/[^\s,:]\s{2,}[^\s\\=]/) { # msg " X X:$fn:$.\n"; @@ -192,11 +201,6 @@ for my $fn (@ARGV) { } } } - ## Warn if the file doesn't end with a blank line. - # (End each file with a single blank line.) - if (! $lastnil) { - msg " EOL\@EOF:$fn:$.\n"; - } close(F); } diff --git a/scripts/maint/format_changelog.py b/scripts/maint/format_changelog.py index c5a0cfc81b..98fbbfb516 100755 --- a/scripts/maint/format_changelog.py +++ b/scripts/maint/format_changelog.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright (c) 2014-2017, The Tor Project, Inc. +# Copyright (c) 2014-2018, The Tor Project, Inc. # See LICENSE for licensing information # # This script reformats a section of the changelog to wrap everything to diff --git a/scripts/maint/rectify_include_paths.py b/scripts/maint/rectify_include_paths.py new file mode 100755 index 0000000000..401fadae6d --- /dev/null +++ b/scripts/maint/rectify_include_paths.py @@ -0,0 +1,60 @@ +#!/usr/bin/python3 + +import os +import os.path +import re + +# Find all the include files, map them to their real names. + +def exclude(paths, dirnames): + for p in paths: + if p in dirnames: + dirnames.remove(p) + +def get_include_map(): + includes = { } + + for dirpath,dirnames,fnames in os.walk("src"): + exclude(["ext", "win32"], dirnames) + + for fname in fnames: + if fname.endswith(".h"): + assert fname not in includes + include = os.path.join(dirpath, fname) + assert include.startswith("src/") + includes[fname] = include[4:] + + return includes + +INCLUDE_PAT = re.compile(r'( *# *include +")([^"]+)(".*)') + +def get_base_header_name(hdr): + return os.path.split(hdr)[1] + +def fix_includes(inp, out, mapping): + for line in inp: + m = INCLUDE_PAT.match(line) + if m: + include,hdr,rest = m.groups() + basehdr = get_base_header_name(hdr) + if basehdr in mapping: + out.write('{}{}{}\n'.format(include,mapping[basehdr],rest)) + continue + + out.write(line) + +incs = get_include_map() + +for dirpath,dirnames,fnames in os.walk("src"): + exclude(["trunnel"], dirnames) + + for fname in fnames: + if fname.endswith(".c") or fname.endswith(".h"): + fname = os.path.join(dirpath, fname) + tmpfile = fname+".tmp" + f_in = open(fname, 'r') + f_out = open(tmpfile, 'w') + fix_includes(f_in, f_out, incs) + f_in.close() + f_out.close() + os.rename(tmpfile, fname) diff --git a/scripts/maint/redox.py b/scripts/maint/redox.py index 53d3d902eb..e8b2622ab9 100755 --- a/scripts/maint/redox.py +++ b/scripts/maint/redox.py @@ -1,6 +1,6 @@ #!/usr/bin/python # -# Copyright (c) 2008-2017, The Tor Project, Inc. +# Copyright (c) 2008-2018, The Tor Project, Inc. # See LICENSE for licensing information. # # Hi! diff --git a/scripts/maint/sortChanges.py b/scripts/maint/sortChanges.py index 22e40fd369..c85e6563b8 100755 --- a/scripts/maint/sortChanges.py +++ b/scripts/maint/sortChanges.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright (c) 2014-2017, The Tor Project, Inc. +# Copyright (c) 2014-2018, The Tor Project, Inc. # See LICENSE for licensing information """This script sorts a bunch of changes files listed on its command diff --git a/scripts/maint/updateCopyright.pl b/scripts/maint/updateCopyright.pl index beb0b8f26e..bd24377d38 100755 --- a/scripts/maint/updateCopyright.pl +++ b/scripts/maint/updateCopyright.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl -i -w -p -$NEWYEAR=2017; +$NEWYEAR=2018; -s/Copyright(.*) (201[^7]), The Tor Project/Copyright$1 $2-${NEWYEAR}, The Tor Project/; +s/Copyright(.*) (201[^8]), The Tor Project/Copyright$1 $2-${NEWYEAR}, The Tor Project/; s/Copyright(.*)-(20..), The Tor Project/Copyright$1-${NEWYEAR}, The Tor Project/; diff --git a/src/common/.may_include b/src/common/.may_include new file mode 100644 index 0000000000..fab9ad0da8 --- /dev/null +++ b/src/common/.may_include @@ -0,0 +1,11 @@ +orconfig.h +common/*.h +lib/*/*.h + +# XXXX These all belong somewhere else +ht.h +linux_syscalls.inc +siphash.h +src/ext/timeouts/timeout.c +tor_queue.h +tor_readpassphrase.h diff --git a/src/common/address_set.c b/src/common/address_set.c index b2f4bb4c95..1bd1462387 100644 --- a/src/common/address_set.c +++ b/src/common/address_set.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,38 +11,20 @@ **/ #include "orconfig.h" -#include "address_set.h" -#include "address.h" -#include "compat.h" -#include "container.h" -#include "crypto_rand.h" -#include "util.h" +#include "common/address_set.h" +#include "lib/net/address.h" +#include "lib/container/bloomfilt.h" +#include "lib/crypt_ops/crypto_rand.h" #include "siphash.h" -/** How many 64-bit siphash values to extract per address */ -#define N_HASHES 2 -/** How many bloom-filter bits we set per address. This is twice the N_HASHES - * value, since we split the siphash output into two 32-bit values. */ -#define N_BITS_PER_ITEM (N_HASHES * 2) - -/* XXXX This code is largely duplicated with digestset_t. We should merge - * them together into a common bloom-filter implementation. I'm keeping - * them separate for now, though, since this module needs to be backported - * all the way to 0.2.9. - * - * The main difference between digestset_t and this code is that we use - * independent siphashes rather than messing around with bit-shifts. The - * approach here is probably more sound, and we should prefer it if&when we - * unify the implementations. - */ - -struct address_set_t { - /** siphash keys to make N_HASHES independent hashes for each address. */ - struct sipkey key[N_HASHES]; - int mask; /**< One less than the number of bits in <b>ba</b>; always one less - * than a power of two. */ - bitarray_t *ba; /**< A bit array to implement the Bloom filter. */ -}; +/* Wrap our hash function to have the signature that the bloom filter + * needs. */ +static uint64_t +bloomfilt_addr_hash(const struct sipkey *key, + const void *item) +{ + return tor_addr_keyed_hash(key, item); +} /** * Allocate and return an address_set, suitable for holding up to @@ -51,34 +33,12 @@ struct address_set_t { address_set_t * address_set_new(int max_addresses_guess) { - /* See digestset_new() for rationale on this equation. */ - int n_bits = 1u << (tor_log2(max_addresses_guess)+5); - - address_set_t *set = tor_malloc_zero(sizeof(address_set_t)); - set->mask = n_bits - 1; - set->ba = bitarray_init_zero(n_bits); - crypto_rand((char*) set->key, sizeof(set->key)); - - return set; + uint8_t k[BLOOMFILT_KEY_LEN]; + crypto_rand((void*)k, sizeof(k)); + return bloomfilt_new(max_addresses_guess, bloomfilt_addr_hash, k); } /** - * Release all storage associated with <b>set</b>. - */ -void -address_set_free(address_set_t *set) -{ - if (! set) - return; - - bitarray_free(set->ba); - tor_free(set); -} - -/** Yield the bit index corresponding to 'val' for set. */ -#define BIT(set, val) ((val) & (set)->mask) - -/** * Add <b>addr</b> to <b>set</b>. * * All future queries for <b>addr</b> in set will return true. Removing @@ -87,14 +47,7 @@ address_set_free(address_set_t *set) void address_set_add(address_set_t *set, const struct tor_addr_t *addr) { - int i; - for (i = 0; i < N_HASHES; ++i) { - uint64_t h = tor_addr_keyed_hash(&set->key[i], addr); - uint32_t high_bits = (uint32_t)(h >> 32); - uint32_t low_bits = (uint32_t)(h); - bitarray_set(set->ba, BIT(set, high_bits)); - bitarray_set(set->ba, BIT(set, low_bits)); - } + bloomfilt_add(set, addr); } /** As address_set_add(), but take an ipv4 address in host order. */ @@ -111,19 +64,8 @@ address_set_add_ipv4h(address_set_t *set, uint32_t addr) * return false if <b>addr</b> is not a member of set.) */ int -address_set_probably_contains(address_set_t *set, +address_set_probably_contains(const address_set_t *set, const struct tor_addr_t *addr) { - int i, matches = 0; - for (i = 0; i < N_HASHES; ++i) { - uint64_t h = tor_addr_keyed_hash(&set->key[i], addr); - uint32_t high_bits = (uint32_t)(h >> 32); - uint32_t low_bits = (uint32_t)(h); - // Note that !! is necessary here, since bitarray_is_set does not - // necessarily return 1 on true. - matches += !! bitarray_is_set(set->ba, BIT(set, high_bits)); - matches += !! bitarray_is_set(set->ba, BIT(set, low_bits)); - } - return matches == N_BITS_PER_ITEM; + return bloomfilt_probably_contains(set, addr); } - diff --git a/src/common/address_set.h b/src/common/address_set.h index 28d29f3fdf..2efa1cb03b 100644 --- a/src/common/address_set.h +++ b/src/common/address_set.h @@ -1,35 +1,31 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file address_set.h * \brief Types to handle sets of addresses. - * - * This module was first written on a semi-emergency basis to improve the - * robustness of the anti-DoS module. As such, it's written in a pretty - * conservative way, and should be susceptible to improvement later on. **/ #ifndef TOR_ADDRESS_SET_H #define TOR_ADDRESS_SET_H #include "orconfig.h" -#include "torint.h" +#include "lib/cc/torint.h" +#include "lib/container/bloomfilt.h" /** * An address_set_t represents a set of tor_addr_t values. The implementation * is probabilistic: false negatives cannot occur but false positives are * possible. */ -typedef struct address_set_t address_set_t; +typedef struct bloomfilt_t address_set_t; struct tor_addr_t; address_set_t *address_set_new(int max_addresses_guess); -void address_set_free(address_set_t *set); +#define address_set_free(set) bloomfilt_free(set) void address_set_add(address_set_t *set, const struct tor_addr_t *addr); void address_set_add_ipv4h(address_set_t *set, uint32_t addr); -int address_set_probably_contains(address_set_t *set, +int address_set_probably_contains(const address_set_t *set, const struct tor_addr_t *addr); #endif - diff --git a/src/common/compat.c b/src/common/compat.c deleted file mode 100644 index 6fdd6ecf00..0000000000 --- a/src/common/compat.c +++ /dev/null @@ -1,3531 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compat.c - * \brief Wrappers to make calls more portable. This code defines - * functions such as tor_snprintf, get/set various data types, - * renaming, setting socket options, switching user IDs. It is basically - * where the non-portable items are conditionally included depending on - * the platform. - **/ - -#define COMPAT_PRIVATE -#include "compat.h" - -#ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#include <sys/locking.h> -#endif - -#ifdef HAVE_UNAME -#include <sys/utsname.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_SYSCTL_H -#include <sys/sysctl.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_UTIME_H -#include <utime.h> -#endif -#ifdef HAVE_SYS_UTIME_H -#include <sys/utime.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SYS_FCNTL_H -#include <sys/fcntl.h> -#endif -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif -#ifdef HAVE_GRP_H -#include <grp.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#ifdef HAVE_CRT_EXTERNS_H -#include <crt_externs.h> -#endif -#ifdef HAVE_SYS_STATVFS_H -#include <sys/statvfs.h> -#endif -#ifdef HAVE_SYS_CAPABILITY_H -#include <sys/capability.h> -#endif - -#ifdef _WIN32 -#include <conio.h> -#include <wchar.h> -/* Some mingw headers lack these. :p */ -#if defined(HAVE_DECL__GETWCH) && !HAVE_DECL__GETWCH -wint_t _getwch(void); -#endif -#ifndef WEOF -#define WEOF (wchar_t)(0xFFFF) -#endif -#if defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY -static inline void -SecureZeroMemory(PVOID ptr, SIZE_T cnt) -{ - volatile char *vcptr = (volatile char*)ptr; - while (cnt--) - *vcptr++ = 0; -} -#endif /* defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY */ -#elif defined(HAVE_READPASSPHRASE_H) -#include <readpassphrase.h> -#else -#include "tor_readpassphrase.h" -#endif /* defined(_WIN32) || ... */ - -/* Includes for the process attaching prevention */ -#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) -/* Only use the linux prctl; the IRIX prctl is totally different */ -#include <sys/prctl.h> -#elif defined(__APPLE__) -#include <sys/ptrace.h> -#endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) || ... */ - -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> /* FreeBSD needs this to know what version it is */ -#endif -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#ifdef HAVE_MMAP -#include <sys/mman.h> -#endif -#ifdef HAVE_SYS_SYSLIMITS_H -#include <sys/syslimits.h> -#endif -#ifdef HAVE_SYS_FILE_H -#include <sys/file.h> -#endif - -#include "torlog.h" -#include "util.h" -#include "container.h" -#include "address.h" -#include "sandbox.h" - -/* Inline the strl functions if the platform doesn't have them. */ -#ifndef HAVE_STRLCPY -#include "strlcpy.c" -#endif -#ifndef HAVE_STRLCAT -#include "strlcat.c" -#endif - -/* When set_max_file_descriptors() is called, update this with the max file - * descriptor value so we can use it to check the limit when opening a new - * socket. Default value is what Debian sets as the default hard limit. */ -static int max_sockets = 1024; - -/** As open(path, flags, mode), but return an fd with the close-on-exec mode - * set. */ -int -tor_open_cloexec(const char *path, int flags, unsigned mode) -{ - int fd; - const char *p = sandbox_intern_string(path); -#ifdef O_CLOEXEC - fd = open(p, flags|O_CLOEXEC, mode); - if (fd >= 0) - return fd; - /* If we got an error, see if it is EINVAL. EINVAL might indicate that, - * even though we were built on a system with O_CLOEXEC support, we - * are running on one without. */ - if (errno != EINVAL) - return -1; -#endif /* defined(O_CLOEXEC) */ - - log_debug(LD_FS, "Opening %s with flags %x", p, flags); - fd = open(p, flags, mode); -#ifdef FD_CLOEXEC - if (fd >= 0) { - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); - close(fd); - return -1; - } - } -#endif /* defined(FD_CLOEXEC) */ - return fd; -} - -/** As fopen(path,mode), but ensures that the O_CLOEXEC bit is set on the - * underlying file handle. */ -FILE * -tor_fopen_cloexec(const char *path, const char *mode) -{ - FILE *result = fopen(path, mode); -#ifdef FD_CLOEXEC - if (result != NULL) { - if (fcntl(fileno(result), F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); - fclose(result); - return NULL; - } - } -#endif /* defined(FD_CLOEXEC) */ - return result; -} - -/** As rename(), but work correctly with the sandbox. */ -int -tor_rename(const char *path_old, const char *path_new) -{ - log_debug(LD_FS, "Renaming %s to %s", path_old, path_new); - return rename(sandbox_intern_string(path_old), - sandbox_intern_string(path_new)); -} - -#if defined(HAVE_MMAP) || defined(RUNNING_DOXYGEN) -/** Try to create a memory mapping for <b>filename</b> and return it. On - * failure, return NULL. Sets errno properly, using ERANGE to mean - * "empty file". Must only be called on trusted Tor-owned files, as changing - * the underlying file's size causes unspecified behavior. */ -tor_mmap_t * -tor_mmap_file(const char *filename) -{ - int fd; /* router file */ - char *string; - int result; - tor_mmap_t *res; - size_t size, filesize; - struct stat st; - - tor_assert(filename); - - fd = tor_open_cloexec(filename, O_RDONLY, 0); - if (fd<0) { - int save_errno = errno; - int severity = (errno == ENOENT) ? LOG_INFO : LOG_WARN; - log_fn(severity, LD_FS,"Could not open \"%s\" for mmap(): %s",filename, - strerror(errno)); - errno = save_errno; - return NULL; - } - - /* Get the size of the file */ - result = fstat(fd, &st); - if (result != 0) { - int save_errno = errno; - log_warn(LD_FS, - "Couldn't fstat opened descriptor for \"%s\" during mmap: %s", - filename, strerror(errno)); - close(fd); - errno = save_errno; - return NULL; - } - size = filesize = (size_t)(st.st_size); - - if (st.st_size > SSIZE_T_CEILING || (off_t)size < st.st_size) { - log_warn(LD_FS, "File \"%s\" is too large. Ignoring.",filename); - errno = EFBIG; - close(fd); - return NULL; - } - if (!size) { - /* Zero-length file. If we call mmap on it, it will succeed but - * return NULL, and bad things will happen. So just fail. */ - log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); - errno = ERANGE; - close(fd); - return NULL; - } - - string = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0); - close(fd); - if (string == MAP_FAILED) { - int save_errno = errno; - log_warn(LD_FS,"Could not mmap file \"%s\": %s", filename, - strerror(errno)); - errno = save_errno; - return NULL; - } - - res = tor_malloc_zero(sizeof(tor_mmap_t)); - res->data = string; - res->size = filesize; - res->mapping_size = size; - - return res; -} -/** Release storage held for a memory mapping; returns 0 on success, - * or -1 on failure (and logs a warning). */ -int -tor_munmap_file(tor_mmap_t *handle) -{ - int res; - - if (handle == NULL) - return 0; - - res = munmap((char*)handle->data, handle->mapping_size); - if (res == 0) { - /* munmap() succeeded */ - tor_free(handle); - } else { - log_warn(LD_FS, "Failed to munmap() in tor_munmap_file(): %s", - strerror(errno)); - res = -1; - } - - return res; -} -#elif defined(_WIN32) -tor_mmap_t * -tor_mmap_file(const char *filename) -{ - TCHAR tfilename[MAX_PATH]= {0}; - tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t)); - int empty = 0; - HANDLE file_handle = INVALID_HANDLE_VALUE; - DWORD size_low, size_high; - uint64_t real_size; - res->mmap_handle = NULL; -#ifdef UNICODE - mbstowcs(tfilename,filename,MAX_PATH); -#else - strlcpy(tfilename,filename,MAX_PATH); -#endif - file_handle = CreateFile(tfilename, - GENERIC_READ, FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - 0); - - if (file_handle == INVALID_HANDLE_VALUE) - goto win_err; - - size_low = GetFileSize(file_handle, &size_high); - - if (size_low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { - log_warn(LD_FS,"Error getting size of \"%s\".",filename); - goto win_err; - } - if (size_low == 0 && size_high == 0) { - log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); - empty = 1; - goto err; - } - real_size = (((uint64_t)size_high)<<32) | size_low; - if (real_size > SIZE_MAX) { - log_warn(LD_FS,"File \"%s\" is too big to map; not trying.",filename); - goto err; - } - res->size = real_size; - - res->mmap_handle = CreateFileMapping(file_handle, - NULL, - PAGE_READONLY, - size_high, - size_low, - NULL); - if (res->mmap_handle == NULL) - goto win_err; - res->data = (char*) MapViewOfFile(res->mmap_handle, - FILE_MAP_READ, - 0, 0, 0); - if (!res->data) - goto win_err; - - CloseHandle(file_handle); - return res; - win_err: { - DWORD e = GetLastError(); - int severity = (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) ? - LOG_INFO : LOG_WARN; - char *msg = format_win32_error(e); - log_fn(severity, LD_FS, "Couldn't mmap file \"%s\": %s", filename, msg); - tor_free(msg); - if (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) - errno = ENOENT; - else - errno = EINVAL; - } - err: - if (empty) - errno = ERANGE; - if (file_handle != INVALID_HANDLE_VALUE) - CloseHandle(file_handle); - tor_munmap_file(res); - return NULL; -} - -/* Unmap the file, and return 0 for success or -1 for failure */ -int -tor_munmap_file(tor_mmap_t *handle) -{ - if (handle == NULL) - return 0; - - if (handle->data) { - /* This is an ugly cast, but without it, "data" in struct tor_mmap_t would - have to be redefined as non-const. */ - BOOL ok = UnmapViewOfFile( (LPVOID) handle->data); - if (!ok) { - log_warn(LD_FS, "Failed to UnmapViewOfFile() in tor_munmap_file(): %d", - (int)GetLastError()); - } - } - - if (handle->mmap_handle != NULL) - CloseHandle(handle->mmap_handle); - tor_free(handle); - - return 0; -} -#else -#error "cannot implement tor_mmap_file" -#endif /* defined(HAVE_MMAP) || ... || ... */ - -/** Replacement for snprintf. Differs from platform snprintf in two - * ways: First, always NUL-terminates its output. Second, always - * returns -1 if the result is truncated. (Note that this return - * behavior does <i>not</i> conform to C99; it just happens to be - * easier to emulate "return -1" with conformant implementations than - * it is to emulate "return number that would be written" with - * non-conformant implementations.) */ -int -tor_snprintf(char *str, size_t size, const char *format, ...) -{ - va_list ap; - int r; - va_start(ap,format); - r = tor_vsnprintf(str,size,format,ap); - va_end(ap); - return r; -} - -/** Replacement for vsnprintf; behavior differs as tor_snprintf differs from - * snprintf. - */ -int -tor_vsnprintf(char *str, size_t size, const char *format, va_list args) -{ - int r; - if (size == 0) - return -1; /* no place for the NUL */ - if (size > SIZE_T_CEILING) - return -1; -#ifdef _WIN32 - r = _vsnprintf(str, size, format, args); -#else - r = vsnprintf(str, size, format, args); -#endif - str[size-1] = '\0'; - if (r < 0 || r >= (ssize_t)size) - return -1; - return r; -} - -/** - * Portable asprintf implementation. Does a printf() into a newly malloc'd - * string. Sets *<b>strp</b> to this string, and returns its length (not - * including the terminating NUL character). - * - * You can treat this function as if its implementation were something like - <pre> - char buf[_INFINITY_]; - tor_snprintf(buf, sizeof(buf), fmt, args); - *strp = tor_strdup(buf); - return strlen(*strp): - </pre> - * Where _INFINITY_ is an imaginary constant so big that any string can fit - * into it. - */ -int -tor_asprintf(char **strp, const char *fmt, ...) -{ - int r; - va_list args; - va_start(args, fmt); - r = tor_vasprintf(strp, fmt, args); - va_end(args); - if (!*strp || r < 0) { - /* LCOV_EXCL_START */ - log_err(LD_BUG, "Internal error in asprintf"); - tor_assert(0); - /* LCOV_EXCL_STOP */ - } - return r; -} - -/** - * Portable vasprintf implementation. Does a printf() into a newly malloc'd - * string. Differs from regular vasprintf in the same ways that - * tor_asprintf() differs from regular asprintf. - */ -int -tor_vasprintf(char **strp, const char *fmt, va_list args) -{ - /* use a temporary variable in case *strp is in args. */ - char *strp_tmp=NULL; -#ifdef HAVE_VASPRINTF - /* If the platform gives us one, use it. */ - int r = vasprintf(&strp_tmp, fmt, args); - if (r < 0) - *strp = NULL; - else - *strp = strp_tmp; - return r; -#elif defined(HAVE__VSCPRINTF) - /* On Windows, _vsnprintf won't tell us the length of the string if it - * overflows, so we need to use _vcsprintf to tell how much to allocate */ - int len, r; - va_list tmp_args; - va_copy(tmp_args, args); - len = _vscprintf(fmt, tmp_args); - va_end(tmp_args); - if (len < 0) { - *strp = NULL; - return -1; - } - strp_tmp = tor_malloc(len + 1); - r = _vsnprintf(strp_tmp, len+1, fmt, args); - if (r != len) { - tor_free(strp_tmp); - *strp = NULL; - return -1; - } - *strp = strp_tmp; - return len; -#else - /* Everywhere else, we have a decent vsnprintf that tells us how many - * characters we need. We give it a try on a short buffer first, since - * it might be nice to avoid the second vsnprintf call. - */ - char buf[128]; - int len, r; - va_list tmp_args; - va_copy(tmp_args, args); - /* vsnprintf() was properly checked but tor_vsnprintf() available so - * why not use it? */ - len = tor_vsnprintf(buf, sizeof(buf), fmt, tmp_args); - va_end(tmp_args); - if (len < (int)sizeof(buf)) { - *strp = tor_strdup(buf); - return len; - } - strp_tmp = tor_malloc(len+1); - /* use of tor_vsnprintf() will ensure string is null terminated */ - r = tor_vsnprintf(strp_tmp, len+1, fmt, args); - if (r != len) { - tor_free(strp_tmp); - *strp = NULL; - return -1; - } - *strp = strp_tmp; - return len; -#endif /* defined(HAVE_VASPRINTF) || ... */ -} - -/** Given <b>hlen</b> bytes at <b>haystack</b> and <b>nlen</b> bytes at - * <b>needle</b>, return a pointer to the first occurrence of the needle - * within the haystack, or NULL if there is no such occurrence. - * - * This function is <em>not</em> timing-safe. - * - * Requires that <b>nlen</b> be greater than zero. - */ -const void * -tor_memmem(const void *_haystack, size_t hlen, - const void *_needle, size_t nlen) -{ -#if defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2) - tor_assert(nlen); - return memmem(_haystack, hlen, _needle, nlen); -#else - /* This isn't as fast as the GLIBC implementation, but it doesn't need to - * be. */ - const char *p, *last_possible_start; - const char *haystack = (const char*)_haystack; - const char *needle = (const char*)_needle; - char first; - tor_assert(nlen); - - if (nlen > hlen) - return NULL; - - p = haystack; - /* Last position at which the needle could start. */ - last_possible_start = haystack + hlen - nlen; - first = *(const char*)needle; - while ((p = memchr(p, first, last_possible_start + 1 - p))) { - if (fast_memeq(p, needle, nlen)) - return p; - if (++p > last_possible_start) { - /* This comparison shouldn't be necessary, since if p was previously - * equal to last_possible_start, the next memchr call would be - * "memchr(p, first, 0)", which will return NULL. But it clarifies the - * logic. */ - return NULL; - } - } - return NULL; -#endif /* defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2) */ -} - -/** - * Tables to implement ctypes-replacement TOR_IS*() functions. Each table - * has 256 bits to look up whether a character is in some set or not. This - * fails on non-ASCII platforms, but it is hard to find a platform whose - * character set is not a superset of ASCII nowadays. */ - -/**@{*/ -const uint32_t TOR_ISALPHA_TABLE[8] = - { 0, 0, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 }; -const uint32_t TOR_ISALNUM_TABLE[8] = - { 0, 0x3ff0000, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 }; -const uint32_t TOR_ISSPACE_TABLE[8] = { 0x3e00, 0x1, 0, 0, 0, 0, 0, 0 }; -const uint32_t TOR_ISXDIGIT_TABLE[8] = - { 0, 0x3ff0000, 0x7e, 0x7e, 0, 0, 0, 0 }; -const uint32_t TOR_ISDIGIT_TABLE[8] = { 0, 0x3ff0000, 0, 0, 0, 0, 0, 0 }; -const uint32_t TOR_ISPRINT_TABLE[8] = - { 0, 0xffffffff, 0xffffffff, 0x7fffffff, 0, 0, 0, 0x0 }; -const uint32_t TOR_ISUPPER_TABLE[8] = { 0, 0, 0x7fffffe, 0, 0, 0, 0, 0 }; -const uint32_t TOR_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 }; - -/** Upper-casing and lowercasing tables to map characters to upper/lowercase - * equivalents. Used by tor_toupper() and tor_tolower(). */ -/**@{*/ -const uint8_t TOR_TOUPPER_TABLE[256] = { - 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, - 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, - 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, - 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, - 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, - 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, - 96,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, - 80,81,82,83,84,85,86,87,88,89,90,123,124,125,126,127, - 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, - 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, - 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, - 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, - 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, - 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, - 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, -}; -const uint8_t TOR_TOLOWER_TABLE[256] = { - 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, - 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, - 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, - 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, - 64,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, - 112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,95, - 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, - 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, - 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, - 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, - 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, - 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, - 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, - 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, - 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, -}; -/**@}*/ - -/** Helper for tor_strtok_r_impl: Advances cp past all characters in - * <b>sep</b>, and returns its new value. */ -static char * -strtok_helper(char *cp, const char *sep) -{ - if (sep[1]) { - while (*cp && strchr(sep, *cp)) - ++cp; - } else { - while (*cp && *cp == *sep) - ++cp; - } - return cp; -} - -/** Implementation of strtok_r for platforms whose coders haven't figured out - * how to write one. Hey, retrograde libc developers! You can use this code - * here for free! */ -char * -tor_strtok_r_impl(char *str, const char *sep, char **lasts) -{ - char *cp, *start; - tor_assert(*sep); - if (str) { - str = strtok_helper(str, sep); - if (!*str) - return NULL; - start = cp = *lasts = str; - } else if (!*lasts || !**lasts) { - return NULL; - } else { - start = cp = *lasts; - } - - if (sep[1]) { - while (*cp && !strchr(sep, *cp)) - ++cp; - } else { - cp = strchr(cp, *sep); - } - - if (!cp || !*cp) { - *lasts = NULL; - } else { - *cp++ = '\0'; - *lasts = strtok_helper(cp, sep); - } - return start; -} - -#ifdef _WIN32 -/** Take a filename and return a pointer to its final element. This - * function is called on __FILE__ to fix a MSVC nit where __FILE__ - * contains the full path to the file. This is bad, because it - * confuses users to find the home directory of the person who - * compiled the binary in their warning messages. - */ -const char * -tor_fix_source_file(const char *fname) -{ - const char *cp1, *cp2, *r; - cp1 = strrchr(fname, '/'); - cp2 = strrchr(fname, '\\'); - if (cp1 && cp2) { - r = (cp1<cp2)?(cp2+1):(cp1+1); - } else if (cp1) { - r = cp1+1; - } else if (cp2) { - r = cp2+1; - } else { - r = fname; - } - return r; -} -#endif /* defined(_WIN32) */ - -/** - * Read a 16-bit value beginning at <b>cp</b>. Equivalent to - * *(uint16_t*)(cp), but will not cause segfaults on platforms that forbid - * unaligned memory access. - */ -uint16_t -get_uint16(const void *cp) -{ - uint16_t v; - memcpy(&v,cp,2); - return v; -} -/** - * Read a 32-bit value beginning at <b>cp</b>. Equivalent to - * *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid - * unaligned memory access. - */ -uint32_t -get_uint32(const void *cp) -{ - uint32_t v; - memcpy(&v,cp,4); - return v; -} -/** - * Read a 64-bit value beginning at <b>cp</b>. Equivalent to - * *(uint64_t*)(cp), but will not cause segfaults on platforms that forbid - * unaligned memory access. - */ -uint64_t -get_uint64(const void *cp) -{ - uint64_t v; - memcpy(&v,cp,8); - return v; -} - -/** - * Set a 16-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to - * *(uint16_t*)(cp) = v, but will not cause segfaults on platforms that forbid - * unaligned memory access. */ -void -set_uint16(void *cp, uint16_t v) -{ - memcpy(cp,&v,2); -} -/** - * Set a 32-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to - * *(uint32_t*)(cp) = v, but will not cause segfaults on platforms that forbid - * unaligned memory access. */ -void -set_uint32(void *cp, uint32_t v) -{ - memcpy(cp,&v,4); -} -/** - * Set a 64-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to - * *(uint64_t*)(cp) = v, but will not cause segfaults on platforms that forbid - * unaligned memory access. */ -void -set_uint64(void *cp, uint64_t v) -{ - memcpy(cp,&v,8); -} - -/** - * Rename the file <b>from</b> to the file <b>to</b>. On Unix, this is - * the same as rename(2). On windows, this removes <b>to</b> first if - * it already exists. - * Returns 0 on success. Returns -1 and sets errno on failure. - */ -int -replace_file(const char *from, const char *to) -{ -#ifndef _WIN32 - return tor_rename(from, to); -#else - switch (file_status(to)) - { - case FN_NOENT: - break; - case FN_FILE: - case FN_EMPTY: - if (unlink(to)) return -1; - break; - case FN_ERROR: - return -1; - case FN_DIR: - errno = EISDIR; - return -1; - } - return tor_rename(from,to); -#endif /* !defined(_WIN32) */ -} - -/** Change <b>fname</b>'s modification time to now. */ -int -touch_file(const char *fname) -{ - if (utime(fname, NULL)!=0) - return -1; - return 0; -} - -/** Represents a lockfile on which we hold the lock. */ -struct tor_lockfile_t { - /** Name of the file */ - char *filename; - /** File descriptor used to hold the file open */ - int fd; -}; - -/** Try to get a lock on the lockfile <b>filename</b>, creating it as - * necessary. If someone else has the lock and <b>blocking</b> is true, - * wait until the lock is available. Otherwise return immediately whether - * we succeeded or not. - * - * Set *<b>locked_out</b> to true if somebody else had the lock, and to false - * otherwise. - * - * Return a <b>tor_lockfile_t</b> on success, NULL on failure. - * - * (Implementation note: because we need to fall back to fcntl on some - * platforms, these locks are per-process, not per-thread. If you want - * to do in-process locking, use tor_mutex_t like a normal person. - * On Windows, when <b>blocking</b> is true, the maximum time that - * is actually waited is 10 seconds, after which NULL is returned - * and <b>locked_out</b> is set to 1.) - */ -tor_lockfile_t * -tor_lockfile_lock(const char *filename, int blocking, int *locked_out) -{ - tor_lockfile_t *result; - int fd; - *locked_out = 0; - - log_info(LD_FS, "Locking \"%s\"", filename); - fd = tor_open_cloexec(filename, O_RDWR|O_CREAT|O_TRUNC, 0600); - if (fd < 0) { - log_warn(LD_FS,"Couldn't open \"%s\" for locking: %s", filename, - strerror(errno)); - return NULL; - } - -#ifdef _WIN32 - _lseek(fd, 0, SEEK_SET); - if (_locking(fd, blocking ? _LK_LOCK : _LK_NBLCK, 1) < 0) { - if (errno != EACCES && errno != EDEADLOCK) - log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno)); - else - *locked_out = 1; - close(fd); - return NULL; - } -#elif defined(HAVE_FLOCK) - if (flock(fd, LOCK_EX|(blocking ? 0 : LOCK_NB)) < 0) { - if (errno != EWOULDBLOCK) - log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno)); - else - *locked_out = 1; - close(fd); - return NULL; - } -#else - { - struct flock lock; - memset(&lock, 0, sizeof(lock)); - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - if (fcntl(fd, blocking ? F_SETLKW : F_SETLK, &lock) < 0) { - if (errno != EACCES && errno != EAGAIN) - log_warn(LD_FS, "Couldn't lock \"%s\": %s", filename, strerror(errno)); - else - *locked_out = 1; - close(fd); - return NULL; - } - } -#endif /* defined(_WIN32) || ... */ - - result = tor_malloc(sizeof(tor_lockfile_t)); - result->filename = tor_strdup(filename); - result->fd = fd; - return result; -} - -/** Release the lock held as <b>lockfile</b>. */ -void -tor_lockfile_unlock(tor_lockfile_t *lockfile) -{ - tor_assert(lockfile); - - log_info(LD_FS, "Unlocking \"%s\"", lockfile->filename); -#ifdef _WIN32 - _lseek(lockfile->fd, 0, SEEK_SET); - if (_locking(lockfile->fd, _LK_UNLCK, 1) < 0) { - log_warn(LD_FS,"Error unlocking \"%s\": %s", lockfile->filename, - strerror(errno)); - } -#elif defined(HAVE_FLOCK) - if (flock(lockfile->fd, LOCK_UN) < 0) { - log_warn(LD_FS, "Error unlocking \"%s\": %s", lockfile->filename, - strerror(errno)); - } -#else - /* Closing the lockfile is sufficient. */ -#endif /* defined(_WIN32) || ... */ - - close(lockfile->fd); - lockfile->fd = -1; - tor_free(lockfile->filename); - tor_free(lockfile); -} - -/** @{ */ -/** Some old versions of Unix didn't define constants for these values, - * and instead expect you to say 0, 1, or 2. */ -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif -#ifndef SEEK_END -#define SEEK_END 2 -#endif -/** @} */ - -/** Return the position of <b>fd</b> with respect to the start of the file. */ -off_t -tor_fd_getpos(int fd) -{ -#ifdef _WIN32 - return (off_t) _lseek(fd, 0, SEEK_CUR); -#else - return (off_t) lseek(fd, 0, SEEK_CUR); -#endif -} - -/** Move <b>fd</b> to the end of the file. Return -1 on error, 0 on success. - * If the file is a pipe, do nothing and succeed. - **/ -int -tor_fd_seekend(int fd) -{ -#ifdef _WIN32 - return _lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; -#else - off_t rc = lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; -#ifdef ESPIPE - /* If we get an error and ESPIPE, then it's a pipe or a socket of a fifo: - * no need to worry. */ - if (rc < 0 && errno == ESPIPE) - rc = 0; -#endif /* defined(ESPIPE) */ - return (rc < 0) ? -1 : 0; -#endif /* defined(_WIN32) */ -} - -/** Move <b>fd</b> to position <b>pos</b> in the file. Return -1 on error, 0 - * on success. */ -int -tor_fd_setpos(int fd, off_t pos) -{ -#ifdef _WIN32 - return _lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; -#else - return lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; -#endif -} - -/** Replacement for ftruncate(fd, 0): move to the front of the file and remove - * all the rest of the file. Return -1 on error, 0 on success. */ -int -tor_ftruncate(int fd) -{ - /* Rumor has it that some versions of ftruncate do not move the file pointer. - */ - if (tor_fd_setpos(fd, 0) < 0) - return -1; - -#ifdef _WIN32 - return _chsize(fd, 0); -#else - return ftruncate(fd, 0); -#endif -} - -#undef DEBUG_SOCKET_COUNTING -#ifdef DEBUG_SOCKET_COUNTING -/** A bitarray of all fds that should be passed to tor_socket_close(). Only - * used if DEBUG_SOCKET_COUNTING is defined. */ -static bitarray_t *open_sockets = NULL; -/** The size of <b>open_sockets</b>, in bits. */ -static int max_socket = -1; -#endif /* defined(DEBUG_SOCKET_COUNTING) */ - -/** Count of number of sockets currently open. (Undercounts sockets opened by - * eventdns and libevent.) */ -static int n_sockets_open = 0; - -/** Mutex to protect open_sockets, max_socket, and n_sockets_open. */ -static tor_mutex_t *socket_accounting_mutex = NULL; - -/** Helper: acquire the socket accounting lock. */ -static inline void -socket_accounting_lock(void) -{ - if (PREDICT_UNLIKELY(!socket_accounting_mutex)) - socket_accounting_mutex = tor_mutex_new(); - tor_mutex_acquire(socket_accounting_mutex); -} - -/** Helper: release the socket accounting lock. */ -static inline void -socket_accounting_unlock(void) -{ - tor_mutex_release(socket_accounting_mutex); -} - -/** As close(), but guaranteed to work for sockets across platforms (including - * Windows, where close()ing a socket doesn't work. Returns 0 on success and - * the socket error code on failure. */ -int -tor_close_socket_simple(tor_socket_t s) -{ - int r = 0; - - /* On Windows, you have to call close() on fds returned by open(), - * and closesocket() on fds returned by socket(). On Unix, everything - * gets close()'d. We abstract this difference by always using - * tor_close_socket to close sockets, and always using close() on - * files. - */ - #if defined(_WIN32) - r = closesocket(s); - #else - r = close(s); - #endif - - if (r != 0) { - int err = tor_socket_errno(-1); - log_info(LD_NET, "Close returned an error: %s", tor_socket_strerror(err)); - return err; - } - - return r; -} - -/** As tor_close_socket_simple(), but keeps track of the number - * of open sockets. Returns 0 on success, -1 on failure. */ -MOCK_IMPL(int, -tor_close_socket,(tor_socket_t s)) -{ - int r = tor_close_socket_simple(s); - - socket_accounting_lock(); -#ifdef DEBUG_SOCKET_COUNTING - if (s > max_socket || ! bitarray_is_set(open_sockets, s)) { - log_warn(LD_BUG, "Closing a socket (%d) that wasn't returned by tor_open_" - "socket(), or that was already closed or something.", s); - } else { - tor_assert(open_sockets && s <= max_socket); - bitarray_clear(open_sockets, s); - } -#endif /* defined(DEBUG_SOCKET_COUNTING) */ - if (r == 0) { - --n_sockets_open; - } else { -#ifdef _WIN32 - if (r != WSAENOTSOCK) - --n_sockets_open; -#else - if (r != EBADF) - --n_sockets_open; // LCOV_EXCL_LINE -- EIO and EINTR too hard to force. -#endif /* defined(_WIN32) */ - r = -1; - } - - tor_assert_nonfatal(n_sockets_open >= 0); - socket_accounting_unlock(); - return r; -} - -/** @{ */ -#ifdef DEBUG_SOCKET_COUNTING -/** Helper: if DEBUG_SOCKET_COUNTING is enabled, remember that <b>s</b> is - * now an open socket. */ -static inline void -mark_socket_open(tor_socket_t s) -{ - /* XXXX This bitarray business will NOT work on windows: sockets aren't - small ints there. */ - if (s > max_socket) { - if (max_socket == -1) { - open_sockets = bitarray_init_zero(s+128); - max_socket = s+128; - } else { - open_sockets = bitarray_expand(open_sockets, max_socket, s+128); - max_socket = s+128; - } - } - if (bitarray_is_set(open_sockets, s)) { - log_warn(LD_BUG, "I thought that %d was already open, but socket() just " - "gave it to me!", s); - } - bitarray_set(open_sockets, s); -} -#else /* !(defined(DEBUG_SOCKET_COUNTING)) */ -#define mark_socket_open(s) ((void) (s)) -#endif /* defined(DEBUG_SOCKET_COUNTING) */ -/** @} */ - -/** As socket(), but counts the number of open sockets. */ -MOCK_IMPL(tor_socket_t, -tor_open_socket,(int domain, int type, int protocol)) -{ - return tor_open_socket_with_extensions(domain, type, protocol, 1, 0); -} - -/** Mockable wrapper for connect(). */ -MOCK_IMPL(tor_socket_t, -tor_connect_socket,(tor_socket_t sock, const struct sockaddr *address, - socklen_t address_len)) -{ - return connect(sock,address,address_len); -} - -/** As socket(), but creates a nonblocking socket and - * counts the number of open sockets. */ -tor_socket_t -tor_open_socket_nonblocking(int domain, int type, int protocol) -{ - return tor_open_socket_with_extensions(domain, type, protocol, 1, 1); -} - -/** As socket(), but counts the number of open sockets and handles - * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified. - * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate - * if the corresponding extension should be used.*/ -tor_socket_t -tor_open_socket_with_extensions(int domain, int type, int protocol, - int cloexec, int nonblock) -{ - tor_socket_t s; - - /* We are about to create a new file descriptor so make sure we have - * enough of them. */ - if (get_n_open_sockets() >= max_sockets - 1) { -#ifdef _WIN32 - WSASetLastError(WSAEMFILE); -#else - errno = EMFILE; -#endif - return TOR_INVALID_SOCKET; - } - -#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) - int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) | - (nonblock ? SOCK_NONBLOCK : 0); - s = socket(domain, type|ext_flags, protocol); - if (SOCKET_OK(s)) - goto socket_ok; - /* If we got an error, see if it is EINVAL. EINVAL might indicate that, - * even though we were built on a system with SOCK_CLOEXEC and SOCK_NONBLOCK - * support, we are running on one without. */ - if (errno != EINVAL) - return s; -#endif /* defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) */ - - s = socket(domain, type, protocol); - if (! SOCKET_OK(s)) - return s; - -#if defined(FD_CLOEXEC) - if (cloexec) { - if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); - tor_close_socket_simple(s); - return TOR_INVALID_SOCKET; - } - } -#else /* !(defined(FD_CLOEXEC)) */ - (void)cloexec; -#endif /* defined(FD_CLOEXEC) */ - - if (nonblock) { - if (set_socket_nonblocking(s) == -1) { - tor_close_socket_simple(s); - return TOR_INVALID_SOCKET; - } - } - - goto socket_ok; /* So that socket_ok will not be unused. */ - - socket_ok: - tor_take_socket_ownership(s); - return s; -} - -/** - * For socket accounting: remember that we are the owner of the socket - * <b>s</b>. This will prevent us from overallocating sockets, and prevent us - * from asserting later when we close the socket <b>s</b>. - */ -void -tor_take_socket_ownership(tor_socket_t s) -{ - socket_accounting_lock(); - ++n_sockets_open; - mark_socket_open(s); - socket_accounting_unlock(); -} - -/** As accept(), but counts the number of open sockets. */ -tor_socket_t -tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len) -{ - return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 0); -} - -/** As accept(), but returns a nonblocking socket and - * counts the number of open sockets. */ -tor_socket_t -tor_accept_socket_nonblocking(tor_socket_t sockfd, struct sockaddr *addr, - socklen_t *len) -{ - return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 1); -} - -/** As accept(), but counts the number of open sockets and handles - * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified. - * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate - * if the corresponding extension should be used.*/ -tor_socket_t -tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr, - socklen_t *len, int cloexec, int nonblock) -{ - tor_socket_t s; - - /* We are about to create a new file descriptor so make sure we have - * enough of them. */ - if (get_n_open_sockets() >= max_sockets - 1) { -#ifdef _WIN32 - WSASetLastError(WSAEMFILE); -#else - errno = EMFILE; -#endif - return TOR_INVALID_SOCKET; - } - -#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) \ - && defined(SOCK_NONBLOCK) - int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) | - (nonblock ? SOCK_NONBLOCK : 0); - s = accept4(sockfd, addr, len, ext_flags); - if (SOCKET_OK(s)) - goto socket_ok; - /* If we got an error, see if it is ENOSYS. ENOSYS indicates that, - * even though we were built on a system with accept4 support, we - * are running on one without. Also, check for EINVAL, which indicates that - * we are missing SOCK_CLOEXEC/SOCK_NONBLOCK support. */ - if (errno != EINVAL && errno != ENOSYS) - return s; -#endif /* defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) ... */ - - s = accept(sockfd, addr, len); - if (!SOCKET_OK(s)) - return s; - -#if defined(FD_CLOEXEC) - if (cloexec) { - if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno)); - tor_close_socket_simple(s); - return TOR_INVALID_SOCKET; - } - } -#else /* !(defined(FD_CLOEXEC)) */ - (void)cloexec; -#endif /* defined(FD_CLOEXEC) */ - - if (nonblock) { - if (set_socket_nonblocking(s) == -1) { - tor_close_socket_simple(s); - return TOR_INVALID_SOCKET; - } - } - - goto socket_ok; /* So that socket_ok will not be unused. */ - - socket_ok: - tor_take_socket_ownership(s); - return s; -} - -/** Return the number of sockets we currently have opened. */ -int -get_n_open_sockets(void) -{ - int n; - socket_accounting_lock(); - n = n_sockets_open; - socket_accounting_unlock(); - return n; -} - -/** Mockable wrapper for getsockname(). */ -MOCK_IMPL(int, -tor_getsockname,(tor_socket_t sock, struct sockaddr *address, - socklen_t *address_len)) -{ - return getsockname(sock, address, address_len); -} - -/** - * Find the local address associated with the socket <b>sock</b>, and - * place it in *<b>addr_out</b>. Return 0 on success, -1 on failure. - * - * (As tor_getsockname, but instead places the result in a tor_addr_t.) */ -int -tor_addr_from_getsockname(tor_addr_t *addr_out, tor_socket_t sock) -{ - struct sockaddr_storage ss; - socklen_t ss_len = sizeof(ss); - memset(&ss, 0, sizeof(ss)); - - if (tor_getsockname(sock, (struct sockaddr *) &ss, &ss_len) < 0) - return -1; - - return tor_addr_from_sockaddr(addr_out, (struct sockaddr *)&ss, NULL); -} - -/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1 - * on failure. - */ -int -set_socket_nonblocking(tor_socket_t sock) -{ -#if defined(_WIN32) - unsigned long nonblocking = 1; - ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking); -#else - int flags; - - flags = fcntl(sock, F_GETFL, 0); - if (flags == -1) { - log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno)); - return -1; - } - flags |= O_NONBLOCK; - if (fcntl(sock, F_SETFL, flags) == -1) { - log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno)); - return -1; - } -#endif /* defined(_WIN32) */ - - return 0; -} - -/** - * Allocate a pair of connected sockets. (Like socketpair(family, - * type,protocol,fd), but works on systems that don't have - * socketpair.) - * - * Currently, only (AF_UNIX, SOCK_STREAM, 0) sockets are supported. - * - * Note that on systems without socketpair, this call will fail if - * localhost is inaccessible (for example, if the networking - * stack is down). And even if it succeeds, the socket pair will not - * be able to read while localhost is down later (the socket pair may - * even close, depending on OS-specific timeouts). - * - * Returns 0 on success and -errno on failure; do not rely on the value - * of errno or WSAGetLastError(). - **/ -/* It would be nicer just to set errno, but that won't work for windows. */ -int -tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) -{ -//don't use win32 socketpairs (they are always bad) -#if defined(HAVE_SOCKETPAIR) && !defined(_WIN32) - int r; - -#ifdef SOCK_CLOEXEC - r = socketpair(family, type|SOCK_CLOEXEC, protocol, fd); - if (r == 0) - goto sockets_ok; - /* If we got an error, see if it is EINVAL. EINVAL might indicate that, - * even though we were built on a system with SOCK_CLOEXEC support, we - * are running on one without. */ - if (errno != EINVAL) - return -errno; -#endif /* defined(SOCK_CLOEXEC) */ - - r = socketpair(family, type, protocol, fd); - if (r < 0) - return -errno; - -#if defined(FD_CLOEXEC) - if (SOCKET_OK(fd[0])) { - r = fcntl(fd[0], F_SETFD, FD_CLOEXEC); - if (r == -1) { - close(fd[0]); - close(fd[1]); - return -errno; - } - } - if (SOCKET_OK(fd[1])) { - r = fcntl(fd[1], F_SETFD, FD_CLOEXEC); - if (r == -1) { - close(fd[0]); - close(fd[1]); - return -errno; - } - } -#endif /* defined(FD_CLOEXEC) */ - goto sockets_ok; /* So that sockets_ok will not be unused. */ - - sockets_ok: - socket_accounting_lock(); - if (SOCKET_OK(fd[0])) { - ++n_sockets_open; - mark_socket_open(fd[0]); - } - if (SOCKET_OK(fd[1])) { - ++n_sockets_open; - mark_socket_open(fd[1]); - } - socket_accounting_unlock(); - - return 0; -#else /* !(defined(HAVE_SOCKETPAIR) && !defined(_WIN32)) */ - return tor_ersatz_socketpair(family, type, protocol, fd); -#endif /* defined(HAVE_SOCKETPAIR) && !defined(_WIN32) */ -} - -#ifdef NEED_ERSATZ_SOCKETPAIR - -static inline socklen_t -SIZEOF_SOCKADDR(int domain) -{ - switch (domain) { - case AF_INET: - return sizeof(struct sockaddr_in); - case AF_INET6: - return sizeof(struct sockaddr_in6); - default: - return 0; - } -} - -/** - * Helper used to implement socketpair on systems that lack it, by - * making a direct connection to localhost. - */ -STATIC int -tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) -{ - /* This socketpair does not work when localhost is down. So - * it's really not the same thing at all. But it's close enough - * for now, and really, when localhost is down sometimes, we - * have other problems too. - */ - tor_socket_t listener = TOR_INVALID_SOCKET; - tor_socket_t connector = TOR_INVALID_SOCKET; - tor_socket_t acceptor = TOR_INVALID_SOCKET; - tor_addr_t listen_tor_addr; - struct sockaddr_storage connect_addr_ss, listen_addr_ss; - struct sockaddr *listen_addr = (struct sockaddr *) &listen_addr_ss; - uint16_t listen_port = 0; - tor_addr_t connect_tor_addr; - uint16_t connect_port = 0; - struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss; - socklen_t size; - int saved_errno = -1; - int ersatz_domain = AF_INET; - - memset(&connect_tor_addr, 0, sizeof(connect_tor_addr)); - memset(&connect_addr_ss, 0, sizeof(connect_addr_ss)); - memset(&listen_tor_addr, 0, sizeof(listen_tor_addr)); - memset(&listen_addr_ss, 0, sizeof(listen_addr_ss)); - - if (protocol -#ifdef AF_UNIX - || family != AF_UNIX -#endif - ) { -#ifdef _WIN32 - return -WSAEAFNOSUPPORT; -#else - return -EAFNOSUPPORT; -#endif - } - if (!fd) { - return -EINVAL; - } - - listener = tor_open_socket(ersatz_domain, type, 0); - if (!SOCKET_OK(listener)) { - int first_errno = tor_socket_errno(-1); - if (first_errno == SOCK_ERRNO(EPROTONOSUPPORT) - && ersatz_domain == AF_INET) { - /* Assume we're on an IPv6-only system */ - ersatz_domain = AF_INET6; - listener = tor_open_socket(ersatz_domain, type, 0); - if (!SOCKET_OK(listener)) { - /* Keep the previous behaviour, which was to return the IPv4 error. - * (This may be less informative on IPv6-only systems.) - * XX/teor - is there a better way to decide which errno to return? - * (I doubt we care much either way, once there is an error.) - */ - return -first_errno; - } - } - } - /* If there is no 127.0.0.1 or ::1, this will and must fail. Otherwise, we - * risk exposing a socketpair on a routable IP address. (Some BSD jails - * use a routable address for localhost. Fortunately, they have the real - * AF_UNIX socketpair.) */ - if (ersatz_domain == AF_INET) { - tor_addr_from_ipv4h(&listen_tor_addr, INADDR_LOOPBACK); - } else { - tor_addr_parse(&listen_tor_addr, "[::1]"); - } - tor_assert(tor_addr_is_loopback(&listen_tor_addr)); - size = tor_addr_to_sockaddr(&listen_tor_addr, - 0 /* kernel chooses port. */, - listen_addr, - sizeof(listen_addr_ss)); - if (bind(listener, listen_addr, size) == -1) - goto tidy_up_and_fail; - if (listen(listener, 1) == -1) - goto tidy_up_and_fail; - - connector = tor_open_socket(ersatz_domain, type, 0); - if (!SOCKET_OK(connector)) - goto tidy_up_and_fail; - /* We want to find out the port number to connect to. */ - size = sizeof(connect_addr_ss); - if (getsockname(listener, connect_addr, &size) == -1) - goto tidy_up_and_fail; - if (size != SIZEOF_SOCKADDR (connect_addr->sa_family)) - goto abort_tidy_up_and_fail; - if (connect(connector, connect_addr, size) == -1) - goto tidy_up_and_fail; - - size = sizeof(listen_addr_ss); - acceptor = tor_accept_socket(listener, listen_addr, &size); - if (!SOCKET_OK(acceptor)) - goto tidy_up_and_fail; - if (size != SIZEOF_SOCKADDR(listen_addr->sa_family)) - goto abort_tidy_up_and_fail; - /* Now check we are talking to ourself by matching port and host on the - two sockets. */ - if (getsockname(connector, connect_addr, &size) == -1) - goto tidy_up_and_fail; - /* Set *_tor_addr and *_port to the address and port that was used */ - tor_addr_from_sockaddr(&listen_tor_addr, listen_addr, &listen_port); - tor_addr_from_sockaddr(&connect_tor_addr, connect_addr, &connect_port); - if (size != SIZEOF_SOCKADDR (connect_addr->sa_family) - || tor_addr_compare(&listen_tor_addr, &connect_tor_addr, CMP_SEMANTIC) - || listen_port != connect_port) { - goto abort_tidy_up_and_fail; - } - tor_close_socket(listener); - fd[0] = connector; - fd[1] = acceptor; - - return 0; - - abort_tidy_up_and_fail: -#ifdef _WIN32 - saved_errno = WSAECONNABORTED; -#else - saved_errno = ECONNABORTED; /* I hope this is portable and appropriate. */ -#endif - tidy_up_and_fail: - if (saved_errno < 0) - saved_errno = errno; - if (SOCKET_OK(listener)) - tor_close_socket(listener); - if (SOCKET_OK(connector)) - tor_close_socket(connector); - if (SOCKET_OK(acceptor)) - tor_close_socket(acceptor); - return -saved_errno; -} - -#undef SIZEOF_SOCKADDR - -#endif /* defined(NEED_ERSATZ_SOCKETPAIR) */ - -/* Return the maximum number of allowed sockets. */ -int -get_max_sockets(void) -{ - return max_sockets; -} - -/** Number of extra file descriptors to keep in reserve beyond those that we - * tell Tor it's allowed to use. */ -#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */ - -/** Learn the maximum allowed number of file descriptors, and tell the - * system we want to use up to that number. (Some systems have a low soft - * limit, and let us set it higher.) We compute this by finding the largest - * number that we can use. - * - * If the limit is below the reserved file descriptor value (ULIMIT_BUFFER), - * return -1 and <b>max_out</b> is untouched. - * - * If we can't find a number greater than or equal to <b>limit</b>, then we - * fail by returning -1 and <b>max_out</b> is untouched. - * - * If we are unable to set the limit value because of setrlimit() failing, - * return 0 and <b>max_out</b> is set to the current maximum value returned - * by getrlimit(). - * - * Otherwise, return 0 and store the maximum we found inside <b>max_out</b> - * and set <b>max_sockets</b> with that value as well.*/ -int -set_max_file_descriptors(rlim_t limit, int *max_out) -{ - if (limit < ULIMIT_BUFFER) { - log_warn(LD_CONFIG, - "ConnLimit must be at least %d. Failing.", ULIMIT_BUFFER); - return -1; - } - - /* Define some maximum connections values for systems where we cannot - * automatically determine a limit. Re Cygwin, see - * http://archives.seul.org/or/talk/Aug-2006/msg00210.html - * For an iPhone, 9999 should work. For Windows and all other unknown - * systems we use 15000 as the default. */ -#ifndef HAVE_GETRLIMIT -#if defined(CYGWIN) || defined(__CYGWIN__) - const char *platform = "Cygwin"; - const unsigned long MAX_CONNECTIONS = 3200; -#elif defined(_WIN32) - const char *platform = "Windows"; - const unsigned long MAX_CONNECTIONS = 15000; -#else - const char *platform = "unknown platforms with no getrlimit()"; - const unsigned long MAX_CONNECTIONS = 15000; -#endif /* defined(CYGWIN) || defined(__CYGWIN__) || ... */ - log_fn(LOG_INFO, LD_NET, - "This platform is missing getrlimit(). Proceeding."); - if (limit > MAX_CONNECTIONS) { - log_warn(LD_CONFIG, - "We do not support more than %lu file descriptors " - "on %s. Tried to raise to %lu.", - (unsigned long)MAX_CONNECTIONS, platform, (unsigned long)limit); - return -1; - } - limit = MAX_CONNECTIONS; -#else /* !(!defined(HAVE_GETRLIMIT)) */ - struct rlimit rlim; - - if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { - log_warn(LD_NET, "Could not get maximum number of file descriptors: %s", - strerror(errno)); - return -1; - } - if (rlim.rlim_max < limit) { - log_warn(LD_CONFIG,"We need %lu file descriptors available, and we're " - "limited to %lu. Please change your ulimit -n.", - (unsigned long)limit, (unsigned long)rlim.rlim_max); - return -1; - } - - if (rlim.rlim_max > rlim.rlim_cur) { - log_info(LD_NET,"Raising max file descriptors from %lu to %lu.", - (unsigned long)rlim.rlim_cur, (unsigned long)rlim.rlim_max); - } - /* Set the current limit value so if the attempt to set the limit to the - * max fails at least we'll have a valid value of maximum sockets. */ - *max_out = max_sockets = (int)rlim.rlim_cur - ULIMIT_BUFFER; - rlim.rlim_cur = rlim.rlim_max; - - if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { - int couldnt_set = 1; - const int setrlimit_errno = errno; -#ifdef OPEN_MAX - uint64_t try_limit = OPEN_MAX - ULIMIT_BUFFER; - if (errno == EINVAL && try_limit < (uint64_t) rlim.rlim_cur) { - /* On some platforms, OPEN_MAX is the real limit, and getrlimit() is - * full of nasty lies. I'm looking at you, OSX 10.5.... */ - rlim.rlim_cur = MIN((rlim_t) try_limit, rlim.rlim_cur); - if (setrlimit(RLIMIT_NOFILE, &rlim) == 0) { - if (rlim.rlim_cur < (rlim_t)limit) { - log_warn(LD_CONFIG, "We are limited to %lu file descriptors by " - "OPEN_MAX (%lu), and ConnLimit is %lu. Changing " - "ConnLimit; sorry.", - (unsigned long)try_limit, (unsigned long)OPEN_MAX, - (unsigned long)limit); - } else { - log_info(LD_CONFIG, "Dropped connection limit to %lu based on " - "OPEN_MAX (%lu); Apparently, %lu was too high and rlimit " - "lied to us.", - (unsigned long)try_limit, (unsigned long)OPEN_MAX, - (unsigned long)rlim.rlim_max); - } - couldnt_set = 0; - } - } -#endif /* defined(OPEN_MAX) */ - if (couldnt_set) { - log_warn(LD_CONFIG,"Couldn't set maximum number of file descriptors: %s", - strerror(setrlimit_errno)); - } - } - /* leave some overhead for logs, etc, */ - limit = rlim.rlim_cur; -#endif /* !defined(HAVE_GETRLIMIT) */ - - if (limit > INT_MAX) - limit = INT_MAX; - tor_assert(max_out); - *max_out = max_sockets = (int)limit - ULIMIT_BUFFER; - return 0; -} - -#ifndef _WIN32 -/** Log details of current user and group credentials. Return 0 on - * success. Logs and return -1 on failure. - */ -static int -log_credential_status(void) -{ -/** Log level to use when describing non-error UID/GID status. */ -#define CREDENTIAL_LOG_LEVEL LOG_INFO - /* Real, effective and saved UIDs */ - uid_t ruid, euid, suid; - /* Read, effective and saved GIDs */ - gid_t rgid, egid, sgid; - /* Supplementary groups */ - gid_t *sup_gids = NULL; - int sup_gids_size; - /* Number of supplementary groups */ - int ngids; - - /* log UIDs */ -#ifdef HAVE_GETRESUID - if (getresuid(&ruid, &euid, &suid) != 0 ) { - log_warn(LD_GENERAL, "Error getting changed UIDs: %s", strerror(errno)); - return -1; - } else { - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, - "UID is %u (real), %u (effective), %u (saved)", - (unsigned)ruid, (unsigned)euid, (unsigned)suid); - } -#else /* !(defined(HAVE_GETRESUID)) */ - /* getresuid is not present on MacOS X, so we can't get the saved (E)UID */ - ruid = getuid(); - euid = geteuid(); - (void)suid; - - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, - "UID is %u (real), %u (effective), unknown (saved)", - (unsigned)ruid, (unsigned)euid); -#endif /* defined(HAVE_GETRESUID) */ - - /* log GIDs */ -#ifdef HAVE_GETRESGID - if (getresgid(&rgid, &egid, &sgid) != 0 ) { - log_warn(LD_GENERAL, "Error getting changed GIDs: %s", strerror(errno)); - return -1; - } else { - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, - "GID is %u (real), %u (effective), %u (saved)", - (unsigned)rgid, (unsigned)egid, (unsigned)sgid); - } -#else /* !(defined(HAVE_GETRESGID)) */ - /* getresgid is not present on MacOS X, so we can't get the saved (E)GID */ - rgid = getgid(); - egid = getegid(); - (void)sgid; - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, - "GID is %u (real), %u (effective), unknown (saved)", - (unsigned)rgid, (unsigned)egid); -#endif /* defined(HAVE_GETRESGID) */ - - /* log supplementary groups */ - sup_gids_size = 64; - sup_gids = tor_calloc(64, sizeof(gid_t)); - while ((ngids = getgroups(sup_gids_size, sup_gids)) < 0 && - errno == EINVAL && - sup_gids_size < NGROUPS_MAX) { - sup_gids_size *= 2; - sup_gids = tor_reallocarray(sup_gids, sizeof(gid_t), sup_gids_size); - } - - if (ngids < 0) { - log_warn(LD_GENERAL, "Error getting supplementary GIDs: %s", - strerror(errno)); - tor_free(sup_gids); - return -1; - } else { - int i, retval = 0; - char *s = NULL; - smartlist_t *elts = smartlist_new(); - - for (i = 0; i<ngids; i++) { - smartlist_add_asprintf(elts, "%u", (unsigned)sup_gids[i]); - } - - s = smartlist_join_strings(elts, " ", 0, NULL); - - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Supplementary groups are: %s",s); - - tor_free(s); - SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); - smartlist_free(elts); - tor_free(sup_gids); - - return retval; - } - - return 0; -} -#endif /* !defined(_WIN32) */ - -#ifndef _WIN32 -/** Cached struct from the last getpwname() call we did successfully. */ -static struct passwd *passwd_cached = NULL; - -/** Helper: copy a struct passwd object. - * - * We only copy the fields pw_uid, pw_gid, pw_name, pw_dir. Tor doesn't use - * any others, and I don't want to run into incompatibilities. - */ -static struct passwd * -tor_passwd_dup(const struct passwd *pw) -{ - struct passwd *new_pw = tor_malloc_zero(sizeof(struct passwd)); - if (pw->pw_name) - new_pw->pw_name = tor_strdup(pw->pw_name); - if (pw->pw_dir) - new_pw->pw_dir = tor_strdup(pw->pw_dir); - new_pw->pw_uid = pw->pw_uid; - new_pw->pw_gid = pw->pw_gid; - - return new_pw; -} - -#define tor_passwd_free(pw) \ - FREE_AND_NULL(struct passwd, tor_passwd_free_, (pw)) - -/** Helper: free one of our cached 'struct passwd' values. */ -static void -tor_passwd_free_(struct passwd *pw) -{ - if (!pw) - return; - - tor_free(pw->pw_name); - tor_free(pw->pw_dir); - tor_free(pw); -} - -/** Wrapper around getpwnam() that caches result. Used so that we don't need - * to give the sandbox access to /etc/passwd. - * - * The following fields alone will definitely be copied in the output: pw_uid, - * pw_gid, pw_name, pw_dir. Other fields are not present in cached values. - * - * When called with a NULL argument, this function clears storage associated - * with static variables it uses. - **/ -const struct passwd * -tor_getpwnam(const char *username) -{ - struct passwd *pw; - - if (username == NULL) { - tor_passwd_free(passwd_cached); - passwd_cached = NULL; - return NULL; - } - - if ((pw = getpwnam(username))) { - tor_passwd_free(passwd_cached); - passwd_cached = tor_passwd_dup(pw); - log_info(LD_GENERAL, "Caching new entry %s for %s", - passwd_cached->pw_name, username); - return pw; - } - - /* Lookup failed */ - if (! passwd_cached || ! passwd_cached->pw_name) - return NULL; - - if (! strcmp(username, passwd_cached->pw_name)) - return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky - - return NULL; -} - -/** Wrapper around getpwnam() that can use cached result from - * tor_getpwnam(). Used so that we don't need to give the sandbox access to - * /etc/passwd. - * - * The following fields alone will definitely be copied in the output: pw_uid, - * pw_gid, pw_name, pw_dir. Other fields are not present in cached values. - */ -const struct passwd * -tor_getpwuid(uid_t uid) -{ - struct passwd *pw; - - if ((pw = getpwuid(uid))) { - return pw; - } - - /* Lookup failed */ - if (! passwd_cached) - return NULL; - - if (uid == passwd_cached->pw_uid) - return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky - - return NULL; -} -#endif /* !defined(_WIN32) */ - -/** Return true iff we were compiled with capability support, and capabilities - * seem to work. **/ -int -have_capability_support(void) -{ -#ifdef HAVE_LINUX_CAPABILITIES - cap_t caps = cap_get_proc(); - if (caps == NULL) - return 0; - cap_free(caps); - return 1; -#else /* !(defined(HAVE_LINUX_CAPABILITIES)) */ - return 0; -#endif /* defined(HAVE_LINUX_CAPABILITIES) */ -} - -#ifdef HAVE_LINUX_CAPABILITIES -/** Helper. Drop all capabilities but a small set, and set PR_KEEPCAPS as - * appropriate. - * - * If pre_setuid, retain only CAP_NET_BIND_SERVICE, CAP_SETUID, and - * CAP_SETGID, and use PR_KEEPCAPS to ensure that capabilities persist across - * setuid(). - * - * If not pre_setuid, retain only CAP_NET_BIND_SERVICE, and disable - * PR_KEEPCAPS. - * - * Return 0 on success, and -1 on failure. - */ -static int -drop_capabilities(int pre_setuid) -{ - /* We keep these three capabilities, and these only, as we setuid. - * After we setuid, we drop all but the first. */ - const cap_value_t caplist[] = { - CAP_NET_BIND_SERVICE, CAP_SETUID, CAP_SETGID - }; - const char *where = pre_setuid ? "pre-setuid" : "post-setuid"; - const int n_effective = pre_setuid ? 3 : 1; - const int n_permitted = pre_setuid ? 3 : 1; - const int n_inheritable = 1; - const int keepcaps = pre_setuid ? 1 : 0; - - /* Sets whether we keep capabilities across a setuid. */ - if (prctl(PR_SET_KEEPCAPS, keepcaps) < 0) { - log_warn(LD_CONFIG, "Unable to call prctl() %s: %s", - where, strerror(errno)); - return -1; - } - - cap_t caps = cap_get_proc(); - if (!caps) { - log_warn(LD_CONFIG, "Unable to call cap_get_proc() %s: %s", - where, strerror(errno)); - return -1; - } - cap_clear(caps); - - cap_set_flag(caps, CAP_EFFECTIVE, n_effective, caplist, CAP_SET); - cap_set_flag(caps, CAP_PERMITTED, n_permitted, caplist, CAP_SET); - cap_set_flag(caps, CAP_INHERITABLE, n_inheritable, caplist, CAP_SET); - - int r = cap_set_proc(caps); - cap_free(caps); - if (r < 0) { - log_warn(LD_CONFIG, "No permission to set capabilities %s: %s", - where, strerror(errno)); - return -1; - } - - return 0; -} -#endif /* defined(HAVE_LINUX_CAPABILITIES) */ - -/** Call setuid and setgid to run as <b>user</b> and switch to their - * primary group. Return 0 on success. On failure, log and return -1. - * - * If SWITCH_ID_KEEP_BINDLOW is set in 'flags', try to use the capability - * system to retain the abilitity to bind low ports. - * - * If SWITCH_ID_WARN_IF_NO_CAPS is set in flags, also warn if we have - * don't have capability support. - */ -int -switch_id(const char *user, const unsigned flags) -{ -#ifndef _WIN32 - const struct passwd *pw = NULL; - uid_t old_uid; - gid_t old_gid; - static int have_already_switched_id = 0; - const int keep_bindlow = !!(flags & SWITCH_ID_KEEP_BINDLOW); - const int warn_if_no_caps = !!(flags & SWITCH_ID_WARN_IF_NO_CAPS); - - tor_assert(user); - - if (have_already_switched_id) - return 0; - - /* Log the initial credential state */ - if (log_credential_status()) - return -1; - - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Changing user and groups"); - - /* Get old UID/GID to check if we changed correctly */ - old_uid = getuid(); - old_gid = getgid(); - - /* Lookup the user and group information, if we have a problem, bail out. */ - pw = tor_getpwnam(user); - if (pw == NULL) { - log_warn(LD_CONFIG, "Error setting configured user: %s not found", user); - return -1; - } - -#ifdef HAVE_LINUX_CAPABILITIES - (void) warn_if_no_caps; - if (keep_bindlow) { - if (drop_capabilities(1)) - return -1; - } -#else /* !(defined(HAVE_LINUX_CAPABILITIES)) */ - (void) keep_bindlow; - if (warn_if_no_caps) { - log_warn(LD_CONFIG, "KeepBindCapabilities set, but no capability support " - "on this system."); - } -#endif /* defined(HAVE_LINUX_CAPABILITIES) */ - - /* Properly switch egid,gid,euid,uid here or bail out */ - if (setgroups(1, &pw->pw_gid)) { - log_warn(LD_GENERAL, "Error setting groups to gid %d: \"%s\".", - (int)pw->pw_gid, strerror(errno)); - if (old_uid == pw->pw_uid) { - log_warn(LD_GENERAL, "Tor is already running as %s. You do not need " - "the \"User\" option if you are already running as the user " - "you want to be. (If you did not set the User option in your " - "torrc, check whether it was specified on the command line " - "by a startup script.)", user); - } else { - log_warn(LD_GENERAL, "If you set the \"User\" option, you must start Tor" - " as root."); - } - return -1; - } - - if (setegid(pw->pw_gid)) { - log_warn(LD_GENERAL, "Error setting egid to %d: %s", - (int)pw->pw_gid, strerror(errno)); - return -1; - } - - if (setgid(pw->pw_gid)) { - log_warn(LD_GENERAL, "Error setting gid to %d: %s", - (int)pw->pw_gid, strerror(errno)); - return -1; - } - - if (setuid(pw->pw_uid)) { - log_warn(LD_GENERAL, "Error setting configured uid to %s (%d): %s", - user, (int)pw->pw_uid, strerror(errno)); - return -1; - } - - if (seteuid(pw->pw_uid)) { - log_warn(LD_GENERAL, "Error setting configured euid to %s (%d): %s", - user, (int)pw->pw_uid, strerror(errno)); - return -1; - } - - /* This is how OpenBSD rolls: - if (setgroups(1, &pw->pw_gid) || setegid(pw->pw_gid) || - setgid(pw->pw_gid) || setuid(pw->pw_uid) || seteuid(pw->pw_uid)) { - setgid(pw->pw_gid) || seteuid(pw->pw_uid) || setuid(pw->pw_uid)) { - log_warn(LD_GENERAL, "Error setting configured UID/GID: %s", - strerror(errno)); - return -1; - } - */ - - /* We've properly switched egid, gid, euid, uid, and supplementary groups if - * we're here. */ -#ifdef HAVE_LINUX_CAPABILITIES - if (keep_bindlow) { - if (drop_capabilities(0)) - return -1; - } -#endif /* defined(HAVE_LINUX_CAPABILITIES) */ - -#if !defined(CYGWIN) && !defined(__CYGWIN__) - /* If we tried to drop privilege to a group/user other than root, attempt to - * restore root (E)(U|G)ID, and abort if the operation succeeds */ - - /* Only check for privilege dropping if we were asked to be non-root */ - if (pw->pw_uid) { - /* Try changing GID/EGID */ - if (pw->pw_gid != old_gid && - (setgid(old_gid) != -1 || setegid(old_gid) != -1)) { - log_warn(LD_GENERAL, "Was able to restore group credentials even after " - "switching GID: this means that the setgid code didn't work."); - return -1; - } - - /* Try changing UID/EUID */ - if (pw->pw_uid != old_uid && - (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) { - log_warn(LD_GENERAL, "Was able to restore user credentials even after " - "switching UID: this means that the setuid code didn't work."); - return -1; - } - } -#endif /* !defined(CYGWIN) && !defined(__CYGWIN__) */ - - /* Check what really happened */ - if (log_credential_status()) { - return -1; - } - - have_already_switched_id = 1; /* mark success so we never try again */ - -#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && \ - defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) - if (pw->pw_uid) { - /* Re-enable core dumps if we're not running as root. */ - log_info(LD_CONFIG, "Re-enabling coredumps"); - if (prctl(PR_SET_DUMPABLE, 1)) { - log_warn(LD_CONFIG, "Unable to re-enable coredumps: %s",strerror(errno)); - } - } -#endif /* defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && ... */ - return 0; - -#else /* !(!defined(_WIN32)) */ - (void)user; - (void)flags; - - log_warn(LD_CONFIG, "Switching users is unsupported on your OS."); - return -1; -#endif /* !defined(_WIN32) */ -} - -/* We only use the linux prctl for now. There is no Win32 support; this may - * also work on various BSD systems and Mac OS X - send testing feedback! - * - * On recent Gnu/Linux kernels it is possible to create a system-wide policy - * that will prevent non-root processes from attaching to other processes - * unless they are the parent process; thus gdb can attach to programs that - * they execute but they cannot attach to other processes running as the same - * user. The system wide policy may be set with the sysctl - * kernel.yama.ptrace_scope or by inspecting - * /proc/sys/kernel/yama/ptrace_scope and it is 1 by default on Ubuntu 11.04. - * - * This ptrace scope will be ignored on Gnu/Linux for users with - * CAP_SYS_PTRACE and so it is very likely that root will still be able to - * attach to the Tor process. - */ -/** Attempt to disable debugger attachment: return 1 on success, -1 on - * failure, and 0 if we don't know how to try on this platform. */ -int -tor_disable_debugger_attach(void) -{ - int r = -1; - log_debug(LD_CONFIG, - "Attemping to disable debugger attachment to Tor for " - "unprivileged users."); -#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) \ - && defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) -#define TRIED_TO_DISABLE - r = prctl(PR_SET_DUMPABLE, 0); -#elif defined(__APPLE__) && defined(PT_DENY_ATTACH) -#define TRIED_TO_ATTACH - r = ptrace(PT_DENY_ATTACH, 0, 0, 0); -#endif /* defined(__linux__) && defined(HAVE_SYS_PRCTL_H) ... || ... */ - - // XXX: TODO - Mac OS X has dtrace and this may be disabled. - // XXX: TODO - Windows probably has something similar -#ifdef TRIED_TO_DISABLE - if (r == 0) { - log_debug(LD_CONFIG,"Debugger attachment disabled for " - "unprivileged users."); - return 1; - } else { - log_warn(LD_CONFIG, "Unable to disable debugger attaching: %s", - strerror(errno)); - } -#endif /* defined(TRIED_TO_DISABLE) */ -#undef TRIED_TO_DISABLE - return r; -} - -#ifdef HAVE_PWD_H -/** Allocate and return a string containing the home directory for the - * user <b>username</b>. Only works on posix-like systems. */ -char * -get_user_homedir(const char *username) -{ - const struct passwd *pw; - tor_assert(username); - - if (!(pw = tor_getpwnam(username))) { - log_err(LD_CONFIG,"User \"%s\" not found.", username); - return NULL; - } - return tor_strdup(pw->pw_dir); -} -#endif /* defined(HAVE_PWD_H) */ - -/** Modify <b>fname</b> to contain the name of its parent directory. Doesn't - * actually examine the filesystem; does a purely syntactic modification. - * - * The parent of the root director is considered to be iteself. - * - * Path separators are the forward slash (/) everywhere and additionally - * the backslash (\) on Win32. - * - * Cuts off any number of trailing path separators but otherwise ignores - * them for purposes of finding the parent directory. - * - * Returns 0 if a parent directory was successfully found, -1 otherwise (fname - * did not have any path separators or only had them at the end). - * */ -int -get_parent_directory(char *fname) -{ - char *cp; - int at_end = 1; - tor_assert(fname); -#ifdef _WIN32 - /* If we start with, say, c:, then don't consider that the start of the path - */ - if (fname[0] && fname[1] == ':') { - fname += 2; - } -#endif /* defined(_WIN32) */ - /* Now we want to remove all path-separators at the end of the string, - * and to remove the end of the string starting with the path separator - * before the last non-path-separator. In perl, this would be - * s#[/]*$##; s#/[^/]*$##; - * on a unixy platform. - */ - cp = fname + strlen(fname); - at_end = 1; - while (--cp >= fname) { - int is_sep = (*cp == '/' -#ifdef _WIN32 - || *cp == '\\' -#endif - ); - if (is_sep) { - if (cp == fname) { - /* This is the first separator in the file name; don't remove it! */ - cp[1] = '\0'; - return 0; - } - *cp = '\0'; - if (! at_end) - return 0; - } else { - at_end = 0; - } - } - return -1; -} - -#ifndef _WIN32 -/** Return a newly allocated string containing the output of getcwd(). Return - * NULL on failure. (We can't just use getcwd() into a PATH_MAX buffer, since - * Hurd hasn't got a PATH_MAX.) - */ -static char * -alloc_getcwd(void) -{ -#ifdef HAVE_GET_CURRENT_DIR_NAME - /* Glibc makes this nice and simple for us. */ - char *cwd = get_current_dir_name(); - char *result = NULL; - if (cwd) { - /* We make a copy here, in case tor_malloc() is not malloc(). */ - result = tor_strdup(cwd); - raw_free(cwd); // alias for free to avoid tripping check-spaces. - } - return result; -#else /* !(defined(HAVE_GET_CURRENT_DIR_NAME)) */ - size_t size = 1024; - char *buf = NULL; - char *ptr = NULL; - - while (ptr == NULL) { - buf = tor_realloc(buf, size); - ptr = getcwd(buf, size); - - if (ptr == NULL && errno != ERANGE) { - tor_free(buf); - return NULL; - } - - size *= 2; - } - return buf; -#endif /* defined(HAVE_GET_CURRENT_DIR_NAME) */ -} -#endif /* !defined(_WIN32) */ - -/** Expand possibly relative path <b>fname</b> to an absolute path. - * Return a newly allocated string, possibly equal to <b>fname</b>. */ -char * -make_path_absolute(char *fname) -{ -#ifdef _WIN32 - char *absfname_malloced = _fullpath(NULL, fname, 1); - - /* We don't want to assume that tor_free can free a string allocated - * with malloc. On failure, return fname (it's better than nothing). */ - char *absfname = tor_strdup(absfname_malloced ? absfname_malloced : fname); - if (absfname_malloced) raw_free(absfname_malloced); - - return absfname; -#else /* !(defined(_WIN32)) */ - char *absfname = NULL, *path = NULL; - - tor_assert(fname); - - if (fname[0] == '/') { - absfname = tor_strdup(fname); - } else { - path = alloc_getcwd(); - if (path) { - tor_asprintf(&absfname, "%s/%s", path, fname); - tor_free(path); - } else { - /* LCOV_EXCL_START Can't make getcwd fail. */ - /* If getcwd failed, the best we can do here is keep using the - * relative path. (Perhaps / isn't readable by this UID/GID.) */ - log_warn(LD_GENERAL, "Unable to find current working directory: %s", - strerror(errno)); - absfname = tor_strdup(fname); - /* LCOV_EXCL_STOP */ - } - } - return absfname; -#endif /* defined(_WIN32) */ -} - -#ifndef HAVE__NSGETENVIRON -#ifndef HAVE_EXTERN_ENVIRON_DECLARED -/* Some platforms declare environ under some circumstances, others don't. */ -#ifndef RUNNING_DOXYGEN -extern char **environ; -#endif -#endif /* !defined(HAVE_EXTERN_ENVIRON_DECLARED) */ -#endif /* !defined(HAVE__NSGETENVIRON) */ - -/** Return the current environment. This is a portable replacement for - * 'environ'. */ -char ** -get_environment(void) -{ -#ifdef HAVE__NSGETENVIRON - /* This is for compatibility between OSX versions. Otherwise (for example) - * when we do a mostly-static build on OSX 10.7, the resulting binary won't - * work on OSX 10.6. */ - return *_NSGetEnviron(); -#else /* !(defined(HAVE__NSGETENVIRON)) */ - return environ; -#endif /* defined(HAVE__NSGETENVIRON) */ -} - -/** Get name of current host and write it to <b>name</b> array, whose - * length is specified by <b>namelen</b> argument. Return 0 upon - * successful completion; otherwise return return -1. (Currently, - * this function is merely a mockable wrapper for POSIX gethostname().) - */ -MOCK_IMPL(int, -tor_gethostname,(char *name, size_t namelen)) -{ - return gethostname(name,namelen); -} - -/** Set *addr to the IP address (in dotted-quad notation) stored in *str. - * Return 1 on success, 0 if *str is badly formatted. - * (Like inet_aton(str,addr), but works on Windows and Solaris.) - */ -int -tor_inet_aton(const char *str, struct in_addr* addr) -{ - unsigned a,b,c,d; - char more; - if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a,&b,&c,&d,&more) != 4) - return 0; - if (a > 255) return 0; - if (b > 255) return 0; - if (c > 255) return 0; - if (d > 255) return 0; - addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d); - return 1; -} - -/** Given <b>af</b>==AF_INET and <b>src</b> a struct in_addr, or - * <b>af</b>==AF_INET6 and <b>src</b> a struct in6_addr, try to format the - * address and store it in the <b>len</b>-byte buffer <b>dst</b>. Returns - * <b>dst</b> on success, NULL on failure. - * - * (Like inet_ntop(af,src,dst,len), but works on platforms that don't have it: - * Tor sometimes needs to format ipv6 addresses even on platforms without ipv6 - * support.) */ -const char * -tor_inet_ntop(int af, const void *src, char *dst, size_t len) -{ - if (af == AF_INET) { - if (tor_inet_ntoa(src, dst, len) < 0) - return NULL; - else - return dst; - } else if (af == AF_INET6) { - const struct in6_addr *addr = src; - char buf[64], *cp; - int longestGapLen = 0, longestGapPos = -1, i, - curGapPos = -1, curGapLen = 0; - uint16_t words[8]; - for (i = 0; i < 8; ++i) { - words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1]; - } - if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && - words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) || - (words[5] == 0xffff))) { - /* This is an IPv4 address. */ - if (words[5] == 0) { - tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d", - addr->s6_addr[12], addr->s6_addr[13], - addr->s6_addr[14], addr->s6_addr[15]); - } else { - tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5], - addr->s6_addr[12], addr->s6_addr[13], - addr->s6_addr[14], addr->s6_addr[15]); - } - if ((strlen(buf) + 1) > len) /* +1 for \0 */ - return NULL; - strlcpy(dst, buf, len); - return dst; - } - i = 0; - while (i < 8) { - if (words[i] == 0) { - curGapPos = i++; - curGapLen = 1; - while (i<8 && words[i] == 0) { - ++i; ++curGapLen; - } - if (curGapLen > longestGapLen) { - longestGapPos = curGapPos; - longestGapLen = curGapLen; - } - } else { - ++i; - } - } - if (longestGapLen<=1) - longestGapPos = -1; - - cp = buf; - for (i = 0; i < 8; ++i) { - if (words[i] == 0 && longestGapPos == i) { - if (i == 0) - *cp++ = ':'; - *cp++ = ':'; - while (i < 8 && words[i] == 0) - ++i; - --i; /* to compensate for loop increment. */ - } else { - tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]); - cp += strlen(cp); - if (i != 7) - *cp++ = ':'; - } - } - *cp = '\0'; - if ((strlen(buf) + 1) > len) /* +1 for \0 */ - return NULL; - strlcpy(dst, buf, len); - return dst; - } else { - return NULL; - } -} - -/** Given <b>af</b>==AF_INET or <b>af</b>==AF_INET6, and a string <b>src</b> - * encoding an IPv4 address or IPv6 address correspondingly, try to parse the - * address and store the result in <b>dst</b> (which must have space for a - * struct in_addr or a struct in6_addr, as appropriate). Return 1 on success, - * 0 on a bad parse, and -1 on a bad <b>af</b>. - * - * (Like inet_pton(af,src,dst) but works on platforms that don't have it: Tor - * sometimes needs to format ipv6 addresses even on platforms without ipv6 - * support.) */ -int -tor_inet_pton(int af, const char *src, void *dst) -{ - if (af == AF_INET) { - return tor_inet_aton(src, dst); - } else if (af == AF_INET6) { - struct in6_addr *out = dst; - uint16_t words[8]; - int gapPos = -1, i, setWords=0; - const char *dot = strchr(src, '.'); - const char *eow; /* end of words. */ - memset(words, 0xf8, sizeof(words)); - if (dot == src) - return 0; - else if (!dot) - eow = src+strlen(src); - else { - unsigned byte1,byte2,byte3,byte4; - char more; - for (eow = dot-1; eow > src && TOR_ISDIGIT(*eow); --eow) - ; - if (*eow != ':') - return 0; - ++eow; - - /* We use "scanf" because some platform inet_aton()s are too lax - * about IPv4 addresses of the form "1.2.3" */ - if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c", - &byte1,&byte2,&byte3,&byte4,&more) != 4) - return 0; - - if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255) - return 0; - - words[6] = (byte1<<8) | byte2; - words[7] = (byte3<<8) | byte4; - setWords += 2; - } - - i = 0; - while (src < eow) { - if (i > 7) - return 0; - if (TOR_ISXDIGIT(*src)) { - char *next; - ssize_t len; - long r = strtol(src, &next, 16); - if (next == NULL || next == src) { - /* The 'next == src' error case can happen on versions of openbsd - * which treat "0xfoo" as an error, rather than as "0" followed by - * "xfoo". */ - return 0; - } - - len = *next == '\0' ? eow - src : next - src; - if (len > 4) - return 0; - if (len > 1 && !TOR_ISXDIGIT(src[1])) - return 0; /* 0x is not valid */ - - tor_assert(r >= 0); - tor_assert(r < 65536); - words[i++] = (uint16_t)r; - setWords++; - src = next; - if (*src != ':' && src != eow) - return 0; - ++src; - } else if (*src == ':' && i > 0 && gapPos == -1) { - gapPos = i; - ++src; - } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' && - gapPos == -1) { - gapPos = i; - src += 2; - } else { - return 0; - } - } - - if (setWords > 8 || - (setWords == 8 && gapPos != -1) || - (setWords < 8 && gapPos == -1)) - return 0; - - if (gapPos >= 0) { - int nToMove = setWords - (dot ? 2 : 0) - gapPos; - int gapLen = 8 - setWords; - tor_assert(nToMove >= 0); - memmove(&words[gapPos+gapLen], &words[gapPos], - sizeof(uint16_t)*nToMove); - memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen); - } - for (i = 0; i < 8; ++i) { - out->s6_addr[2*i ] = words[i] >> 8; - out->s6_addr[2*i+1] = words[i] & 0xff; - } - - return 1; - } else { - return -1; - } -} - -/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set - * *<b>addr</b> to the proper IP address, in host byte order. Returns 0 - * on success, -1 on failure; 1 on transient failure. - * - * (This function exists because standard windows gethostbyname - * doesn't treat raw IP addresses properly.) - */ - -MOCK_IMPL(int, -tor_lookup_hostname,(const char *name, uint32_t *addr)) -{ - tor_addr_t myaddr; - int ret; - - if ((ret = tor_addr_lookup(name, AF_INET, &myaddr))) - return ret; - - if (tor_addr_family(&myaddr) == AF_INET) { - *addr = tor_addr_to_ipv4h(&myaddr); - return ret; - } - - return -1; -} - -/** Hold the result of our call to <b>uname</b>. */ -static char uname_result[256]; -/** True iff uname_result is set. */ -static int uname_result_is_set = 0; - -/** Return a pointer to a description of our platform. - */ -MOCK_IMPL(const char *, -get_uname,(void)) -{ -#ifdef HAVE_UNAME - struct utsname u; -#endif - if (!uname_result_is_set) { -#ifdef HAVE_UNAME - if (uname(&u) != -1) { - /* (Linux says 0 is success, Solaris says 1 is success) */ - strlcpy(uname_result, u.sysname, sizeof(uname_result)); - } else -#endif /* defined(HAVE_UNAME) */ - { -#ifdef _WIN32 - OSVERSIONINFOEX info; - int i; - const char *plat = NULL; - static struct { - unsigned major; unsigned minor; const char *version; - } win_version_table[] = { - { 6, 2, "Windows 8" }, - { 6, 1, "Windows 7" }, - { 6, 0, "Windows Vista" }, - { 5, 2, "Windows Server 2003" }, - { 5, 1, "Windows XP" }, - { 5, 0, "Windows 2000" }, - /* { 4, 0, "Windows NT 4.0" }, */ - { 4, 90, "Windows Me" }, - { 4, 10, "Windows 98" }, - /* { 4, 0, "Windows 95" } */ - { 3, 51, "Windows NT 3.51" }, - { 0, 0, NULL } - }; - memset(&info, 0, sizeof(info)); - info.dwOSVersionInfoSize = sizeof(info); - if (! GetVersionEx((LPOSVERSIONINFO)&info)) { - strlcpy(uname_result, "Bizarre version of Windows where GetVersionEx" - " doesn't work.", sizeof(uname_result)); - uname_result_is_set = 1; - return uname_result; - } - if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) { - if (info.dwPlatformId == VER_PLATFORM_WIN32_NT) - plat = "Windows NT 4.0"; - else - plat = "Windows 95"; - } else { - for (i=0; win_version_table[i].major>0; ++i) { - if (win_version_table[i].major == info.dwMajorVersion && - win_version_table[i].minor == info.dwMinorVersion) { - plat = win_version_table[i].version; - break; - } - } - } - if (plat) { - strlcpy(uname_result, plat, sizeof(uname_result)); - } else { - if (info.dwMajorVersion > 6 || - (info.dwMajorVersion==6 && info.dwMinorVersion>2)) - tor_snprintf(uname_result, sizeof(uname_result), - "Very recent version of Windows [major=%d,minor=%d]", - (int)info.dwMajorVersion,(int)info.dwMinorVersion); - else - tor_snprintf(uname_result, sizeof(uname_result), - "Unrecognized version of Windows [major=%d,minor=%d]", - (int)info.dwMajorVersion,(int)info.dwMinorVersion); - } -#ifdef VER_NT_SERVER - if (info.wProductType == VER_NT_SERVER || - info.wProductType == VER_NT_DOMAIN_CONTROLLER) { - strlcat(uname_result, " [server]", sizeof(uname_result)); - } -#endif /* defined(VER_NT_SERVER) */ -#else /* !(defined(_WIN32)) */ - /* LCOV_EXCL_START -- can't provoke uname failure */ - strlcpy(uname_result, "Unknown platform", sizeof(uname_result)); - /* LCOV_EXCL_STOP */ -#endif /* defined(_WIN32) */ - } - uname_result_is_set = 1; - } - return uname_result; -} - -/* - * Process control - */ - -/** Implementation logic for compute_num_cpus(). */ -static int -compute_num_cpus_impl(void) -{ -#ifdef _WIN32 - SYSTEM_INFO info; - memset(&info, 0, sizeof(info)); - GetSystemInfo(&info); - if (info.dwNumberOfProcessors >= 1 && info.dwNumberOfProcessors < INT_MAX) - return (int)info.dwNumberOfProcessors; - else - return -1; -#elif defined(HAVE_SYSCONF) -#ifdef _SC_NPROCESSORS_CONF - long cpus_conf = sysconf(_SC_NPROCESSORS_CONF); -#else - long cpus_conf = -1; -#endif -#ifdef _SC_NPROCESSORS_ONLN - long cpus_onln = sysconf(_SC_NPROCESSORS_ONLN); -#else - long cpus_onln = -1; -#endif - long cpus = -1; - - if (cpus_conf > 0 && cpus_onln < 0) { - cpus = cpus_conf; - } else if (cpus_onln > 0 && cpus_conf < 0) { - cpus = cpus_onln; - } else if (cpus_onln > 0 && cpus_conf > 0) { - if (cpus_onln < cpus_conf) { - log_notice(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them " - "are available. Telling Tor to only use %ld. You can over" - "ride this with the NumCPUs option", - cpus_conf, cpus_onln, cpus_onln); - } - cpus = cpus_onln; - } - - if (cpus >= 1 && cpus < INT_MAX) - return (int)cpus; - else - return -1; -#else - return -1; -#endif /* defined(_WIN32) || ... */ -} - -#define MAX_DETECTABLE_CPUS 16 - -/** Return how many CPUs we are running with. We assume that nobody is - * using hot-swappable CPUs, so we don't recompute this after the first - * time. Return -1 if we don't know how to tell the number of CPUs on this - * system. - */ -int -compute_num_cpus(void) -{ - static int num_cpus = -2; - if (num_cpus == -2) { - num_cpus = compute_num_cpus_impl(); - tor_assert(num_cpus != -2); - if (num_cpus > MAX_DETECTABLE_CPUS) { - /* LCOV_EXCL_START */ - log_notice(LD_GENERAL, "Wow! I detected that you have %d CPUs. I " - "will not autodetect any more than %d, though. If you " - "want to configure more, set NumCPUs in your torrc", - num_cpus, MAX_DETECTABLE_CPUS); - num_cpus = MAX_DETECTABLE_CPUS; - /* LCOV_EXCL_STOP */ - } - } - return num_cpus; -} - -#if !defined(_WIN32) -/** Defined iff we need to add locks when defining fake versions of reentrant - * versions of time-related functions. */ -#define TIME_FNS_NEED_LOCKS -#endif - -/** Helper: Deal with confused or out-of-bounds values from localtime_r and - * friends. (On some platforms, they can give out-of-bounds values or can - * return NULL.) If <b>islocal</b>, this is a localtime result; otherwise - * it's from gmtime. The function returns <b>r</b>, when given <b>timep</b> - * as its input. If we need to store new results, store them in - * <b>resultbuf</b>. */ -static struct tm * -correct_tm(int islocal, const time_t *timep, struct tm *resultbuf, - struct tm *r) -{ - const char *outcome; - - if (PREDICT_LIKELY(r)) { - /* We can't strftime dates after 9999 CE, and we want to avoid dates - * before 1 CE (avoiding the year 0 issue and negative years). */ - if (r->tm_year > 8099) { - r->tm_year = 8099; - r->tm_mon = 11; - r->tm_mday = 31; - r->tm_yday = 364; - r->tm_wday = 6; - r->tm_hour = 23; - r->tm_min = 59; - r->tm_sec = 59; - } else if (r->tm_year < (1-1900)) { - r->tm_year = (1-1900); - r->tm_mon = 0; - r->tm_mday = 1; - r->tm_yday = 0; - r->tm_wday = 0; - r->tm_hour = 0; - r->tm_min = 0; - r->tm_sec = 0; - } - return r; - } - - /* If we get here, gmtime or localtime returned NULL. It might have done - * this because of overrun or underrun, or it might have done it because of - * some other weird issue. */ - if (timep) { - if (*timep < 0) { - r = resultbuf; - r->tm_year = 70; /* 1970 CE */ - r->tm_mon = 0; - r->tm_mday = 1; - r->tm_yday = 0; - r->tm_wday = 0; - r->tm_hour = 0; - r->tm_min = 0 ; - r->tm_sec = 0; - outcome = "Rounding up to 1970"; - goto done; - } else if (*timep >= INT32_MAX) { - /* Rounding down to INT32_MAX isn't so great, but keep in mind that we - * only do it if gmtime/localtime tells us NULL. */ - r = resultbuf; - r->tm_year = 137; /* 2037 CE */ - r->tm_mon = 11; - r->tm_mday = 31; - r->tm_yday = 364; - r->tm_wday = 6; - r->tm_hour = 23; - r->tm_min = 59; - r->tm_sec = 59; - outcome = "Rounding down to 2037"; - goto done; - } - } - - /* If we get here, then gmtime/localtime failed without getting an extreme - * value for *timep */ - /* LCOV_EXCL_START */ - tor_fragile_assert(); - r = resultbuf; - memset(resultbuf, 0, sizeof(struct tm)); - outcome="can't recover"; - /* LCOV_EXCL_STOP */ - done: - log_warn(LD_BUG, "%s("I64_FORMAT") failed with error %s: %s", - islocal?"localtime":"gmtime", - timep?I64_PRINTF_ARG(*timep):0, - strerror(errno), - outcome); - return r; -} - -/** @{ */ -/** As localtime_r, but defined for platforms that don't have it: - * - * Convert *<b>timep</b> to a struct tm in local time, and store the value in - * *<b>result</b>. Return the result on success, or NULL on failure. - */ -#ifdef HAVE_LOCALTIME_R -struct tm * -tor_localtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - r = localtime_r(timep, result); - return correct_tm(1, timep, result, r); -} -#elif defined(TIME_FNS_NEED_LOCKS) -struct tm * -tor_localtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - static tor_mutex_t *m=NULL; - if (!m) { m=tor_mutex_new(); } - tor_assert(result); - tor_mutex_acquire(m); - r = localtime(timep); - if (r) - memcpy(result, r, sizeof(struct tm)); - tor_mutex_release(m); - return correct_tm(1, timep, result, r); -} -#else -struct tm * -tor_localtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - tor_assert(result); - r = localtime(timep); - if (r) - memcpy(result, r, sizeof(struct tm)); - return correct_tm(1, timep, result, r); -} -#endif /* defined(HAVE_LOCALTIME_R) || ... */ -/** @} */ - -/** @{ */ -/** As gmtime_r, but defined for platforms that don't have it: - * - * Convert *<b>timep</b> to a struct tm in UTC, and store the value in - * *<b>result</b>. Return the result on success, or NULL on failure. - */ -#ifdef HAVE_GMTIME_R -struct tm * -tor_gmtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - r = gmtime_r(timep, result); - return correct_tm(0, timep, result, r); -} -#elif defined(TIME_FNS_NEED_LOCKS) -struct tm * -tor_gmtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - static tor_mutex_t *m=NULL; - if (!m) { m=tor_mutex_new(); } - tor_assert(result); - tor_mutex_acquire(m); - r = gmtime(timep); - if (r) - memcpy(result, r, sizeof(struct tm)); - tor_mutex_release(m); - return correct_tm(0, timep, result, r); -} -#else -struct tm * -tor_gmtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - tor_assert(result); - r = gmtime(timep); - if (r) - memcpy(result, r, sizeof(struct tm)); - return correct_tm(0, timep, result, r); -} -#endif /* defined(HAVE_GMTIME_R) || ... */ - -#if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK) -#define HAVE_UNIX_MLOCKALL -#endif - -#ifdef HAVE_UNIX_MLOCKALL -/** Attempt to raise the current and max rlimit to infinity for our process. - * This only needs to be done once and can probably only be done when we have - * not already dropped privileges. - */ -static int -tor_set_max_memlock(void) -{ - /* Future consideration for Windows is probably SetProcessWorkingSetSize - * This is similar to setting the memory rlimit of RLIMIT_MEMLOCK - * http://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx - */ - - struct rlimit limit; - - /* RLIM_INFINITY is -1 on some platforms. */ - limit.rlim_cur = RLIM_INFINITY; - limit.rlim_max = RLIM_INFINITY; - - if (setrlimit(RLIMIT_MEMLOCK, &limit) == -1) { - if (errno == EPERM) { - log_warn(LD_GENERAL, "You appear to lack permissions to change memory " - "limits. Are you root?"); - } - log_warn(LD_GENERAL, "Unable to raise RLIMIT_MEMLOCK: %s", - strerror(errno)); - return -1; - } - - return 0; -} -#endif /* defined(HAVE_UNIX_MLOCKALL) */ - -/** Attempt to lock all current and all future memory pages. - * This should only be called once and while we're privileged. - * Like mlockall() we return 0 when we're successful and -1 when we're not. - * Unlike mlockall() we return 1 if we've already attempted to lock memory. - */ -int -tor_mlockall(void) -{ - static int memory_lock_attempted = 0; - - if (memory_lock_attempted) { - return 1; - } - - memory_lock_attempted = 1; - - /* - * Future consideration for Windows may be VirtualLock - * VirtualLock appears to implement mlock() but not mlockall() - * - * http://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx - */ - -#ifdef HAVE_UNIX_MLOCKALL - if (tor_set_max_memlock() == 0) { - log_debug(LD_GENERAL, "RLIMIT_MEMLOCK is now set to RLIM_INFINITY."); - } - - if (mlockall(MCL_CURRENT|MCL_FUTURE) == 0) { - log_info(LD_GENERAL, "Insecure OS paging is effectively disabled."); - return 0; - } else { - if (errno == ENOSYS) { - /* Apple - it's 2009! I'm looking at you. Grrr. */ - log_notice(LD_GENERAL, "It appears that mlockall() is not available on " - "your platform."); - } else if (errno == EPERM) { - log_notice(LD_GENERAL, "It appears that you lack the permissions to " - "lock memory. Are you root?"); - } - log_notice(LD_GENERAL, "Unable to lock all current and future memory " - "pages: %s", strerror(errno)); - return -1; - } -#else /* !(defined(HAVE_UNIX_MLOCKALL)) */ - log_warn(LD_GENERAL, "Unable to lock memory pages. mlockall() unsupported?"); - return -1; -#endif /* defined(HAVE_UNIX_MLOCKALL) */ -} - -/** - * On Windows, WSAEWOULDBLOCK is not always correct: when you see it, - * you need to ask the socket for its actual errno. Also, you need to - * get your errors from WSAGetLastError, not errno. (If you supply a - * socket of -1, we check WSAGetLastError, but don't correct - * WSAEWOULDBLOCKs.) - * - * The upshot of all of this is that when a socket call fails, you - * should call tor_socket_errno <em>at most once</em> on the failing - * socket to get the error. - */ -#if defined(_WIN32) -int -tor_socket_errno(tor_socket_t sock) -{ - int optval, optvallen=sizeof(optval); - int err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK && SOCKET_OK(sock)) { - if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval, &optvallen)) - return err; - if (optval) - return optval; - } - return err; -} -#endif /* defined(_WIN32) */ - -#if defined(_WIN32) -#define E(code, s) { code, (s " [" #code " ]") } -struct { int code; const char *msg; } windows_socket_errors[] = { - E(WSAEINTR, "Interrupted function call"), - E(WSAEACCES, "Permission denied"), - E(WSAEFAULT, "Bad address"), - E(WSAEINVAL, "Invalid argument"), - E(WSAEMFILE, "Too many open files"), - E(WSAEWOULDBLOCK, "Resource temporarily unavailable"), - E(WSAEINPROGRESS, "Operation now in progress"), - E(WSAEALREADY, "Operation already in progress"), - E(WSAENOTSOCK, "Socket operation on nonsocket"), - E(WSAEDESTADDRREQ, "Destination address required"), - E(WSAEMSGSIZE, "Message too long"), - E(WSAEPROTOTYPE, "Protocol wrong for socket"), - E(WSAENOPROTOOPT, "Bad protocol option"), - E(WSAEPROTONOSUPPORT, "Protocol not supported"), - E(WSAESOCKTNOSUPPORT, "Socket type not supported"), - /* What's the difference between NOTSUPP and NOSUPPORT? :) */ - E(WSAEOPNOTSUPP, "Operation not supported"), - E(WSAEPFNOSUPPORT, "Protocol family not supported"), - E(WSAEAFNOSUPPORT, "Address family not supported by protocol family"), - E(WSAEADDRINUSE, "Address already in use"), - E(WSAEADDRNOTAVAIL, "Cannot assign requested address"), - E(WSAENETDOWN, "Network is down"), - E(WSAENETUNREACH, "Network is unreachable"), - E(WSAENETRESET, "Network dropped connection on reset"), - E(WSAECONNABORTED, "Software caused connection abort"), - E(WSAECONNRESET, "Connection reset by peer"), - E(WSAENOBUFS, "No buffer space available"), - E(WSAEISCONN, "Socket is already connected"), - E(WSAENOTCONN, "Socket is not connected"), - E(WSAESHUTDOWN, "Cannot send after socket shutdown"), - E(WSAETIMEDOUT, "Connection timed out"), - E(WSAECONNREFUSED, "Connection refused"), - E(WSAEHOSTDOWN, "Host is down"), - E(WSAEHOSTUNREACH, "No route to host"), - E(WSAEPROCLIM, "Too many processes"), - /* Yes, some of these start with WSA, not WSAE. No, I don't know why. */ - E(WSASYSNOTREADY, "Network subsystem is unavailable"), - E(WSAVERNOTSUPPORTED, "Winsock.dll out of range"), - E(WSANOTINITIALISED, "Successful WSAStartup not yet performed"), - E(WSAEDISCON, "Graceful shutdown now in progress"), -#ifdef WSATYPE_NOT_FOUND - E(WSATYPE_NOT_FOUND, "Class type not found"), -#endif - E(WSAHOST_NOT_FOUND, "Host not found"), - E(WSATRY_AGAIN, "Nonauthoritative host not found"), - E(WSANO_RECOVERY, "This is a nonrecoverable error"), - E(WSANO_DATA, "Valid name, no data record of requested type)"), - - /* There are some more error codes whose numeric values are marked - * <b>OS dependent</b>. They start with WSA_, apparently for the same - * reason that practitioners of some craft traditions deliberately - * introduce imperfections into their baskets and rugs "to allow the - * evil spirits to escape." If we catch them, then our binaries - * might not report consistent results across versions of Windows. - * Thus, I'm going to let them all fall through. - */ - { -1, NULL }, -}; -/** There does not seem to be a strerror equivalent for Winsock errors. - * Naturally, we have to roll our own. - */ -const char * -tor_socket_strerror(int e) -{ - int i; - for (i=0; windows_socket_errors[i].code >= 0; ++i) { - if (e == windows_socket_errors[i].code) - return windows_socket_errors[i].msg; - } - return strerror(e); -} -#endif /* defined(_WIN32) */ - -/** Called before we make any calls to network-related functions. - * (Some operating systems require their network libraries to be - * initialized.) */ -int -network_init(void) -{ -#ifdef _WIN32 - /* This silly exercise is necessary before windows will allow - * gethostbyname to work. */ - WSADATA WSAData; - int r; - r = WSAStartup(0x101,&WSAData); - if (r) { - log_warn(LD_NET,"Error initializing windows network layer: code was %d",r); - return -1; - } - if (sizeof(SOCKET) != sizeof(tor_socket_t)) { - log_warn(LD_BUG,"The tor_socket_t type does not match SOCKET in size; Tor " - "might not work. (Sizes are %d and %d respectively.)", - (int)sizeof(tor_socket_t), (int)sizeof(SOCKET)); - } - /* WSAData.iMaxSockets might show the max sockets we're allowed to use. - * We might use it to complain if we're trying to be a server but have - * too few sockets available. */ -#endif /* defined(_WIN32) */ - return 0; -} - -#ifdef _WIN32 -/** Return a newly allocated string describing the windows system error code - * <b>err</b>. Note that error codes are different from errno. Error codes - * come from GetLastError() when a winapi call fails. errno is set only when - * ANSI functions fail. Whee. */ -char * -format_win32_error(DWORD err) -{ - TCHAR *str = NULL; - char *result; - DWORD n; - - /* Somebody once decided that this interface was better than strerror(). */ - n = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, err, - MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), - (LPVOID)&str, - 0, NULL); - - if (str && n) { -#ifdef UNICODE - size_t len; - if (n > 128*1024) - len = (128 * 1024) * 2 + 1; /* This shouldn't be possible, but let's - * make sure. */ - else - len = n * 2 + 1; - result = tor_malloc(len); - wcstombs(result,str,len); - result[len-1] = '\0'; -#else /* !(defined(UNICODE)) */ - result = tor_strdup(str); -#endif /* defined(UNICODE) */ - } else { - result = tor_strdup("<unformattable error>"); - } - if (str) { - LocalFree(str); /* LocalFree != free() */ - } - return result; -} -#endif /* defined(_WIN32) */ - -#if defined(HW_PHYSMEM64) -/* This appears to be an OpenBSD thing */ -#define INT64_HW_MEM HW_PHYSMEM64 -#elif defined(HW_MEMSIZE) -/* OSX defines this one */ -#define INT64_HW_MEM HW_MEMSIZE -#endif /* defined(HW_PHYSMEM64) || ... */ - -/** - * Helper: try to detect the total system memory, and return it. On failure, - * return 0. - */ -static uint64_t -get_total_system_memory_impl(void) -{ -#if defined(__linux__) - /* On linux, sysctl is deprecated. Because proc is so awesome that you - * shouldn't _want_ to write portable code, I guess? */ - unsigned long long result=0; - int fd = -1; - char *s = NULL; - const char *cp; - size_t file_size=0; - if (-1 == (fd = tor_open_cloexec("/proc/meminfo",O_RDONLY,0))) - return 0; - s = read_file_to_str_until_eof(fd, 65536, &file_size); - if (!s) - goto err; - cp = strstr(s, "MemTotal:"); - if (!cp) - goto err; - /* Use the system sscanf so that space will match a wider number of space */ - if (sscanf(cp, "MemTotal: %llu kB\n", &result) != 1) - goto err; - - close(fd); - tor_free(s); - return result * 1024; - - /* LCOV_EXCL_START Can't reach this unless proc is broken. */ - err: - tor_free(s); - close(fd); - return 0; - /* LCOV_EXCL_STOP */ -#elif defined (_WIN32) - /* Windows has MEMORYSTATUSEX; pretty straightforward. */ - MEMORYSTATUSEX ms; - memset(&ms, 0, sizeof(ms)); - ms.dwLength = sizeof(ms); - if (! GlobalMemoryStatusEx(&ms)) - return 0; - - return ms.ullTotalPhys; - -#elif defined(HAVE_SYSCTL) && defined(INT64_HW_MEM) - /* On many systems, HW_PYHSMEM is clipped to 32 bits; let's use a better - * variant if we know about it. */ - uint64_t memsize = 0; - size_t len = sizeof(memsize); - int mib[2] = {CTL_HW, INT64_HW_MEM}; - if (sysctl(mib,2,&memsize,&len,NULL,0)) - return 0; - - return memsize; - -#elif defined(HAVE_SYSCTL) && defined(HW_PHYSMEM) - /* On some systems (like FreeBSD I hope) you can use a size_t with - * HW_PHYSMEM. */ - size_t memsize=0; - size_t len = sizeof(memsize); - int mib[2] = {CTL_HW, HW_USERMEM}; - if (sysctl(mib,2,&memsize,&len,NULL,0)) - return 0; - - return memsize; - -#else - /* I have no clue. */ - return 0; -#endif /* defined(__linux__) || ... */ -} - -/** - * Try to find out how much physical memory the system has. On success, - * return 0 and set *<b>mem_out</b> to that value. On failure, return -1. - */ -MOCK_IMPL(int, -get_total_system_memory, (size_t *mem_out)) -{ - static size_t mem_cached=0; - uint64_t m = get_total_system_memory_impl(); - if (0 == m) { - /* LCOV_EXCL_START -- can't make this happen without mocking. */ - /* We couldn't find our memory total */ - if (0 == mem_cached) { - /* We have no cached value either */ - *mem_out = 0; - return -1; - } - - *mem_out = mem_cached; - return 0; - /* LCOV_EXCL_STOP */ - } - -#if SIZE_MAX != UINT64_MAX - if (m > SIZE_MAX) { - /* I think this could happen if we're a 32-bit Tor running on a 64-bit - * system: we could have more system memory than would fit in a - * size_t. */ - m = SIZE_MAX; - } -#endif /* SIZE_MAX != UINT64_MAX */ - - *mem_out = mem_cached = (size_t) m; - - return 0; -} - -/** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b> - * bytes of passphrase into <b>output</b>. Return the number of bytes in - * the passphrase, excluding terminating NUL. - */ -ssize_t -tor_getpass(const char *prompt, char *output, size_t buflen) -{ - tor_assert(buflen <= SSIZE_MAX); - tor_assert(buflen >= 1); -#if defined(HAVE_READPASSPHRASE) - char *pwd = readpassphrase(prompt, output, buflen, RPP_ECHO_OFF); - if (pwd == NULL) - return -1; - return strlen(pwd); -#elif defined(_WIN32) - int r = -1; - while (*prompt) { - _putch(*prompt++); - } - - tor_assert(buflen <= INT_MAX); - wchar_t *buf = tor_calloc(buflen, sizeof(wchar_t)); - - wchar_t *ptr = buf, *lastch = buf + buflen - 1; - while (ptr < lastch) { - wint_t ch = _getwch(); - switch (ch) { - case '\r': - case '\n': - case WEOF: - goto done_reading; - case 3: - goto done; /* Can't actually read ctrl-c this way. */ - case '\b': - if (ptr > buf) - --ptr; - continue; - case 0: - case 0xe0: - ch = _getwch(); /* Ignore; this is a function or arrow key */ - break; - default: - *ptr++ = ch; - break; - } - } - done_reading: - ; - -#ifndef WC_ERR_INVALID_CHARS -#define WC_ERR_INVALID_CHARS 0x80 -#endif - - /* Now convert it to UTF-8 */ - r = WideCharToMultiByte(CP_UTF8, - WC_NO_BEST_FIT_CHARS|WC_ERR_INVALID_CHARS, - buf, (int)(ptr-buf), - output, (int)(buflen-1), - NULL, NULL); - if (r <= 0) { - r = -1; - goto done; - } - - tor_assert(r < (int)buflen); - - output[r] = 0; - - done: - SecureZeroMemory(buf, sizeof(wchar_t)*buflen); - tor_free(buf); - return r; -#else -#error "No implementation for tor_getpass found!" -#endif /* defined(HAVE_READPASSPHRASE) || ... */ -} - -/** Return the amount of free disk space we have permission to use, in - * bytes. Return -1 if the amount of free space can't be determined. */ -int64_t -tor_get_avail_disk_space(const char *path) -{ -#ifdef HAVE_STATVFS - struct statvfs st; - int r; - memset(&st, 0, sizeof(st)); - - r = statvfs(path, &st); - if (r < 0) - return -1; - - int64_t result = st.f_bavail; - if (st.f_frsize) { - result *= st.f_frsize; - } else if (st.f_bsize) { - result *= st.f_bsize; - } else { - return -1; - } - - return result; -#elif defined(_WIN32) - ULARGE_INTEGER freeBytesAvail; - BOOL ok; - - ok = GetDiskFreeSpaceEx(path, &freeBytesAvail, NULL, NULL); - if (!ok) { - return -1; - } - return (int64_t)freeBytesAvail.QuadPart; -#else - (void)path; - errno = ENOSYS; - return -1; -#endif /* defined(HAVE_STATVFS) || ... */ -} - diff --git a/src/common/compat.h b/src/common/compat.h deleted file mode 100644 index c7e7f8d9ef..0000000000 --- a/src/common/compat.h +++ /dev/null @@ -1,757 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_COMPAT_H -#define TOR_COMPAT_H - -#include "orconfig.h" -#ifdef _WIN32 -#include <winsock2.h> -#include <ws2tcpip.h> -#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY -#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747b -#endif -#endif -#include "torint.h" -#include "testsupport.h" -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#include <stdarg.h> -#ifdef HAVE_SYS_RESOURCE_H -#include <sys/resource.h> -#endif -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif -#ifdef HAVE_NETINET6_IN6_H -#include <netinet6/in6.h> -#endif - -#include "compat_time.h" - -#if defined(__has_feature) -# if __has_feature(address_sanitizer) -/* Some of the fancy glibc strcmp() macros include references to memory that - * clang rejects because it is off the end of a less-than-3. Clang hates this, - * even though those references never actually happen. */ -# undef strcmp -#endif /* __has_feature(address_sanitizer) */ -#endif /* defined(__has_feature) */ - -#include <stdio.h> -#include <errno.h> - -#ifndef NULL_REP_IS_ZERO_BYTES -#error "It seems your platform does not represent NULL as zero. We can't cope." -#endif - -#ifndef DOUBLE_0_REP_IS_ZERO_BYTES -#error "It seems your platform does not represent 0.0 as zeros. We can't cope." -#endif - -#if 'a'!=97 || 'z'!=122 || 'A'!=65 || ' '!=32 -#error "It seems that you encode characters in something other than ASCII." -#endif - -/* ===== Compiler compatibility */ - -/* GCC can check printf and scanf types on arbitrary functions. */ -#ifdef __GNUC__ -#define CHECK_PRINTF(formatIdx, firstArg) \ - __attribute__ ((format(printf, formatIdx, firstArg))) -#else -#define CHECK_PRINTF(formatIdx, firstArg) -#endif /* defined(__GNUC__) */ -#ifdef __GNUC__ -#define CHECK_SCANF(formatIdx, firstArg) \ - __attribute__ ((format(scanf, formatIdx, firstArg))) -#else -#define CHECK_SCANF(formatIdx, firstArg) -#endif /* defined(__GNUC__) */ - -/* What GCC do we have? */ -#ifdef __GNUC__ -#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -#else -#define GCC_VERSION 0 -#endif - -/* Temporarily enable and disable warnings. */ -#ifdef __GNUC__ -# define PRAGMA_STRINGIFY_(s) #s -# define PRAGMA_JOIN_STRINGIFY_(a,b) PRAGMA_STRINGIFY_(a ## b) -/* Support for macro-generated pragmas (c99) */ -# define PRAGMA_(x) _Pragma (#x) -# ifdef __clang__ -# define PRAGMA_DIAGNOSTIC_(x) PRAGMA_(clang diagnostic x) -# else -# define PRAGMA_DIAGNOSTIC_(x) PRAGMA_(GCC diagnostic x) -# endif -# if defined(__clang__) || GCC_VERSION >= 406 -/* we have push/pop support */ -# define DISABLE_GCC_WARNING(warningopt) \ - PRAGMA_DIAGNOSTIC_(push) \ - PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) -# define ENABLE_GCC_WARNING(warningopt) \ - PRAGMA_DIAGNOSTIC_(pop) -#else /* !(defined(__clang__) || GCC_VERSION >= 406) */ -/* older version of gcc: no push/pop support. */ -# define DISABLE_GCC_WARNING(warningopt) \ - PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) -# define ENABLE_GCC_WARNING(warningopt) \ - PRAGMA_DIAGNOSTIC_(warning PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) -#endif /* defined(__clang__) || GCC_VERSION >= 406 */ -#else /* !(defined(__GNUC__)) */ -/* not gcc at all */ -# define DISABLE_GCC_WARNING(warning) -# define ENABLE_GCC_WARNING(warning) -#endif /* defined(__GNUC__) */ - -/* inline is __inline on windows. */ -#ifdef _WIN32 -#define inline __inline -#endif - -/* Try to get a reasonable __func__ substitute in place. */ -#if defined(_MSC_VER) - -#define __func__ __FUNCTION__ - -#else -/* For platforms where autoconf works, make sure __func__ is defined - * sanely. */ -#ifndef HAVE_MACRO__func__ -#ifdef HAVE_MACRO__FUNCTION__ -#define __func__ __FUNCTION__ -#elif HAVE_MACRO__FUNC__ -#define __func__ __FUNC__ -#else -#define __func__ "???" -#endif /* defined(HAVE_MACRO__FUNCTION__) || ... */ -#endif /* !defined(HAVE_MACRO__func__) */ -#endif /* defined(_MSC_VER) */ - -#define U64_TO_DBL(x) ((double) (x)) -#define DBL_TO_U64(x) ((uint64_t) (x)) - -#ifdef ENUM_VALS_ARE_SIGNED -#define ENUM_BF(t) unsigned -#else -/** Wrapper for having a bitfield of an enumerated type. Where possible, we - * just use the enumerated type (so the compiler can help us and notice - * problems), but if enumerated types are unsigned, we must use unsigned, - * so that the loss of precision doesn't make large values negative. */ -#define ENUM_BF(t) t -#endif /* defined(ENUM_VALS_ARE_SIGNED) */ - -/* GCC has several useful attributes. */ -#if defined(__GNUC__) && __GNUC__ >= 3 -#define ATTR_NORETURN __attribute__((noreturn)) -#define ATTR_CONST __attribute__((const)) -#define ATTR_MALLOC __attribute__((malloc)) -#define ATTR_NORETURN __attribute__((noreturn)) -#define ATTR_WUR __attribute__((warn_unused_result)) -/* Alas, nonnull is not at present a good idea for us. We'd like to get - * warnings when we pass NULL where we shouldn't (which nonnull does, albeit - * spottily), but we don't want to tell the compiler to make optimizations - * with the assumption that the argument can't be NULL (since this would make - * many of our checks go away, and make our code less robust against - * programming errors). Unfortunately, nonnull currently does both of these - * things, and there's no good way to split them up. - * - * #define ATTR_NONNULL(x) __attribute__((nonnull x)) */ -#define ATTR_NONNULL(x) -#define ATTR_UNUSED __attribute__ ((unused)) - -/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value - * of <b>exp</b> will probably be true. - * - * In other words, "if (PREDICT_LIKELY(foo))" is the same as "if (foo)", - * except that it tells the compiler that the branch will be taken most of the - * time. This can generate slightly better code with some CPUs. - */ -#define PREDICT_LIKELY(exp) __builtin_expect(!!(exp), 1) -/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value - * of <b>exp</b> will probably be false. - * - * In other words, "if (PREDICT_UNLIKELY(foo))" is the same as "if (foo)", - * except that it tells the compiler that the branch will usually not be - * taken. This can generate slightly better code with some CPUs. - */ -#define PREDICT_UNLIKELY(exp) __builtin_expect(!!(exp), 0) -#else /* !(defined(__GNUC__) && __GNUC__ >= 3) */ -#define ATTR_NORETURN -#define ATTR_CONST -#define ATTR_MALLOC -#define ATTR_NORETURN -#define ATTR_NONNULL(x) -#define ATTR_UNUSED -#define ATTR_WUR -#define PREDICT_LIKELY(exp) (exp) -#define PREDICT_UNLIKELY(exp) (exp) -#endif /* defined(__GNUC__) && __GNUC__ >= 3 */ - -/** Expands to a syntactically valid empty statement. */ -#define STMT_NIL (void)0 - -/** Expands to a syntactically valid empty statement, explicitly (void)ing its - * argument. */ -#define STMT_VOID(a) while (0) { (void)(a); } - -#ifdef __GNUC__ -/** STMT_BEGIN and STMT_END are used to wrap blocks inside macros so that - * the macro can be used as if it were a single C statement. */ -#define STMT_BEGIN (void) ({ -#define STMT_END }) -#elif defined(sun) || defined(__sun__) -#define STMT_BEGIN if (1) { -#define STMT_END } else STMT_NIL -#else -#define STMT_BEGIN do { -#define STMT_END } while (0) -#endif /* defined(__GNUC__) || ... */ - -/* Some tools (like coccinelle) don't like to see operators as macro - * arguments. */ -#define OP_LT < -#define OP_GT > -#define OP_GE >= -#define OP_LE <= -#define OP_EQ == -#define OP_NE != - -/* ===== String compatibility */ -#ifdef _WIN32 -/* Windows names string functions differently from most other platforms. */ -#define strncasecmp _strnicmp -#define strcasecmp _stricmp -#endif - -#if defined __APPLE__ -/* On OSX 10.9 and later, the overlap-checking code for strlcat would - * appear to have a severe bug that can sometimes cause aborts in Tor. - * Instead, use the non-checking variants. This is sad. - * - * See https://trac.torproject.org/projects/tor/ticket/15205 - */ -#undef strlcat -#undef strlcpy -#endif /* defined __APPLE__ */ - -#ifndef HAVE_STRLCAT -size_t strlcat(char *dst, const char *src, size_t siz) ATTR_NONNULL((1,2)); -#endif -#ifndef HAVE_STRLCPY -size_t strlcpy(char *dst, const char *src, size_t siz) ATTR_NONNULL((1,2)); -#endif - -#ifdef _MSC_VER -/** Casts the uint64_t value in <b>a</b> to the right type for an argument - * to printf. */ -#define U64_PRINTF_ARG(a) (a) -/** Casts the uint64_t* value in <b>a</b> to the right type for an argument - * to scanf. */ -#define U64_SCANF_ARG(a) (a) -/** Expands to a literal uint64_t-typed constant for the value <b>n</b>. */ -#define U64_LITERAL(n) (n ## ui64) -#define I64_PRINTF_ARG(a) (a) -#define I64_SCANF_ARG(a) (a) -#define I64_LITERAL(n) (n ## i64) -#else /* !(defined(_MSC_VER)) */ -#define U64_PRINTF_ARG(a) ((long long unsigned int)(a)) -#define U64_SCANF_ARG(a) ((long long unsigned int*)(a)) -#define U64_LITERAL(n) (n ## llu) -#define I64_PRINTF_ARG(a) ((long long signed int)(a)) -#define I64_SCANF_ARG(a) ((long long signed int*)(a)) -#define I64_LITERAL(n) (n ## ll) -#endif /* defined(_MSC_VER) */ - -#if defined(__MINGW32__) || defined(__MINGW64__) -#define MINGW_ANY -#endif - -#if defined(_MSC_VER) || defined(MINGW_ANY) -/** The formatting string used to put a uint64_t value in a printf() or - * scanf() function. See also U64_PRINTF_ARG and U64_SCANF_ARG. */ -#define U64_FORMAT "%I64u" -#define I64_FORMAT "%I64d" -#else /* !(defined(_MSC_VER) || defined(MINGW_ANY)) */ -#define U64_FORMAT "%llu" -#define I64_FORMAT "%lld" -#endif /* defined(_MSC_VER) || defined(MINGW_ANY) */ - -#if (SIZEOF_INTPTR_T == SIZEOF_INT) -#define INTPTR_T_FORMAT "%d" -#define INTPTR_PRINTF_ARG(x) ((int)(x)) -#elif (SIZEOF_INTPTR_T == SIZEOF_LONG) -#define INTPTR_T_FORMAT "%ld" -#define INTPTR_PRINTF_ARG(x) ((long)(x)) -#elif (SIZEOF_INTPTR_T == 8) -#define INTPTR_T_FORMAT I64_FORMAT -#define INTPTR_PRINTF_ARG(x) I64_PRINTF_ARG(x) -#else -#error Unknown: SIZEOF_INTPTR_T -#endif /* (SIZEOF_INTPTR_T == SIZEOF_INT) || ... */ - -/** Represents an mmaped file. Allocated via tor_mmap_file; freed with - * tor_munmap_file. */ -typedef struct tor_mmap_t { - const char *data; /**< Mapping of the file's contents. */ - size_t size; /**< Size of the file. */ - - /* None of the fields below should be accessed from outside compat.c */ -#ifdef HAVE_MMAP - size_t mapping_size; /**< Size of the actual mapping. (This is this file - * size, rounded up to the nearest page.) */ -#elif defined _WIN32 - HANDLE mmap_handle; -#endif /* defined(HAVE_MMAP) || ... */ - -} tor_mmap_t; - -tor_mmap_t *tor_mmap_file(const char *filename) ATTR_NONNULL((1)); -int tor_munmap_file(tor_mmap_t *handle) ATTR_NONNULL((1)); - -int tor_snprintf(char *str, size_t size, const char *format, ...) - CHECK_PRINTF(3,4) ATTR_NONNULL((1,3)); -int tor_vsnprintf(char *str, size_t size, const char *format, va_list args) - CHECK_PRINTF(3,0) ATTR_NONNULL((1,3)); - -int tor_asprintf(char **strp, const char *fmt, ...) - CHECK_PRINTF(2,3); -int tor_vasprintf(char **strp, const char *fmt, va_list args) - CHECK_PRINTF(2,0); - -const void *tor_memmem(const void *haystack, size_t hlen, const void *needle, - size_t nlen) ATTR_NONNULL((1,3)); -static const void *tor_memstr(const void *haystack, size_t hlen, - const char *needle) ATTR_NONNULL((1,3)); -static inline const void * -tor_memstr(const void *haystack, size_t hlen, const char *needle) -{ - return tor_memmem(haystack, hlen, needle, strlen(needle)); -} - -/* Much of the time when we're checking ctypes, we're doing spec compliance, - * which all assumes we're doing ASCII. */ -#define DECLARE_CTYPE_FN(name) \ - static int TOR_##name(char c); \ - extern const uint32_t TOR_##name##_TABLE[]; \ - static inline int TOR_##name(char c) { \ - uint8_t u = c; \ - return !!(TOR_##name##_TABLE[(u >> 5) & 7] & (1u << (u & 31))); \ - } -DECLARE_CTYPE_FN(ISALPHA) -DECLARE_CTYPE_FN(ISALNUM) -DECLARE_CTYPE_FN(ISSPACE) -DECLARE_CTYPE_FN(ISDIGIT) -DECLARE_CTYPE_FN(ISXDIGIT) -DECLARE_CTYPE_FN(ISPRINT) -DECLARE_CTYPE_FN(ISLOWER) -DECLARE_CTYPE_FN(ISUPPER) -extern const uint8_t TOR_TOUPPER_TABLE[]; -extern const uint8_t TOR_TOLOWER_TABLE[]; -#define TOR_TOLOWER(c) (TOR_TOLOWER_TABLE[(uint8_t)c]) -#define TOR_TOUPPER(c) (TOR_TOUPPER_TABLE[(uint8_t)c]) - -char *tor_strtok_r_impl(char *str, const char *sep, char **lasts); -#ifdef HAVE_STRTOK_R -#define tor_strtok_r(str, sep, lasts) strtok_r(str, sep, lasts) -#else -#define tor_strtok_r(str, sep, lasts) tor_strtok_r_impl(str, sep, lasts) -#endif - -#ifdef _WIN32 -#define SHORT_FILE__ (tor_fix_source_file(__FILE__)) -const char *tor_fix_source_file(const char *fname); -#else -#define SHORT_FILE__ (__FILE__) -#define tor_fix_source_file(s) (s) -#endif /* defined(_WIN32) */ - -/* ===== Time compatibility */ - -struct tm *tor_localtime_r(const time_t *timep, struct tm *result); -struct tm *tor_gmtime_r(const time_t *timep, struct tm *result); - -#ifndef timeradd -/** Replacement for timeradd on platforms that do not have it: sets tvout to - * the sum of tv1 and tv2. */ -#define timeradd(tv1,tv2,tvout) \ - do { \ - (tvout)->tv_sec = (tv1)->tv_sec + (tv2)->tv_sec; \ - (tvout)->tv_usec = (tv1)->tv_usec + (tv2)->tv_usec; \ - if ((tvout)->tv_usec >= 1000000) { \ - (tvout)->tv_usec -= 1000000; \ - (tvout)->tv_sec++; \ - } \ - } while (0) -#endif /* !defined(timeradd) */ - -#ifndef timersub -/** Replacement for timersub on platforms that do not have it: sets tvout to - * tv1 minus tv2. */ -#define timersub(tv1,tv2,tvout) \ - do { \ - (tvout)->tv_sec = (tv1)->tv_sec - (tv2)->tv_sec; \ - (tvout)->tv_usec = (tv1)->tv_usec - (tv2)->tv_usec; \ - if ((tvout)->tv_usec < 0) { \ - (tvout)->tv_usec += 1000000; \ - (tvout)->tv_sec--; \ - } \ - } while (0) -#endif /* !defined(timersub) */ - -#ifndef timercmp -/** Replacement for timercmp on platforms that do not have it: returns true - * iff the relational operator "op" makes the expression tv1 op tv2 true. - * - * Note that while this definition should work for all boolean operators, some - * platforms' native timercmp definitions do not support >=, <=, or ==. So - * don't use those. - */ -#define timercmp(tv1,tv2,op) \ - (((tv1)->tv_sec == (tv2)->tv_sec) ? \ - ((tv1)->tv_usec op (tv2)->tv_usec) : \ - ((tv1)->tv_sec op (tv2)->tv_sec)) -#endif /* !defined(timercmp) */ - -/* ===== File compatibility */ -int tor_open_cloexec(const char *path, int flags, unsigned mode); -FILE *tor_fopen_cloexec(const char *path, const char *mode); -int tor_rename(const char *path_old, const char *path_new); - -int replace_file(const char *from, const char *to); -int touch_file(const char *fname); - -typedef struct tor_lockfile_t tor_lockfile_t; -tor_lockfile_t *tor_lockfile_lock(const char *filename, int blocking, - int *locked_out); -void tor_lockfile_unlock(tor_lockfile_t *lockfile); - -off_t tor_fd_getpos(int fd); -int tor_fd_setpos(int fd, off_t pos); -int tor_fd_seekend(int fd); -int tor_ftruncate(int fd); - -int64_t tor_get_avail_disk_space(const char *path); - -#ifdef _WIN32 -#define PATH_SEPARATOR "\\" -#else -#define PATH_SEPARATOR "/" -#endif - -/* ===== Net compatibility */ - -#if (SIZEOF_SOCKLEN_T == 0) -typedef int socklen_t; -#endif - -#ifdef _WIN32 -/* XXX Actually, this should arguably be SOCKET; we use intptr_t here so that - * any inadvertent checks for the socket being <= 0 or > 0 will probably - * still work. */ -#define tor_socket_t intptr_t -#define TOR_SOCKET_T_FORMAT INTPTR_T_FORMAT -#define SOCKET_OK(s) ((SOCKET)(s) != INVALID_SOCKET) -#define TOR_INVALID_SOCKET INVALID_SOCKET -#else /* !(defined(_WIN32)) */ -/** Type used for a network socket. */ -#define tor_socket_t int -#define TOR_SOCKET_T_FORMAT "%d" -/** Macro: true iff 's' is a possible value for a valid initialized socket. */ -#define SOCKET_OK(s) ((s) >= 0) -/** Error/uninitialized value for a tor_socket_t. */ -#define TOR_INVALID_SOCKET (-1) -#endif /* defined(_WIN32) */ - -int tor_close_socket_simple(tor_socket_t s); -MOCK_DECL(int, tor_close_socket, (tor_socket_t s)); -void tor_take_socket_ownership(tor_socket_t s); -tor_socket_t tor_open_socket_with_extensions( - int domain, int type, int protocol, - int cloexec, int nonblock); -MOCK_DECL(tor_socket_t, -tor_open_socket,(int domain, int type, int protocol)); -tor_socket_t tor_open_socket_nonblocking(int domain, int type, int protocol); -tor_socket_t tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, - socklen_t *len); -tor_socket_t tor_accept_socket_nonblocking(tor_socket_t sockfd, - struct sockaddr *addr, - socklen_t *len); -tor_socket_t tor_accept_socket_with_extensions(tor_socket_t sockfd, - struct sockaddr *addr, - socklen_t *len, - int cloexec, int nonblock); -MOCK_DECL(tor_socket_t, -tor_connect_socket,(tor_socket_t socket,const struct sockaddr *address, - socklen_t address_len)); -int get_n_open_sockets(void); - -MOCK_DECL(int, -tor_getsockname,(tor_socket_t socket, struct sockaddr *address, - socklen_t *address_len)); -struct tor_addr_t; -int tor_addr_from_getsockname(struct tor_addr_t *addr_out, tor_socket_t sock); - -#define tor_socket_send(s, buf, len, flags) send(s, buf, len, flags) -#define tor_socket_recv(s, buf, len, flags) recv(s, buf, len, flags) - -/** Implementation of struct in6_addr for platforms that do not have it. - * Generally, these platforms are ones without IPv6 support, but we want to - * have a working in6_addr there anyway, so we can use it to parse IPv6 - * addresses. */ -#if !defined(HAVE_STRUCT_IN6_ADDR) -struct in6_addr -{ - union { - uint8_t u6_addr8[16]; - uint16_t u6_addr16[8]; - uint32_t u6_addr32[4]; - } in6_u; -#define s6_addr in6_u.u6_addr8 -#define s6_addr16 in6_u.u6_addr16 -#define s6_addr32 in6_u.u6_addr32 -}; -#endif /* !defined(HAVE_STRUCT_IN6_ADDR) */ - -/** @{ */ -/** Many BSD variants seem not to define these. */ -#if defined(__APPLE__) || defined(__darwin__) || \ - defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -#ifndef s6_addr16 -#define s6_addr16 __u6_addr.__u6_addr16 -#endif -#ifndef s6_addr32 -#define s6_addr32 __u6_addr.__u6_addr32 -#endif -#endif /* defined(__APPLE__) || defined(__darwin__) || ... */ -/** @} */ - -#ifndef HAVE_SA_FAMILY_T -typedef uint16_t sa_family_t; -#endif - -/** @{ */ -/** Apparently, MS and Solaris don't define s6_addr16 or s6_addr32; these - * macros get you a pointer to s6_addr32 or local equivalent. */ -#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR32 -#define S6_ADDR32(x) ((uint32_t*)(x).s6_addr32) -#else -#define S6_ADDR32(x) ((uint32_t*)((char*)&(x).s6_addr)) -#endif -#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR16 -#define S6_ADDR16(x) ((uint16_t*)(x).s6_addr16) -#else -#define S6_ADDR16(x) ((uint16_t*)((char*)&(x).s6_addr)) -#endif -/** @} */ - -/** Implementation of struct sockaddr_in6 on platforms that do not have - * it. See notes on struct in6_addr. */ -#if !defined(HAVE_STRUCT_SOCKADDR_IN6) -struct sockaddr_in6 { - sa_family_t sin6_family; - uint16_t sin6_port; - // uint32_t sin6_flowinfo; - struct in6_addr sin6_addr; - // uint32_t sin6_scope_id; -}; -#endif /* !defined(HAVE_STRUCT_SOCKADDR_IN6) */ - -MOCK_DECL(int,tor_gethostname,(char *name, size_t namelen)); -int tor_inet_aton(const char *cp, struct in_addr *addr) ATTR_NONNULL((1,2)); -const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len); -int tor_inet_pton(int af, const char *src, void *dst); -MOCK_DECL(int,tor_lookup_hostname,(const char *name, uint32_t *addr)); -int set_socket_nonblocking(tor_socket_t socket); -int tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]); -int network_init(void); - -/* For stupid historical reasons, windows sockets have an independent - * set of errnos, and an independent way to get them. Also, you can't - * always believe WSAEWOULDBLOCK. Use the macros below to compare - * errnos against expected values, and use tor_socket_errno to find - * the actual errno after a socket operation fails. - */ -#if defined(_WIN32) -/** Expands to WSA<b>e</b> on Windows, and to <b>e</b> elsewhere. */ -#define SOCK_ERRNO(e) WSA##e -/** Return true if e is EAGAIN or the local equivalent. */ -#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == WSAEWOULDBLOCK) -/** Return true if e is EINPROGRESS or the local equivalent. */ -#define ERRNO_IS_EINPROGRESS(e) ((e) == WSAEINPROGRESS) -/** Return true if e is EINPROGRESS or the local equivalent as returned by - * a call to connect(). */ -#define ERRNO_IS_CONN_EINPROGRESS(e) \ - ((e) == WSAEINPROGRESS || (e)== WSAEINVAL || (e) == WSAEWOULDBLOCK) -/** Return true if e is EAGAIN or another error indicating that a call to - * accept() has no pending connections to return. */ -#define ERRNO_IS_ACCEPT_EAGAIN(e) ERRNO_IS_EAGAIN(e) -/** Return true if e is EMFILE or another error indicating that a call to - * accept() has failed because we're out of fds or something. */ -#define ERRNO_IS_RESOURCE_LIMIT(e) \ - ((e) == WSAEMFILE || (e) == WSAENOBUFS) -/** Return true if e is EADDRINUSE or the local equivalent. */ -#define ERRNO_IS_EADDRINUSE(e) ((e) == WSAEADDRINUSE) -/** Return true if e is EINTR or the local equivalent */ -#define ERRNO_IS_EINTR(e) ((e) == WSAEINTR || 0) -int tor_socket_errno(tor_socket_t sock); -const char *tor_socket_strerror(int e); -#else /* !(defined(_WIN32)) */ -#define SOCK_ERRNO(e) e -#if EAGAIN == EWOULDBLOCK -/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */ -#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || 0) -#else -#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == EWOULDBLOCK) -#endif /* EAGAIN == EWOULDBLOCK */ -#define ERRNO_IS_EINTR(e) ((e) == EINTR || 0) -#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS || 0) -#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS || 0) -#define ERRNO_IS_ACCEPT_EAGAIN(e) \ - (ERRNO_IS_EAGAIN(e) || (e) == ECONNABORTED) -#define ERRNO_IS_RESOURCE_LIMIT(e) \ - ((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM) -#define ERRNO_IS_EADDRINUSE(e) (((e) == EADDRINUSE) || 0) -#define tor_socket_errno(sock) (errno) -#define tor_socket_strerror(e) strerror(e) -#endif /* defined(_WIN32) */ - -/** Specified SOCKS5 status codes. */ -typedef enum { - SOCKS5_SUCCEEDED = 0x00, - SOCKS5_GENERAL_ERROR = 0x01, - SOCKS5_NOT_ALLOWED = 0x02, - SOCKS5_NET_UNREACHABLE = 0x03, - SOCKS5_HOST_UNREACHABLE = 0x04, - SOCKS5_CONNECTION_REFUSED = 0x05, - SOCKS5_TTL_EXPIRED = 0x06, - SOCKS5_COMMAND_NOT_SUPPORTED = 0x07, - SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08, -} socks5_reply_status_t; - -/* ===== OS compatibility */ -MOCK_DECL(const char *, get_uname, (void)); - -uint16_t get_uint16(const void *cp) ATTR_NONNULL((1)); -uint32_t get_uint32(const void *cp) ATTR_NONNULL((1)); -uint64_t get_uint64(const void *cp) ATTR_NONNULL((1)); -void set_uint16(void *cp, uint16_t v) ATTR_NONNULL((1)); -void set_uint32(void *cp, uint32_t v) ATTR_NONNULL((1)); -void set_uint64(void *cp, uint64_t v) ATTR_NONNULL((1)); - -/* These uint8 variants are defined to make the code more uniform. */ -#define get_uint8(cp) (*(const uint8_t*)(cp)) -static void set_uint8(void *cp, uint8_t v); -static inline void -set_uint8(void *cp, uint8_t v) -{ - *(uint8_t*)cp = v; -} - -#if !defined(HAVE_RLIM_T) -typedef unsigned long rlim_t; -#endif -int get_max_sockets(void); -int set_max_file_descriptors(rlim_t limit, int *max); -int tor_disable_debugger_attach(void); - -#if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_CAP_SET_PROC) -#define HAVE_LINUX_CAPABILITIES -#endif - -int have_capability_support(void); - -/** Flag for switch_id; see switch_id() for documentation */ -#define SWITCH_ID_KEEP_BINDLOW (1<<0) -/** Flag for switch_id; see switch_id() for documentation */ -#define SWITCH_ID_WARN_IF_NO_CAPS (1<<1) -int switch_id(const char *user, unsigned flags); -#ifdef HAVE_PWD_H -char *get_user_homedir(const char *username); -#endif - -#ifndef _WIN32 -const struct passwd *tor_getpwnam(const char *username); -const struct passwd *tor_getpwuid(uid_t uid); -#endif - -int get_parent_directory(char *fname); -char *make_path_absolute(char *fname); - -char **get_environment(void); - -MOCK_DECL(int, get_total_system_memory, (size_t *mem_out)); - -int compute_num_cpus(void); - -int tor_mlockall(void); - -/** Macros for MIN/MAX. Never use these when the arguments could have - * side-effects. - * {With GCC extensions we could probably define a safer MIN/MAX. But - * depending on that safety would be dangerous, since not every platform - * has it.} - **/ -#ifndef MAX -#define MAX(a,b) ( ((a)<(b)) ? (b) : (a) ) -#endif -#ifndef MIN -#define MIN(a,b) ( ((a)>(b)) ? (b) : (a) ) -#endif - -/* Platform-specific helpers. */ -#ifdef _WIN32 -char *format_win32_error(DWORD err); -#endif - -/*for some reason my compiler doesn't have these version flags defined - a nice homework assignment for someone one day is to define the rest*/ -//these are the values as given on MSDN -#ifdef _WIN32 - -#ifndef VER_SUITE_EMBEDDEDNT -#define VER_SUITE_EMBEDDEDNT 0x00000040 -#endif - -#ifndef VER_SUITE_SINGLEUSERTS -#define VER_SUITE_SINGLEUSERTS 0x00000100 -#endif - -#endif /* defined(_WIN32) */ - -#ifdef COMPAT_PRIVATE -#if !defined(HAVE_SOCKETPAIR) || defined(_WIN32) || defined(TOR_UNIT_TESTS) -#define NEED_ERSATZ_SOCKETPAIR -STATIC int tor_ersatz_socketpair(int family, int type, int protocol, - tor_socket_t fd[2]); -#endif -#endif /* defined(COMPAT_PRIVATE) */ - -ssize_t tor_getpass(const char *prompt, char *output, size_t buflen); - -/* This needs some of the declarations above so we include it here. */ -#include "compat_threads.h" - -#endif /* !defined(TOR_COMPAT_H) */ - diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c index e60eb148d8..9d21cf20bd 100644 --- a/src/common/compat_libevent.c +++ b/src/common/compat_libevent.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2017, The Tor Project, Inc. */ +/* Copyright (c) 2009-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,17 +7,17 @@ */ #include "orconfig.h" -#include "compat.h" #define COMPAT_LIBEVENT_PRIVATE -#include "compat_libevent.h" +#include "common/compat_libevent.h" -#include "crypto_rand.h" - -#include "util.h" -#include "torlog.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/string/compat_string.h" #include <event2/event.h> #include <event2/thread.h> +#include <string.h> /** A string which, if it appears in a libevent log, should be ignored. */ static const char *suppress_msg = NULL; @@ -533,4 +533,3 @@ tor_libevent_postfork(void) tor_assert(r == 0); } #endif /* defined(TOR_UNIT_TESTS) */ - diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h index 286a268122..0a50cfa667 100644 --- a/src/common/compat_libevent.h +++ b/src/common/compat_libevent.h @@ -1,11 +1,12 @@ -/* Copyright (c) 2009-2017, The Tor Project, Inc. */ +/* Copyright (c) 2009-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_COMPAT_LIBEVENT_H #define TOR_COMPAT_LIBEVENT_H #include "orconfig.h" -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" +#include "lib/malloc/util_malloc.h" void configure_libevent_logging(void); void suppress_libevent_log_msg(const char *msg); @@ -19,6 +20,7 @@ void suppress_libevent_log_msg(const char *msg); struct event; struct event_base; +struct timeval; void tor_event_free_(struct event *ev); #define tor_event_free(ev) \ @@ -95,4 +97,3 @@ libevent_logging_callback(int severity, const char *msg); #endif /* defined(COMPAT_LIBEVENT_PRIVATE) */ #endif /* !defined(TOR_COMPAT_LIBEVENT_H) */ - diff --git a/src/common/container.c b/src/common/container.c deleted file mode 100644 index 5386e6458b..0000000000 --- a/src/common/container.c +++ /dev/null @@ -1,1542 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file container.c - * \brief Implements a smartlist (a resizable array) along - * with helper functions to use smartlists. Also includes - * hash table implementations of a string-to-void* map, and of - * a digest-to-void* map. - **/ - -#include "compat.h" -#include "util.h" -#include "torlog.h" -#include "container.h" -#include "crypto_digest.h" - -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -#include "ht.h" - -/** All newly allocated smartlists have this capacity. */ -#define SMARTLIST_DEFAULT_CAPACITY 16 - -/** Allocate and return an empty smartlist. - */ -MOCK_IMPL(smartlist_t *, -smartlist_new,(void)) -{ - smartlist_t *sl = tor_malloc(sizeof(smartlist_t)); - sl->num_used = 0; - sl->capacity = SMARTLIST_DEFAULT_CAPACITY; - sl->list = tor_calloc(sizeof(void *), sl->capacity); - return sl; -} - -/** Deallocate a smartlist. Does not release storage associated with the - * list's elements. - */ -MOCK_IMPL(void, -smartlist_free_,(smartlist_t *sl)) -{ - if (!sl) - return; - tor_free(sl->list); - tor_free(sl); -} - -/** Remove all elements from the list. - */ -void -smartlist_clear(smartlist_t *sl) -{ - memset(sl->list, 0, sizeof(void *) * sl->num_used); - sl->num_used = 0; -} - -#if SIZE_MAX < INT_MAX -#error "We don't support systems where size_t is smaller than int." -#endif - -/** Make sure that <b>sl</b> can hold at least <b>size</b> entries. */ -static inline void -smartlist_ensure_capacity(smartlist_t *sl, size_t size) -{ - /* Set MAX_CAPACITY to MIN(INT_MAX, SIZE_MAX / sizeof(void*)) */ -#if (SIZE_MAX/SIZEOF_VOID_P) > INT_MAX -#define MAX_CAPACITY (INT_MAX) -#else -#define MAX_CAPACITY (int)((SIZE_MAX / (sizeof(void*)))) -#endif - - tor_assert(size <= MAX_CAPACITY); - - if (size > (size_t) sl->capacity) { - size_t higher = (size_t) sl->capacity; - if (PREDICT_UNLIKELY(size > MAX_CAPACITY/2)) { - higher = MAX_CAPACITY; - } else { - while (size > higher) - higher *= 2; - } - sl->list = tor_reallocarray(sl->list, sizeof(void *), - ((size_t)higher)); - memset(sl->list + sl->capacity, 0, - sizeof(void *) * (higher - sl->capacity)); - sl->capacity = (int) higher; - } -#undef ASSERT_CAPACITY -#undef MAX_CAPACITY -} - -/** Append element to the end of the list. */ -void -smartlist_add(smartlist_t *sl, void *element) -{ - smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1); - sl->list[sl->num_used++] = element; -} - -/** Append each element from S2 to the end of S1. */ -void -smartlist_add_all(smartlist_t *s1, const smartlist_t *s2) -{ - size_t new_size = (size_t)s1->num_used + (size_t)s2->num_used; - tor_assert(new_size >= (size_t) s1->num_used); /* check for overflow. */ - smartlist_ensure_capacity(s1, new_size); - memcpy(s1->list + s1->num_used, s2->list, s2->num_used*sizeof(void*)); - tor_assert(new_size <= INT_MAX); /* redundant. */ - s1->num_used = (int) new_size; -} - -/** Remove all elements E from sl such that E==element. Preserve - * the order of any elements before E, but elements after E can be - * rearranged. - */ -void -smartlist_remove(smartlist_t *sl, const void *element) -{ - int i; - if (element == NULL) - return; - for (i=0; i < sl->num_used; i++) - if (sl->list[i] == element) { - sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ - i--; /* so we process the new i'th element */ - sl->list[sl->num_used] = NULL; - } -} - -/** As <b>smartlist_remove</b>, but do not change the order of - * any elements not removed */ -void -smartlist_remove_keeporder(smartlist_t *sl, const void *element) -{ - int i, j, num_used_orig = sl->num_used; - if (element == NULL) - return; - - for (i=j=0; j < num_used_orig; ++j) { - if (sl->list[j] == element) { - --sl->num_used; - } else { - sl->list[i++] = sl->list[j]; - } - } -} - -/** If <b>sl</b> is nonempty, remove and return the final element. Otherwise, - * return NULL. */ -void * -smartlist_pop_last(smartlist_t *sl) -{ - tor_assert(sl); - if (sl->num_used) { - void *tmp = sl->list[--sl->num_used]; - sl->list[sl->num_used] = NULL; - return tmp; - } else - return NULL; -} - -/** Reverse the order of the items in <b>sl</b>. */ -void -smartlist_reverse(smartlist_t *sl) -{ - int i, j; - void *tmp; - tor_assert(sl); - for (i = 0, j = sl->num_used-1; i < j; ++i, --j) { - tmp = sl->list[i]; - sl->list[i] = sl->list[j]; - sl->list[j] = tmp; - } -} - -/** If there are any strings in sl equal to element, remove and free them. - * Does not preserve order. */ -void -smartlist_string_remove(smartlist_t *sl, const char *element) -{ - int i; - tor_assert(sl); - tor_assert(element); - for (i = 0; i < sl->num_used; ++i) { - if (!strcmp(element, sl->list[i])) { - tor_free(sl->list[i]); - sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ - i--; /* so we process the new i'th element */ - sl->list[sl->num_used] = NULL; - } - } -} - -/** Return true iff some element E of sl has E==element. - */ -int -smartlist_contains(const smartlist_t *sl, const void *element) -{ - int i; - for (i=0; i < sl->num_used; i++) - if (sl->list[i] == element) - return 1; - return 0; -} - -/** Return true iff <b>sl</b> has some element E such that - * !strcmp(E,<b>element</b>) - */ -int -smartlist_contains_string(const smartlist_t *sl, const char *element) -{ - int i; - if (!sl) return 0; - for (i=0; i < sl->num_used; i++) - if (strcmp((const char*)sl->list[i],element)==0) - return 1; - return 0; -} - -/** If <b>element</b> is equal to an element of <b>sl</b>, return that - * element's index. Otherwise, return -1. */ -int -smartlist_string_pos(const smartlist_t *sl, const char *element) -{ - int i; - if (!sl) return -1; - for (i=0; i < sl->num_used; i++) - if (strcmp((const char*)sl->list[i],element)==0) - return i; - return -1; -} - -/** If <b>element</b> is the same pointer as an element of <b>sl</b>, return - * that element's index. Otherwise, return -1. */ -int -smartlist_pos(const smartlist_t *sl, const void *element) -{ - int i; - if (!sl) return -1; - for (i=0; i < sl->num_used; i++) - if (element == sl->list[i]) - return i; - return -1; -} - -/** Return true iff <b>sl</b> has some element E such that - * !strcasecmp(E,<b>element</b>) - */ -int -smartlist_contains_string_case(const smartlist_t *sl, const char *element) -{ - int i; - if (!sl) return 0; - for (i=0; i < sl->num_used; i++) - if (strcasecmp((const char*)sl->list[i],element)==0) - return 1; - return 0; -} - -/** Return true iff <b>sl</b> has some element E such that E is equal - * to the decimal encoding of <b>num</b>. - */ -int -smartlist_contains_int_as_string(const smartlist_t *sl, int num) -{ - char buf[32]; /* long enough for 64-bit int, and then some. */ - tor_snprintf(buf,sizeof(buf),"%d", num); - return smartlist_contains_string(sl, buf); -} - -/** Return true iff the two lists contain the same strings in the same - * order, or if they are both NULL. */ -int -smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2) -{ - if (sl1 == NULL) - return sl2 == NULL; - if (sl2 == NULL) - return 0; - if (smartlist_len(sl1) != smartlist_len(sl2)) - return 0; - SMARTLIST_FOREACH(sl1, const char *, cp1, { - const char *cp2 = smartlist_get(sl2, cp1_sl_idx); - if (strcmp(cp1, cp2)) - return 0; - }); - return 1; -} - -/** Return true iff the two lists contain the same int pointer values in - * the same order, or if they are both NULL. */ -int -smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2) -{ - if (sl1 == NULL) - return sl2 == NULL; - if (sl2 == NULL) - return 0; - if (smartlist_len(sl1) != smartlist_len(sl2)) - return 0; - SMARTLIST_FOREACH(sl1, int *, cp1, { - int *cp2 = smartlist_get(sl2, cp1_sl_idx); - if (*cp1 != *cp2) - return 0; - }); - return 1; -} - -/** Return true iff <b>sl</b> has some element E such that - * tor_memeq(E,<b>element</b>,DIGEST_LEN) - */ -int -smartlist_contains_digest(const smartlist_t *sl, const char *element) -{ - int i; - if (!sl) return 0; - for (i=0; i < sl->num_used; i++) - if (tor_memeq((const char*)sl->list[i],element,DIGEST_LEN)) - return 1; - return 0; -} - -/** Return true iff some element E of sl2 has smartlist_contains(sl1,E). - */ -int -smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2) -{ - int i; - for (i=0; i < sl2->num_used; i++) - if (smartlist_contains(sl1, sl2->list[i])) - return 1; - return 0; -} - -/** Remove every element E of sl1 such that !smartlist_contains(sl2,E). - * Does not preserve the order of sl1. - */ -void -smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2) -{ - int i; - for (i=0; i < sl1->num_used; i++) - if (!smartlist_contains(sl2, sl1->list[i])) { - sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */ - i--; /* so we process the new i'th element */ - sl1->list[sl1->num_used] = NULL; - } -} - -/** Remove every element E of sl1 such that smartlist_contains(sl2,E). - * Does not preserve the order of sl1. - */ -void -smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2) -{ - int i; - for (i=0; i < sl2->num_used; i++) - smartlist_remove(sl1, sl2->list[i]); -} - -/** Remove the <b>idx</b>th element of sl; if idx is not the last - * element, swap the last element of sl into the <b>idx</b>th space. - */ -void -smartlist_del(smartlist_t *sl, int idx) -{ - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(idx < sl->num_used); - sl->list[idx] = sl->list[--sl->num_used]; - sl->list[sl->num_used] = NULL; -} - -/** Remove the <b>idx</b>th element of sl; if idx is not the last element, - * moving all subsequent elements back one space. Return the old value - * of the <b>idx</b>th element. - */ -void -smartlist_del_keeporder(smartlist_t *sl, int idx) -{ - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(idx < sl->num_used); - --sl->num_used; - if (idx < sl->num_used) - memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx)); - sl->list[sl->num_used] = NULL; -} - -/** Insert the value <b>val</b> as the new <b>idx</b>th element of - * <b>sl</b>, moving all items previously at <b>idx</b> or later - * forward one space. - */ -void -smartlist_insert(smartlist_t *sl, int idx, void *val) -{ - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(idx <= sl->num_used); - if (idx == sl->num_used) { - smartlist_add(sl, val); - } else { - smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1); - /* Move other elements away */ - if (idx < sl->num_used) - memmove(sl->list + idx + 1, sl->list + idx, - sizeof(void*)*(sl->num_used-idx)); - sl->num_used++; - sl->list[idx] = val; - } -} - -/** - * Split a string <b>str</b> along all occurrences of <b>sep</b>, - * appending the (newly allocated) split strings, in order, to - * <b>sl</b>. Return the number of strings added to <b>sl</b>. - * - * If <b>flags</b>&SPLIT_SKIP_SPACE is true, remove initial and - * trailing space from each entry. - * If <b>flags</b>&SPLIT_IGNORE_BLANK is true, remove any entries - * of length 0. - * If <b>flags</b>&SPLIT_STRIP_SPACE is true, strip spaces from each - * split string. - * - * If <b>max</b>\>0, divide the string into no more than <b>max</b> pieces. If - * <b>sep</b> is NULL, split on any sequence of horizontal space. - */ -int -smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, - int flags, int max) -{ - const char *cp, *end, *next; - int n = 0; - - tor_assert(sl); - tor_assert(str); - - cp = str; - while (1) { - if (flags&SPLIT_SKIP_SPACE) { - while (TOR_ISSPACE(*cp)) ++cp; - } - - if (max>0 && n == max-1) { - end = strchr(cp,'\0'); - } else if (sep) { - end = strstr(cp,sep); - if (!end) - end = strchr(cp,'\0'); - } else { - for (end = cp; *end && *end != '\t' && *end != ' '; ++end) - ; - } - - tor_assert(end); - - if (!*end) { - next = NULL; - } else if (sep) { - next = end+strlen(sep); - } else { - next = end+1; - while (*next == '\t' || *next == ' ') - ++next; - } - - if (flags&SPLIT_SKIP_SPACE) { - while (end > cp && TOR_ISSPACE(*(end-1))) - --end; - } - if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) { - char *string = tor_strndup(cp, end-cp); - if (flags&SPLIT_STRIP_SPACE) - tor_strstrip(string, " "); - smartlist_add(sl, string); - ++n; - } - if (!next) - break; - cp = next; - } - - return n; -} - -/** Allocate and return a new string containing the concatenation of - * the elements of <b>sl</b>, in order, separated by <b>join</b>. If - * <b>terminate</b> is true, also terminate the string with <b>join</b>. - * If <b>len_out</b> is not NULL, set <b>len_out</b> to the length of - * the returned string. Requires that every element of <b>sl</b> is - * NUL-terminated string. - */ -char * -smartlist_join_strings(smartlist_t *sl, const char *join, - int terminate, size_t *len_out) -{ - return smartlist_join_strings2(sl,join,strlen(join),terminate,len_out); -} - -/** As smartlist_join_strings, but instead of separating/terminated with a - * NUL-terminated string <b>join</b>, uses the <b>join_len</b>-byte sequence - * at <b>join</b>. (Useful for generating a sequence of NUL-terminated - * strings.) - */ -char * -smartlist_join_strings2(smartlist_t *sl, const char *join, - size_t join_len, int terminate, size_t *len_out) -{ - int i; - size_t n = 0; - char *r = NULL, *dst, *src; - - tor_assert(sl); - tor_assert(join); - - if (terminate) - n = join_len; - - for (i = 0; i < sl->num_used; ++i) { - n += strlen(sl->list[i]); - if (i+1 < sl->num_used) /* avoid double-counting the last one */ - n += join_len; - } - dst = r = tor_malloc(n+1); - for (i = 0; i < sl->num_used; ) { - for (src = sl->list[i]; *src; ) - *dst++ = *src++; - if (++i < sl->num_used) { - memcpy(dst, join, join_len); - dst += join_len; - } - } - if (terminate) { - memcpy(dst, join, join_len); - dst += join_len; - } - *dst = '\0'; - - if (len_out) - *len_out = dst-r; - return r; -} - -/** Sort the members of <b>sl</b> into an order defined by - * the ordering function <b>compare</b>, which returns less then 0 if a - * precedes b, greater than 0 if b precedes a, and 0 if a 'equals' b. - */ -void -smartlist_sort(smartlist_t *sl, int (*compare)(const void **a, const void **b)) -{ - if (!sl->num_used) - return; - qsort(sl->list, sl->num_used, sizeof(void*), - (int (*)(const void *,const void*))compare); -} - -/** Given a smartlist <b>sl</b> sorted with the function <b>compare</b>, - * return the most frequent member in the list. Break ties in favor of - * later elements. If the list is empty, return NULL. If count_out is - * non-null, set it to the count of the most frequent member. - */ -void * -smartlist_get_most_frequent_(const smartlist_t *sl, - int (*compare)(const void **a, const void **b), - int *count_out) -{ - const void *most_frequent = NULL; - int most_frequent_count = 0; - - const void *cur = NULL; - int i, count=0; - - if (!sl->num_used) { - if (count_out) - *count_out = 0; - return NULL; - } - for (i = 0; i < sl->num_used; ++i) { - const void *item = sl->list[i]; - if (cur && 0 == compare(&cur, &item)) { - ++count; - } else { - if (cur && count >= most_frequent_count) { - most_frequent = cur; - most_frequent_count = count; - } - cur = item; - count = 1; - } - } - if (cur && count >= most_frequent_count) { - most_frequent = cur; - most_frequent_count = count; - } - if (count_out) - *count_out = most_frequent_count; - return (void*)most_frequent; -} - -/** Given a sorted smartlist <b>sl</b> and the comparison function used to - * sort it, remove all duplicate members. If free_fn is provided, calls - * free_fn on each duplicate. Otherwise, just removes them. Preserves order. - */ -void -smartlist_uniq(smartlist_t *sl, - int (*compare)(const void **a, const void **b), - void (*free_fn)(void *a)) -{ - int i; - for (i=1; i < sl->num_used; ++i) { - if (compare((const void **)&(sl->list[i-1]), - (const void **)&(sl->list[i])) == 0) { - if (free_fn) - free_fn(sl->list[i]); - smartlist_del_keeporder(sl, i--); - } - } -} - -/** Assuming the members of <b>sl</b> are in order, return a pointer to the - * member that matches <b>key</b>. Ordering and matching are defined by a - * <b>compare</b> function that returns 0 on a match; less than 0 if key is - * less than member, and greater than 0 if key is greater then member. - */ -void * -smartlist_bsearch(smartlist_t *sl, const void *key, - int (*compare)(const void *key, const void **member)) -{ - int found, idx; - idx = smartlist_bsearch_idx(sl, key, compare, &found); - return found ? smartlist_get(sl, idx) : NULL; -} - -/** Assuming the members of <b>sl</b> are in order, return the index of the - * member that matches <b>key</b>. If no member matches, return the index of - * the first member greater than <b>key</b>, or smartlist_len(sl) if no member - * is greater than <b>key</b>. Set <b>found_out</b> to true on a match, to - * false otherwise. Ordering and matching are defined by a <b>compare</b> - * function that returns 0 on a match; less than 0 if key is less than member, - * and greater than 0 if key is greater then member. - */ -int -smartlist_bsearch_idx(const smartlist_t *sl, const void *key, - int (*compare)(const void *key, const void **member), - int *found_out) -{ - int hi, lo, cmp, mid, len, diff; - - tor_assert(sl); - tor_assert(compare); - tor_assert(found_out); - - len = smartlist_len(sl); - - /* Check for the trivial case of a zero-length list */ - if (len == 0) { - *found_out = 0; - /* We already know smartlist_len(sl) is 0 in this case */ - return 0; - } - - /* Okay, we have a real search to do */ - tor_assert(len > 0); - lo = 0; - hi = len - 1; - - /* - * These invariants are always true: - * - * For all i such that 0 <= i < lo, sl[i] < key - * For all i such that hi < i <= len, sl[i] > key - */ - - while (lo <= hi) { - diff = hi - lo; - /* - * We want mid = (lo + hi) / 2, but that could lead to overflow, so - * instead diff = hi - lo (non-negative because of loop condition), and - * then hi = lo + diff, mid = (lo + lo + diff) / 2 = lo + (diff / 2). - */ - mid = lo + (diff / 2); - cmp = compare(key, (const void**) &(sl->list[mid])); - if (cmp == 0) { - /* sl[mid] == key; we found it */ - *found_out = 1; - return mid; - } else if (cmp > 0) { - /* - * key > sl[mid] and an index i such that sl[i] == key must - * have i > mid if it exists. - */ - - /* - * Since lo <= mid <= hi, hi can only decrease on each iteration (by - * being set to mid - 1) and hi is initially len - 1, mid < len should - * always hold, and this is not symmetric with the left end of list - * mid > 0 test below. A key greater than the right end of the list - * should eventually lead to lo == hi == mid == len - 1, and then - * we set lo to len below and fall out to the same exit we hit for - * a key in the middle of the list but not matching. Thus, we just - * assert for consistency here rather than handle a mid == len case. - */ - tor_assert(mid < len); - /* Move lo to the element immediately after sl[mid] */ - lo = mid + 1; - } else { - /* This should always be true in this case */ - tor_assert(cmp < 0); - - /* - * key < sl[mid] and an index i such that sl[i] == key must - * have i < mid if it exists. - */ - - if (mid > 0) { - /* Normal case, move hi to the element immediately before sl[mid] */ - hi = mid - 1; - } else { - /* These should always be true in this case */ - tor_assert(mid == lo); - tor_assert(mid == 0); - /* - * We were at the beginning of the list and concluded that every - * element e compares e > key. - */ - *found_out = 0; - return 0; - } - } - } - - /* - * lo > hi; we have no element matching key but we have elements falling - * on both sides of it. The lo index points to the first element > key. - */ - tor_assert(lo == hi + 1); /* All other cases should have been handled */ - tor_assert(lo >= 0); - tor_assert(lo <= len); - tor_assert(hi >= 0); - tor_assert(hi <= len); - - if (lo < len) { - cmp = compare(key, (const void **) &(sl->list[lo])); - tor_assert(cmp < 0); - } else { - cmp = compare(key, (const void **) &(sl->list[len-1])); - tor_assert(cmp > 0); - } - - *found_out = 0; - return lo; -} - -/** Helper: compare two const char **s. */ -static int -compare_string_ptrs_(const void **_a, const void **_b) -{ - return strcmp((const char*)*_a, (const char*)*_b); -} - -/** Sort a smartlist <b>sl</b> containing strings into lexically ascending - * order. */ -void -smartlist_sort_strings(smartlist_t *sl) -{ - smartlist_sort(sl, compare_string_ptrs_); -} - -/** Return the most frequent string in the sorted list <b>sl</b> */ -const char * -smartlist_get_most_frequent_string(smartlist_t *sl) -{ - return smartlist_get_most_frequent(sl, compare_string_ptrs_); -} - -/** Return the most frequent string in the sorted list <b>sl</b>. - * If <b>count_out</b> is provided, set <b>count_out</b> to the - * number of times that string appears. - */ -const char * -smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out) -{ - return smartlist_get_most_frequent_(sl, compare_string_ptrs_, count_out); -} - -/** Remove duplicate strings from a sorted list, and free them with tor_free(). - */ -void -smartlist_uniq_strings(smartlist_t *sl) -{ - smartlist_uniq(sl, compare_string_ptrs_, tor_free_); -} - -/** Helper: compare two pointers. */ -static int -compare_ptrs_(const void **_a, const void **_b) -{ - const void *a = *_a, *b = *_b; - if (a<b) - return -1; - else if (a==b) - return 0; - else - return 1; -} - -/** Sort <b>sl</b> in ascending order of the pointers it contains. */ -void -smartlist_sort_pointers(smartlist_t *sl) -{ - smartlist_sort(sl, compare_ptrs_); -} - -/* Heap-based priority queue implementation for O(lg N) insert and remove. - * Recall that the heap property is that, for every index I, h[I] < - * H[LEFT_CHILD[I]] and h[I] < H[RIGHT_CHILD[I]]. - * - * For us to remove items other than the topmost item, each item must store - * its own index within the heap. When calling the pqueue functions, tell - * them about the offset of the field that stores the index within the item. - * - * Example: - * - * typedef struct timer_t { - * struct timeval tv; - * int heap_index; - * } timer_t; - * - * static int compare(const void *p1, const void *p2) { - * const timer_t *t1 = p1, *t2 = p2; - * if (t1->tv.tv_sec < t2->tv.tv_sec) { - * return -1; - * } else if (t1->tv.tv_sec > t2->tv.tv_sec) { - * return 1; - * } else { - * return t1->tv.tv_usec - t2->tv_usec; - * } - * } - * - * void timer_heap_insert(smartlist_t *heap, timer_t *timer) { - * smartlist_pqueue_add(heap, compare, offsetof(timer_t, heap_index), - * timer); - * } - * - * void timer_heap_pop(smartlist_t *heap) { - * return smartlist_pqueue_pop(heap, compare, - * offsetof(timer_t, heap_index)); - * } - */ - -/** @{ */ -/** Functions to manipulate heap indices to find a node's parent and children. - * - * For a 1-indexed array, we would use LEFT_CHILD[x] = 2*x and RIGHT_CHILD[x] - * = 2*x + 1. But this is C, so we have to adjust a little. */ - -/* MAX_PARENT_IDX is the largest IDX in the smartlist which might have - * children whose indices fit inside an int. - * LEFT_CHILD(MAX_PARENT_IDX) == INT_MAX-2; - * RIGHT_CHILD(MAX_PARENT_IDX) == INT_MAX-1; - * LEFT_CHILD(MAX_PARENT_IDX + 1) == INT_MAX // impossible, see max list size. - */ -#define MAX_PARENT_IDX ((INT_MAX - 2) / 2) -/* If this is true, then i is small enough to potentially have children - * in the smartlist, and it is save to use LEFT_CHILD/RIGHT_CHILD on it. */ -#define IDX_MAY_HAVE_CHILDREN(i) ((i) <= MAX_PARENT_IDX) -#define LEFT_CHILD(i) ( 2*(i) + 1 ) -#define RIGHT_CHILD(i) ( 2*(i) + 2 ) -#define PARENT(i) ( ((i)-1) / 2 ) -/** }@ */ - -/** @{ */ -/** Helper macros for heaps: Given a local variable <b>idx_field_offset</b> - * set to the offset of an integer index within the heap element structure, - * IDX_OF_ITEM(p) gives you the index of p, and IDXP(p) gives you a pointer to - * where p's index is stored. Given additionally a local smartlist <b>sl</b>, - * UPDATE_IDX(i) sets the index of the element at <b>i</b> to the correct - * value (that is, to <b>i</b>). - */ -#define IDXP(p) ((int*)STRUCT_VAR_P(p, idx_field_offset)) - -#define UPDATE_IDX(i) do { \ - void *updated = sl->list[i]; \ - *IDXP(updated) = i; \ - } while (0) - -#define IDX_OF_ITEM(p) (*IDXP(p)) -/** @} */ - -/** Helper. <b>sl</b> may have at most one violation of the heap property: - * the item at <b>idx</b> may be greater than one or both of its children. - * Restore the heap property. */ -static inline void -smartlist_heapify(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - int idx) -{ - while (1) { - if (! IDX_MAY_HAVE_CHILDREN(idx)) { - /* idx is so large that it cannot have any children, since doing so - * would mean the smartlist was over-capacity. Therefore it cannot - * violate the heap property by being greater than a child (since it - * doesn't have any). */ - return; - } - - int left_idx = LEFT_CHILD(idx); - int best_idx; - - if (left_idx >= sl->num_used) - return; - if (compare(sl->list[idx],sl->list[left_idx]) < 0) - best_idx = idx; - else - best_idx = left_idx; - if (left_idx+1 < sl->num_used && - compare(sl->list[left_idx+1],sl->list[best_idx]) < 0) - best_idx = left_idx + 1; - - if (best_idx == idx) { - return; - } else { - void *tmp = sl->list[idx]; - sl->list[idx] = sl->list[best_idx]; - sl->list[best_idx] = tmp; - UPDATE_IDX(idx); - UPDATE_IDX(best_idx); - - idx = best_idx; - } - } -} - -/** Insert <b>item</b> into the heap stored in <b>sl</b>, where order is - * determined by <b>compare</b> and the offset of the item in the heap is - * stored in an int-typed field at position <b>idx_field_offset</b> within - * item. - */ -void -smartlist_pqueue_add(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - void *item) -{ - int idx; - smartlist_add(sl,item); - UPDATE_IDX(sl->num_used-1); - - for (idx = sl->num_used - 1; idx; ) { - int parent = PARENT(idx); - if (compare(sl->list[idx], sl->list[parent]) < 0) { - void *tmp = sl->list[parent]; - sl->list[parent] = sl->list[idx]; - sl->list[idx] = tmp; - UPDATE_IDX(parent); - UPDATE_IDX(idx); - idx = parent; - } else { - return; - } - } -} - -/** Remove and return the top-priority item from the heap stored in <b>sl</b>, - * where order is determined by <b>compare</b> and the item's position is - * stored at position <b>idx_field_offset</b> within the item. <b>sl</b> must - * not be empty. */ -void * -smartlist_pqueue_pop(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset) -{ - void *top; - tor_assert(sl->num_used); - - top = sl->list[0]; - *IDXP(top)=-1; - if (--sl->num_used) { - sl->list[0] = sl->list[sl->num_used]; - sl->list[sl->num_used] = NULL; - UPDATE_IDX(0); - smartlist_heapify(sl, compare, idx_field_offset, 0); - } - sl->list[sl->num_used] = NULL; - return top; -} - -/** Remove the item <b>item</b> from the heap stored in <b>sl</b>, - * where order is determined by <b>compare</b> and the item's position is - * stored at position <b>idx_field_offset</b> within the item. <b>sl</b> must - * not be empty. */ -void -smartlist_pqueue_remove(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - void *item) -{ - int idx = IDX_OF_ITEM(item); - tor_assert(idx >= 0); - tor_assert(sl->list[idx] == item); - --sl->num_used; - *IDXP(item) = -1; - if (idx == sl->num_used) { - sl->list[sl->num_used] = NULL; - return; - } else { - sl->list[idx] = sl->list[sl->num_used]; - sl->list[sl->num_used] = NULL; - UPDATE_IDX(idx); - smartlist_heapify(sl, compare, idx_field_offset, idx); - } -} - -/** Assert that the heap property is correctly maintained by the heap stored - * in <b>sl</b>, where order is determined by <b>compare</b>. */ -void -smartlist_pqueue_assert_ok(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset) -{ - int i; - for (i = sl->num_used - 1; i >= 0; --i) { - if (i>0) - tor_assert(compare(sl->list[PARENT(i)], sl->list[i]) <= 0); - tor_assert(IDX_OF_ITEM(sl->list[i]) == i); - } -} - -/** Helper: compare two DIGEST_LEN digests. */ -static int -compare_digests_(const void **_a, const void **_b) -{ - return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST_LEN); -} - -/** Sort the list of DIGEST_LEN-byte digests into ascending order. */ -void -smartlist_sort_digests(smartlist_t *sl) -{ - smartlist_sort(sl, compare_digests_); -} - -/** Remove duplicate digests from a sorted list, and free them with tor_free(). - */ -void -smartlist_uniq_digests(smartlist_t *sl) -{ - smartlist_uniq(sl, compare_digests_, tor_free_); -} - -/** Helper: compare two DIGEST256_LEN digests. */ -static int -compare_digests256_(const void **_a, const void **_b) -{ - return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST256_LEN); -} - -/** Sort the list of DIGEST256_LEN-byte digests into ascending order. */ -void -smartlist_sort_digests256(smartlist_t *sl) -{ - smartlist_sort(sl, compare_digests256_); -} - -/** Return the most frequent member of the sorted list of DIGEST256_LEN - * digests in <b>sl</b> */ -const uint8_t * -smartlist_get_most_frequent_digest256(smartlist_t *sl) -{ - return smartlist_get_most_frequent(sl, compare_digests256_); -} - -/** Remove duplicate 256-bit digests from a sorted list, and free them with - * tor_free(). - */ -void -smartlist_uniq_digests256(smartlist_t *sl) -{ - smartlist_uniq(sl, compare_digests256_, tor_free_); -} - -/** Helper: Declare an entry type and a map type to implement a mapping using - * ht.h. The map type will be called <b>maptype</b>. The key part of each - * entry is declared using the C declaration <b>keydecl</b>. All functions - * and types associated with the map get prefixed with <b>prefix</b> */ -#define DEFINE_MAP_STRUCTS(maptype, keydecl, prefix) \ - typedef struct prefix ## entry_t { \ - HT_ENTRY(prefix ## entry_t) node; \ - void *val; \ - keydecl; \ - } prefix ## entry_t; \ - struct maptype { \ - HT_HEAD(prefix ## impl, prefix ## entry_t) head; \ - } - -DEFINE_MAP_STRUCTS(strmap_t, char *key, strmap_); -DEFINE_MAP_STRUCTS(digestmap_t, char key[DIGEST_LEN], digestmap_); -DEFINE_MAP_STRUCTS(digest256map_t, uint8_t key[DIGEST256_LEN], digest256map_); - -/** Helper: compare strmap_entry_t objects by key value. */ -static inline int -strmap_entries_eq(const strmap_entry_t *a, const strmap_entry_t *b) -{ - return !strcmp(a->key, b->key); -} - -/** Helper: return a hash value for a strmap_entry_t. */ -static inline unsigned int -strmap_entry_hash(const strmap_entry_t *a) -{ - return (unsigned) siphash24g(a->key, strlen(a->key)); -} - -/** Helper: compare digestmap_entry_t objects by key value. */ -static inline int -digestmap_entries_eq(const digestmap_entry_t *a, const digestmap_entry_t *b) -{ - return tor_memeq(a->key, b->key, DIGEST_LEN); -} - -/** Helper: return a hash value for a digest_map_t. */ -static inline unsigned int -digestmap_entry_hash(const digestmap_entry_t *a) -{ - return (unsigned) siphash24g(a->key, DIGEST_LEN); -} - -/** Helper: compare digestmap_entry_t objects by key value. */ -static inline int -digest256map_entries_eq(const digest256map_entry_t *a, - const digest256map_entry_t *b) -{ - return tor_memeq(a->key, b->key, DIGEST256_LEN); -} - -/** Helper: return a hash value for a digest_map_t. */ -static inline unsigned int -digest256map_entry_hash(const digest256map_entry_t *a) -{ - return (unsigned) siphash24g(a->key, DIGEST256_LEN); -} - -HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash, - strmap_entries_eq) -HT_GENERATE2(strmap_impl, strmap_entry_t, node, strmap_entry_hash, - strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_) - -HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, - digestmap_entries_eq) -HT_GENERATE2(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, - digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_) - -HT_PROTOTYPE(digest256map_impl, digest256map_entry_t, node, - digest256map_entry_hash, - digest256map_entries_eq) -HT_GENERATE2(digest256map_impl, digest256map_entry_t, node, - digest256map_entry_hash, - digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_) - -#define strmap_entry_free(ent) \ - FREE_AND_NULL(strmap_entry_t, strmap_entry_free_, (ent)) -#define digestmap_entry_free(ent) \ - FREE_AND_NULL(digestmap_entry_t, digestmap_entry_free_, (ent)) -#define digest256map_entry_free(ent) \ - FREE_AND_NULL(digest256map_entry_t, digest256map_entry_free_, (ent)) - -static inline void -strmap_entry_free_(strmap_entry_t *ent) -{ - tor_free(ent->key); - tor_free(ent); -} -static inline void -digestmap_entry_free_(digestmap_entry_t *ent) -{ - tor_free(ent); -} -static inline void -digest256map_entry_free_(digest256map_entry_t *ent) -{ - tor_free(ent); -} - -static inline void -strmap_assign_tmp_key(strmap_entry_t *ent, const char *key) -{ - ent->key = (char*)key; -} -static inline void -digestmap_assign_tmp_key(digestmap_entry_t *ent, const char *key) -{ - memcpy(ent->key, key, DIGEST_LEN); -} -static inline void -digest256map_assign_tmp_key(digest256map_entry_t *ent, const uint8_t *key) -{ - memcpy(ent->key, key, DIGEST256_LEN); -} -static inline void -strmap_assign_key(strmap_entry_t *ent, const char *key) -{ - ent->key = tor_strdup(key); -} -static inline void -digestmap_assign_key(digestmap_entry_t *ent, const char *key) -{ - memcpy(ent->key, key, DIGEST_LEN); -} -static inline void -digest256map_assign_key(digest256map_entry_t *ent, const uint8_t *key) -{ - memcpy(ent->key, key, DIGEST256_LEN); -} - -/** - * Macro: implement all the functions for a map that are declared in - * container.h by the DECLARE_MAP_FNS() macro. You must additionally define a - * prefix_entry_free_() function to free entries (and their keys), a - * prefix_assign_tmp_key() function to temporarily set a stack-allocated - * entry to hold a key, and a prefix_assign_key() function to set a - * heap-allocated entry to hold a key. - */ -#define IMPLEMENT_MAP_FNS(maptype, keytype, prefix) \ - /** Create and return a new empty map. */ \ - MOCK_IMPL(maptype *, \ - prefix##_new,(void)) \ - { \ - maptype *result; \ - result = tor_malloc(sizeof(maptype)); \ - HT_INIT(prefix##_impl, &result->head); \ - return result; \ - } \ - \ - /** Return the item from <b>map</b> whose key matches <b>key</b>, or \ - * NULL if no such value exists. */ \ - void * \ - prefix##_get(const maptype *map, const keytype key) \ - { \ - prefix ##_entry_t *resolve; \ - prefix ##_entry_t search; \ - tor_assert(map); \ - tor_assert(key); \ - prefix ##_assign_tmp_key(&search, key); \ - resolve = HT_FIND(prefix ##_impl, &map->head, &search); \ - if (resolve) { \ - return resolve->val; \ - } else { \ - return NULL; \ - } \ - } \ - \ - /** Add an entry to <b>map</b> mapping <b>key</b> to <b>val</b>; \ - * return the previous value, or NULL if no such value existed. */ \ - void * \ - prefix##_set(maptype *map, const keytype key, void *val) \ - { \ - prefix##_entry_t search; \ - void *oldval; \ - tor_assert(map); \ - tor_assert(key); \ - tor_assert(val); \ - prefix##_assign_tmp_key(&search, key); \ - /* We a lot of our time in this function, so the code below is */ \ - /* meant to optimize the check/alloc/set cycle by avoiding the two */\ - /* trips to the hash table that we would do in the unoptimized */ \ - /* version of this code. (Each of HT_INSERT and HT_FIND calls */ \ - /* HT_SET_HASH and HT_FIND_P.) */ \ - HT_FIND_OR_INSERT_(prefix##_impl, node, prefix##_entry_hash, \ - &(map->head), \ - prefix##_entry_t, &search, ptr, \ - { \ - /* we found an entry. */ \ - oldval = (*ptr)->val; \ - (*ptr)->val = val; \ - return oldval; \ - }, \ - { \ - /* We didn't find the entry. */ \ - prefix##_entry_t *newent = \ - tor_malloc_zero(sizeof(prefix##_entry_t)); \ - prefix##_assign_key(newent, key); \ - newent->val = val; \ - HT_FOI_INSERT_(node, &(map->head), \ - &search, newent, ptr); \ - return NULL; \ - }); \ - } \ - \ - /** Remove the value currently associated with <b>key</b> from the map. \ - * Return the value if one was set, or NULL if there was no entry for \ - * <b>key</b>. \ - * \ - * Note: you must free any storage associated with the returned value. \ - */ \ - void * \ - prefix##_remove(maptype *map, const keytype key) \ - { \ - prefix##_entry_t *resolve; \ - prefix##_entry_t search; \ - void *oldval; \ - tor_assert(map); \ - tor_assert(key); \ - prefix##_assign_tmp_key(&search, key); \ - resolve = HT_REMOVE(prefix##_impl, &map->head, &search); \ - if (resolve) { \ - oldval = resolve->val; \ - prefix##_entry_free(resolve); \ - return oldval; \ - } else { \ - return NULL; \ - } \ - } \ - \ - /** Return the number of elements in <b>map</b>. */ \ - int \ - prefix##_size(const maptype *map) \ - { \ - return HT_SIZE(&map->head); \ - } \ - \ - /** Return true iff <b>map</b> has no entries. */ \ - int \ - prefix##_isempty(const maptype *map) \ - { \ - return HT_EMPTY(&map->head); \ - } \ - \ - /** Assert that <b>map</b> is not corrupt. */ \ - void \ - prefix##_assert_ok(const maptype *map) \ - { \ - tor_assert(!prefix##_impl_HT_REP_IS_BAD_(&map->head)); \ - } \ - \ - /** Remove all entries from <b>map</b>, and deallocate storage for \ - * those entries. If free_val is provided, invoked it every value in \ - * <b>map</b>. */ \ - MOCK_IMPL(void, \ - prefix##_free_, (maptype *map, void (*free_val)(void*))) \ - { \ - prefix##_entry_t **ent, **next, *this; \ - if (!map) \ - return; \ - for (ent = HT_START(prefix##_impl, &map->head); ent != NULL; \ - ent = next) { \ - this = *ent; \ - next = HT_NEXT_RMV(prefix##_impl, &map->head, ent); \ - if (free_val) \ - free_val(this->val); \ - prefix##_entry_free(this); \ - } \ - tor_assert(HT_EMPTY(&map->head)); \ - HT_CLEAR(prefix##_impl, &map->head); \ - tor_free(map); \ - } \ - \ - /** return an <b>iterator</b> pointer to the front of a map. \ - * \ - * Iterator example: \ - * \ - * \code \ - * // uppercase values in "map", removing empty values. \ - * \ - * strmap_iter_t *iter; \ - * const char *key; \ - * void *val; \ - * char *cp; \ - * \ - * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) { \ - * strmap_iter_get(iter, &key, &val); \ - * cp = (char*)val; \ - * if (!*cp) { \ - * iter = strmap_iter_next_rmv(map,iter); \ - * free(val); \ - * } else { \ - * for (;*cp;cp++) *cp = TOR_TOUPPER(*cp); \ - */ \ - prefix##_iter_t * \ - prefix##_iter_init(maptype *map) \ - { \ - tor_assert(map); \ - return HT_START(prefix##_impl, &map->head); \ - } \ - \ - /** Advance <b>iter</b> a single step to the next entry, and return \ - * its new value. */ \ - prefix##_iter_t * \ - prefix##_iter_next(maptype *map, prefix##_iter_t *iter) \ - { \ - tor_assert(map); \ - tor_assert(iter); \ - return HT_NEXT(prefix##_impl, &map->head, iter); \ - } \ - /** Advance <b>iter</b> a single step to the next entry, removing the \ - * current entry, and return its new value. */ \ - prefix##_iter_t * \ - prefix##_iter_next_rmv(maptype *map, prefix##_iter_t *iter) \ - { \ - prefix##_entry_t *rmv; \ - tor_assert(map); \ - tor_assert(iter); \ - tor_assert(*iter); \ - rmv = *iter; \ - iter = HT_NEXT_RMV(prefix##_impl, &map->head, iter); \ - prefix##_entry_free(rmv); \ - return iter; \ - } \ - /** Set *<b>keyp</b> and *<b>valp</b> to the current entry pointed \ - * to by iter. */ \ - void \ - prefix##_iter_get(prefix##_iter_t *iter, const keytype *keyp, \ - void **valp) \ - { \ - tor_assert(iter); \ - tor_assert(*iter); \ - tor_assert(keyp); \ - tor_assert(valp); \ - *keyp = (*iter)->key; \ - *valp = (*iter)->val; \ - } \ - /** Return true iff <b>iter</b> has advanced past the last entry of \ - * <b>map</b>. */ \ - int \ - prefix##_iter_done(prefix##_iter_t *iter) \ - { \ - return iter == NULL; \ - } - -IMPLEMENT_MAP_FNS(strmap_t, char *, strmap) -IMPLEMENT_MAP_FNS(digestmap_t, char *, digestmap) -IMPLEMENT_MAP_FNS(digest256map_t, uint8_t *, digest256map) - -/** Same as strmap_set, but first converts <b>key</b> to lowercase. */ -void * -strmap_set_lc(strmap_t *map, const char *key, void *val) -{ - /* We could be a little faster by using strcasecmp instead, and a separate - * type, but I don't think it matters. */ - void *v; - char *lc_key = tor_strdup(key); - tor_strlower(lc_key); - v = strmap_set(map,lc_key,val); - tor_free(lc_key); - return v; -} - -/** Same as strmap_get, but first converts <b>key</b> to lowercase. */ -void * -strmap_get_lc(const strmap_t *map, const char *key) -{ - void *v; - char *lc_key = tor_strdup(key); - tor_strlower(lc_key); - v = strmap_get(map,lc_key); - tor_free(lc_key); - return v; -} - -/** Same as strmap_remove, but first converts <b>key</b> to lowercase */ -void * -strmap_remove_lc(strmap_t *map, const char *key) -{ - void *v; - char *lc_key = tor_strdup(key); - tor_strlower(lc_key); - v = strmap_remove(map,lc_key); - tor_free(lc_key); - return v; -} - -/** Declare a function called <b>funcname</b> that acts as a find_nth_FOO - * function for an array of type <b>elt_t</b>*. - * - * NOTE: The implementation kind of sucks: It's O(n log n), whereas finding - * the kth element of an n-element list can be done in O(n). Then again, this - * implementation is not in critical path, and it is obviously correct. */ -#define IMPLEMENT_ORDER_FUNC(funcname, elt_t) \ - static int \ - _cmp_ ## elt_t(const void *_a, const void *_b) \ - { \ - const elt_t *a = _a, *b = _b; \ - if (*a<*b) \ - return -1; \ - else if (*a>*b) \ - return 1; \ - else \ - return 0; \ - } \ - elt_t \ - funcname(elt_t *array, int n_elements, int nth) \ - { \ - tor_assert(nth >= 0); \ - tor_assert(nth < n_elements); \ - qsort(array, n_elements, sizeof(elt_t), _cmp_ ##elt_t); \ - return array[nth]; \ - } - -IMPLEMENT_ORDER_FUNC(find_nth_int, int) -IMPLEMENT_ORDER_FUNC(find_nth_time, time_t) -IMPLEMENT_ORDER_FUNC(find_nth_double, double) -IMPLEMENT_ORDER_FUNC(find_nth_uint32, uint32_t) -IMPLEMENT_ORDER_FUNC(find_nth_int32, int32_t) -IMPLEMENT_ORDER_FUNC(find_nth_long, long) - -/** Return a newly allocated digestset_t, optimized to hold a total of - * <b>max_elements</b> digests with a reasonably low false positive weight. */ -digestset_t * -digestset_new(int max_elements) -{ - /* The probability of false positives is about P=(1 - exp(-kn/m))^k, where k - * is the number of hash functions per entry, m is the bits in the array, - * and n is the number of elements inserted. For us, k==4, n<=max_elements, - * and m==n_bits= approximately max_elements*32. This gives - * P<(1-exp(-4*n/(32*n)))^4 == (1-exp(1/-8))^4 == .00019 - * - * It would be more optimal in space vs false positives to get this false - * positive rate by going for k==13, and m==18.5n, but we also want to - * conserve CPU, and k==13 is pretty big. - */ - int n_bits = 1u << (tor_log2(max_elements)+5); - digestset_t *r = tor_malloc(sizeof(digestset_t)); - r->mask = n_bits - 1; - r->ba = bitarray_init_zero(n_bits); - return r; -} - -/** Free all storage held in <b>set</b>. */ -void -digestset_free_(digestset_t *set) -{ - if (!set) - return; - bitarray_free(set->ba); - tor_free(set); -} - diff --git a/src/common/container.h b/src/common/container.h deleted file mode 100644 index 5d2dce5416..0000000000 --- a/src/common/container.h +++ /dev/null @@ -1,742 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_CONTAINER_H -#define TOR_CONTAINER_H - -#include "util.h" -#include "siphash.h" - -/** A resizeable list of pointers, with associated helpful functionality. - * - * The members of this struct are exposed only so that macros and inlines can - * use them; all access to smartlist internals should go through the functions - * and macros defined here. - **/ -typedef struct smartlist_t { - /** @{ */ - /** <b>list</b> has enough capacity to store exactly <b>capacity</b> elements - * before it needs to be resized. Only the first <b>num_used</b> (\<= - * capacity) elements point to valid data. - */ - void **list; - int num_used; - int capacity; - /** @} */ -} smartlist_t; - -MOCK_DECL(smartlist_t *, smartlist_new, (void)); -MOCK_DECL(void, smartlist_free_, (smartlist_t *sl)); -#define smartlist_free(sl) FREE_AND_NULL(smartlist_t, smartlist_free_, (sl)) - -void smartlist_clear(smartlist_t *sl); -void smartlist_add(smartlist_t *sl, void *element); -void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2); -void smartlist_remove(smartlist_t *sl, const void *element); -void smartlist_remove_keeporder(smartlist_t *sl, const void *element); -void *smartlist_pop_last(smartlist_t *sl); -void smartlist_reverse(smartlist_t *sl); -void smartlist_string_remove(smartlist_t *sl, const char *element); -int smartlist_contains(const smartlist_t *sl, const void *element); -int smartlist_contains_string(const smartlist_t *sl, const char *element); -int smartlist_pos(const smartlist_t *sl, const void *element); -int smartlist_string_pos(const smartlist_t *, const char *elt); -int smartlist_contains_string_case(const smartlist_t *sl, const char *element); -int smartlist_contains_int_as_string(const smartlist_t *sl, int num); -int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2); -int smartlist_contains_digest(const smartlist_t *sl, const char *element); -int smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2); -int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2); -void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2); -void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2); - -/* smartlist_choose() is defined in crypto.[ch] */ -#ifdef DEBUG_SMARTLIST -/** Return the number of items in sl. - */ -static inline int smartlist_len(const smartlist_t *sl); -static inline int smartlist_len(const smartlist_t *sl) { - tor_assert(sl); - return (sl)->num_used; -} -/** Return the <b>idx</b>th element of sl. - */ -static inline void *smartlist_get(const smartlist_t *sl, int idx); -static inline void *smartlist_get(const smartlist_t *sl, int idx) { - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(sl->num_used > idx); - return sl->list[idx]; -} -static inline void smartlist_set(smartlist_t *sl, int idx, void *val) { - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(sl->num_used > idx); - sl->list[idx] = val; -} -#else /* !(defined(DEBUG_SMARTLIST)) */ -#define smartlist_len(sl) ((sl)->num_used) -#define smartlist_get(sl, idx) ((sl)->list[idx]) -#define smartlist_set(sl, idx, val) ((sl)->list[idx] = (val)) -#endif /* defined(DEBUG_SMARTLIST) */ - -/** Exchange the elements at indices <b>idx1</b> and <b>idx2</b> of the - * smartlist <b>sl</b>. */ -static inline void smartlist_swap(smartlist_t *sl, int idx1, int idx2) -{ - if (idx1 != idx2) { - void *elt = smartlist_get(sl, idx1); - smartlist_set(sl, idx1, smartlist_get(sl, idx2)); - smartlist_set(sl, idx2, elt); - } -} - -void smartlist_del(smartlist_t *sl, int idx); -void smartlist_del_keeporder(smartlist_t *sl, int idx); -void smartlist_insert(smartlist_t *sl, int idx, void *val); -void smartlist_sort(smartlist_t *sl, - int (*compare)(const void **a, const void **b)); -void *smartlist_get_most_frequent_(const smartlist_t *sl, - int (*compare)(const void **a, const void **b), - int *count_out); -#define smartlist_get_most_frequent(sl, compare) \ - smartlist_get_most_frequent_((sl), (compare), NULL) -void smartlist_uniq(smartlist_t *sl, - int (*compare)(const void **a, const void **b), - void (*free_fn)(void *elt)); - -void smartlist_sort_strings(smartlist_t *sl); -void smartlist_sort_digests(smartlist_t *sl); -void smartlist_sort_digests256(smartlist_t *sl); -void smartlist_sort_pointers(smartlist_t *sl); - -const char *smartlist_get_most_frequent_string(smartlist_t *sl); -const char *smartlist_get_most_frequent_string_(smartlist_t *sl, - int *count_out); -const uint8_t *smartlist_get_most_frequent_digest256(smartlist_t *sl); - -void smartlist_uniq_strings(smartlist_t *sl); -void smartlist_uniq_digests(smartlist_t *sl); -void smartlist_uniq_digests256(smartlist_t *sl); -void *smartlist_bsearch(smartlist_t *sl, const void *key, - int (*compare)(const void *key, const void **member)); -int smartlist_bsearch_idx(const smartlist_t *sl, const void *key, - int (*compare)(const void *key, const void **member), - int *found_out); - -void smartlist_pqueue_add(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - void *item); -void *smartlist_pqueue_pop(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset); -void smartlist_pqueue_remove(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - void *item); -void smartlist_pqueue_assert_ok(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset); - -#define SPLIT_SKIP_SPACE 0x01 -#define SPLIT_IGNORE_BLANK 0x02 -#define SPLIT_STRIP_SPACE 0x04 -int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, - int flags, int max); -char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, - size_t *len_out) ATTR_MALLOC; -char *smartlist_join_strings2(smartlist_t *sl, const char *join, - size_t join_len, int terminate, size_t *len_out) - ATTR_MALLOC; - -/** Iterate over the items in a smartlist <b>sl</b>, in order. For each item, - * assign it to a new local variable of type <b>type</b> named <b>var</b>, and - * execute the statements inside the loop body. Inside the loop, the loop - * index can be accessed as <b>var</b>_sl_idx and the length of the list can - * be accessed as <b>var</b>_sl_len. - * - * NOTE: Do not change the length of the list while the loop is in progress, - * unless you adjust the _sl_len variable correspondingly. See second example - * below. - * - * Example use: - * <pre> - * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0); - * SMARTLIST_FOREACH_BEGIN(list, char *, cp) { - * printf("%d: %s\n", cp_sl_idx, cp); - * tor_free(cp); - * } SMARTLIST_FOREACH_END(cp); - * smartlist_free(list); - * </pre> - * - * Example use (advanced): - * <pre> - * SMARTLIST_FOREACH_BEGIN(list, char *, cp) { - * if (!strcmp(cp, "junk")) { - * tor_free(cp); - * SMARTLIST_DEL_CURRENT(list, cp); - * } - * } SMARTLIST_FOREACH_END(cp); - * </pre> - */ -/* Note: these macros use token pasting, and reach into smartlist internals. - * This can make them a little daunting. Here's the approximate unpacking of - * the above examples, for entertainment value: - * - * <pre> - * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0); - * { - * int cp_sl_idx, cp_sl_len = smartlist_len(list); - * char *cp; - * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) { - * cp = smartlist_get(list, cp_sl_idx); - * printf("%d: %s\n", cp_sl_idx, cp); - * tor_free(cp); - * } - * } - * smartlist_free(list); - * </pre> - * - * <pre> - * { - * int cp_sl_idx, cp_sl_len = smartlist_len(list); - * char *cp; - * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) { - * cp = smartlist_get(list, cp_sl_idx); - * if (!strcmp(cp, "junk")) { - * tor_free(cp); - * smartlist_del(list, cp_sl_idx); - * --cp_sl_idx; - * --cp_sl_len; - * } - * } - * } - * </pre> - */ -#define SMARTLIST_FOREACH_BEGIN(sl, type, var) \ - STMT_BEGIN \ - int var ## _sl_idx, var ## _sl_len=(sl)->num_used; \ - type var; \ - for (var ## _sl_idx = 0; var ## _sl_idx < var ## _sl_len; \ - ++var ## _sl_idx) { \ - var = (sl)->list[var ## _sl_idx]; - -#define SMARTLIST_FOREACH_END(var) \ - var = NULL; \ - (void) var ## _sl_idx; \ - } STMT_END - -/** - * An alias for SMARTLIST_FOREACH_BEGIN and SMARTLIST_FOREACH_END, using - * <b>cmd</b> as the loop body. This wrapper is here for convenience with - * very short loops. - * - * By convention, we do not use this for loops which nest, or for loops over - * 10 lines or so. Use SMARTLIST_FOREACH_{BEGIN,END} for those. - */ -#define SMARTLIST_FOREACH(sl, type, var, cmd) \ - SMARTLIST_FOREACH_BEGIN(sl,type,var) { \ - cmd; \ - } SMARTLIST_FOREACH_END(var) - -/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed - * with the variable <b>var</b>, remove the current element in a way that - * won't confuse the loop. */ -#define SMARTLIST_DEL_CURRENT(sl, var) \ - STMT_BEGIN \ - smartlist_del(sl, var ## _sl_idx); \ - --var ## _sl_idx; \ - --var ## _sl_len; \ - STMT_END - -/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed - * with the variable <b>var</b>, remove the current element in a way that - * won't confuse the loop. */ -#define SMARTLIST_DEL_CURRENT_KEEPORDER(sl, var) \ - STMT_BEGIN \ - smartlist_del_keeporder(sl, var ## _sl_idx); \ - --var ## _sl_idx; \ - --var ## _sl_len; \ - STMT_END - -/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed - * with the variable <b>var</b>, replace the current element with <b>val</b>. - * Does not deallocate the current value of <b>var</b>. - */ -#define SMARTLIST_REPLACE_CURRENT(sl, var, val) \ - STMT_BEGIN \ - smartlist_set(sl, var ## _sl_idx, val); \ - STMT_END - -/* Helper: Given two lists of items, possibly of different types, such that - * both lists are sorted on some common field (as determined by a comparison - * expression <b>cmpexpr</b>), and such that one list (<b>sl1</b>) has no - * duplicates on the common field, loop through the lists in lockstep, and - * execute <b>unmatched_var2</b> on items in var2 that do not appear in - * var1. - * - * WARNING: It isn't safe to add remove elements from either list while the - * loop is in progress. - * - * Example use: - * SMARTLIST_FOREACH_JOIN(routerstatus_list, routerstatus_t *, rs, - * routerinfo_list, routerinfo_t *, ri, - * tor_memcmp(rs->identity_digest, ri->identity_digest, 20), - * log_info(LD_GENERAL,"No match for %s", ri->nickname)) { - * log_info(LD_GENERAL, "%s matches routerstatus %p", ri->nickname, rs); - * } SMARTLIST_FOREACH_JOIN_END(rs, ri); - **/ -/* The example above unpacks (approximately) to: - * int rs_sl_idx = 0, rs_sl_len = smartlist_len(routerstatus_list); - * int ri_sl_idx, ri_sl_len = smartlist_len(routerinfo_list); - * int rs_ri_cmp; - * routerstatus_t *rs; - * routerinfo_t *ri; - * for (; ri_sl_idx < ri_sl_len; ++ri_sl_idx) { - * ri = smartlist_get(routerinfo_list, ri_sl_idx); - * while (rs_sl_idx < rs_sl_len) { - * rs = smartlist_get(routerstatus_list, rs_sl_idx); - * rs_ri_cmp = tor_memcmp(rs->identity_digest, ri->identity_digest, 20); - * if (rs_ri_cmp > 0) { - * break; - * } else if (rs_ri_cmp == 0) { - * goto matched_ri; - * } else { - * ++rs_sl_idx; - * } - * } - * log_info(LD_GENERAL,"No match for %s", ri->nickname); - * continue; - * matched_ri: { - * log_info(LD_GENERAL,"%s matches with routerstatus %p",ri->nickname,rs); - * } - * } - */ -#define SMARTLIST_FOREACH_JOIN(sl1, type1, var1, sl2, type2, var2, \ - cmpexpr, unmatched_var2) \ - STMT_BEGIN \ - int var1 ## _sl_idx = 0, var1 ## _sl_len=(sl1)->num_used; \ - int var2 ## _sl_idx = 0, var2 ## _sl_len=(sl2)->num_used; \ - int var1 ## _ ## var2 ## _cmp; \ - type1 var1; \ - type2 var2; \ - for (; var2##_sl_idx < var2##_sl_len; ++var2##_sl_idx) { \ - var2 = (sl2)->list[var2##_sl_idx]; \ - while (var1##_sl_idx < var1##_sl_len) { \ - var1 = (sl1)->list[var1##_sl_idx]; \ - var1##_##var2##_cmp = (cmpexpr); \ - if (var1##_##var2##_cmp > 0) { \ - break; \ - } else if (var1##_##var2##_cmp == 0) { \ - goto matched_##var2; \ - } else { \ - ++var1##_sl_idx; \ - } \ - } \ - /* Ran out of v1, or no match for var2. */ \ - unmatched_var2; \ - continue; \ - matched_##var2: ; \ - -#define SMARTLIST_FOREACH_JOIN_END(var1, var2) \ - } \ - STMT_END - -#define DECLARE_MAP_FNS(maptype, keytype, prefix) \ - typedef struct maptype maptype; \ - typedef struct prefix##entry_t *prefix##iter_t; \ - MOCK_DECL(maptype*, prefix##new, (void)); \ - void* prefix##set(maptype *map, keytype key, void *val); \ - void* prefix##get(const maptype *map, keytype key); \ - void* prefix##remove(maptype *map, keytype key); \ - MOCK_DECL(void, prefix##free_, (maptype *map, void (*free_val)(void*))); \ - int prefix##isempty(const maptype *map); \ - int prefix##size(const maptype *map); \ - prefix##iter_t *prefix##iter_init(maptype *map); \ - prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter); \ - prefix##iter_t *prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter); \ - void prefix##iter_get(prefix##iter_t *iter, keytype *keyp, void **valp); \ - int prefix##iter_done(prefix##iter_t *iter); \ - void prefix##assert_ok(const maptype *map) - -/* Map from const char * to void *. Implemented with a hash table. */ -DECLARE_MAP_FNS(strmap_t, const char *, strmap_); -/* Map from const char[DIGEST_LEN] to void *. Implemented with a hash table. */ -DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_); -/* Map from const uint8_t[DIGEST256_LEN] to void *. Implemented with a hash - * table. */ -DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_); - -#define MAP_FREE_AND_NULL(maptype, map, fn) \ - do { \ - maptype ## _free_((map), (fn)); \ - (map) = NULL; \ - } while (0) - -#define strmap_free(map, fn) MAP_FREE_AND_NULL(strmap, (map), (fn)) -#define digestmap_free(map, fn) MAP_FREE_AND_NULL(digestmap, (map), (fn)) -#define digest256map_free(map, fn) MAP_FREE_AND_NULL(digest256map, (map), (fn)) - -#undef DECLARE_MAP_FNS - -/** Iterates over the key-value pairs in a map <b>map</b> in order. - * <b>prefix</b> is as for DECLARE_MAP_FNS (i.e., strmap_ or digestmap_). - * The map's keys and values are of type keytype and valtype respectively; - * each iteration assigns them to keyvar and valvar. - * - * Example use: - * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { - * // use k and r - * } MAP_FOREACH_END. - */ -/* Unpacks to, approximately: - * { - * digestmap_iter_t *k_iter; - * for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter); - * k_iter = digestmap_iter_next(m, k_iter)) { - * const char *k; - * void *r_voidp; - * routerinfo_t *r; - * digestmap_iter_get(k_iter, &k, &r_voidp); - * r = r_voidp; - * // use k and r - * } - * } - */ -#define MAP_FOREACH(prefix, map, keytype, keyvar, valtype, valvar) \ - STMT_BEGIN \ - prefix##iter_t *keyvar##_iter; \ - for (keyvar##_iter = prefix##iter_init(map); \ - !prefix##iter_done(keyvar##_iter); \ - keyvar##_iter = prefix##iter_next(map, keyvar##_iter)) { \ - keytype keyvar; \ - void *valvar##_voidp; \ - valtype valvar; \ - prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ - valvar = valvar##_voidp; - -/** As MAP_FOREACH, except allows members to be removed from the map - * during the iteration via MAP_DEL_CURRENT. Example use: - * - * Example use: - * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { - * if (is_very_old(r)) - * MAP_DEL_CURRENT(k); - * } MAP_FOREACH_END. - **/ -/* Unpacks to, approximately: - * { - * digestmap_iter_t *k_iter; - * int k_del=0; - * for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter); - * k_iter = k_del ? digestmap_iter_next(m, k_iter) - * : digestmap_iter_next_rmv(m, k_iter)) { - * const char *k; - * void *r_voidp; - * routerinfo_t *r; - * k_del=0; - * digestmap_iter_get(k_iter, &k, &r_voidp); - * r = r_voidp; - * if (is_very_old(r)) { - * k_del = 1; - * } - * } - * } - */ -#define MAP_FOREACH_MODIFY(prefix, map, keytype, keyvar, valtype, valvar) \ - STMT_BEGIN \ - prefix##iter_t *keyvar##_iter; \ - int keyvar##_del=0; \ - for (keyvar##_iter = prefix##iter_init(map); \ - !prefix##iter_done(keyvar##_iter); \ - keyvar##_iter = keyvar##_del ? \ - prefix##iter_next_rmv(map, keyvar##_iter) : \ - prefix##iter_next(map, keyvar##_iter)) { \ - keytype keyvar; \ - void *valvar##_voidp; \ - valtype valvar; \ - keyvar##_del=0; \ - prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ - valvar = valvar##_voidp; - -/** Used with MAP_FOREACH_MODIFY to remove the currently-iterated-upon - * member of the map. */ -#define MAP_DEL_CURRENT(keyvar) \ - STMT_BEGIN \ - keyvar##_del = 1; \ - STMT_END - -/** Used to end a MAP_FOREACH() block. */ -#define MAP_FOREACH_END } STMT_END ; - -/** As MAP_FOREACH, but does not require declaration of prefix or keytype. - * Example use: - * DIGESTMAP_FOREACH(m, k, routerinfo_t *, r) { - * // use k and r - * } DIGESTMAP_FOREACH_END. - */ -#define DIGESTMAP_FOREACH(map, keyvar, valtype, valvar) \ - MAP_FOREACH(digestmap_, map, const char *, keyvar, valtype, valvar) - -/** As MAP_FOREACH_MODIFY, but does not require declaration of prefix or - * keytype. - * Example use: - * DIGESTMAP_FOREACH_MODIFY(m, k, routerinfo_t *, r) { - * if (is_very_old(r)) - * MAP_DEL_CURRENT(k); - * } DIGESTMAP_FOREACH_END. - */ -#define DIGESTMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ - MAP_FOREACH_MODIFY(digestmap_, map, const char *, keyvar, valtype, valvar) -/** Used to end a DIGESTMAP_FOREACH() block. */ -#define DIGESTMAP_FOREACH_END MAP_FOREACH_END - -#define DIGEST256MAP_FOREACH(map, keyvar, valtype, valvar) \ - MAP_FOREACH(digest256map_, map, const uint8_t *, keyvar, valtype, valvar) -#define DIGEST256MAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ - MAP_FOREACH_MODIFY(digest256map_, map, const uint8_t *, \ - keyvar, valtype, valvar) -#define DIGEST256MAP_FOREACH_END MAP_FOREACH_END - -#define STRMAP_FOREACH(map, keyvar, valtype, valvar) \ - MAP_FOREACH(strmap_, map, const char *, keyvar, valtype, valvar) -#define STRMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ - MAP_FOREACH_MODIFY(strmap_, map, const char *, keyvar, valtype, valvar) -#define STRMAP_FOREACH_END MAP_FOREACH_END - -void* strmap_set_lc(strmap_t *map, const char *key, void *val); -void* strmap_get_lc(const strmap_t *map, const char *key); -void* strmap_remove_lc(strmap_t *map, const char *key); - -#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, maptype, valtype) \ - typedef struct maptype maptype; \ - typedef struct prefix##iter_t *prefix##iter_t; \ - ATTR_UNUSED static inline maptype* \ - prefix##new(void) \ - { \ - return (maptype*)digestmap_new(); \ - } \ - ATTR_UNUSED static inline digestmap_t* \ - prefix##to_digestmap(maptype *map) \ - { \ - return (digestmap_t*)map; \ - } \ - ATTR_UNUSED static inline valtype* \ - prefix##get(maptype *map, const char *key) \ - { \ - return (valtype*)digestmap_get((digestmap_t*)map, key); \ - } \ - ATTR_UNUSED static inline valtype* \ - prefix##set(maptype *map, const char *key, valtype *val) \ - { \ - return (valtype*)digestmap_set((digestmap_t*)map, key, val); \ - } \ - ATTR_UNUSED static inline valtype* \ - prefix##remove(maptype *map, const char *key) \ - { \ - return (valtype*)digestmap_remove((digestmap_t*)map, key); \ - } \ - ATTR_UNUSED static inline void \ - prefix##f##ree_(maptype *map, void (*free_val)(void*)) \ - { \ - digestmap_free_((digestmap_t*)map, free_val); \ - } \ - ATTR_UNUSED static inline int \ - prefix##isempty(maptype *map) \ - { \ - return digestmap_isempty((digestmap_t*)map); \ - } \ - ATTR_UNUSED static inline int \ - prefix##size(maptype *map) \ - { \ - return digestmap_size((digestmap_t*)map); \ - } \ - ATTR_UNUSED static inline \ - prefix##iter_t *prefix##iter_init(maptype *map) \ - { \ - return (prefix##iter_t*) digestmap_iter_init((digestmap_t*)map); \ - } \ - ATTR_UNUSED static inline \ - prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter) \ - { \ - return (prefix##iter_t*) digestmap_iter_next( \ - (digestmap_t*)map, (digestmap_iter_t*)iter); \ - } \ - ATTR_UNUSED static inline prefix##iter_t* \ - prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter) \ - { \ - return (prefix##iter_t*) digestmap_iter_next_rmv( \ - (digestmap_t*)map, (digestmap_iter_t*)iter); \ - } \ - ATTR_UNUSED static inline void \ - prefix##iter_get(prefix##iter_t *iter, \ - const char **keyp, \ - valtype **valp) \ - { \ - void *v; \ - digestmap_iter_get((digestmap_iter_t*) iter, keyp, &v); \ - *valp = v; \ - } \ - ATTR_UNUSED static inline int \ - prefix##iter_done(prefix##iter_t *iter) \ - { \ - return digestmap_iter_done((digestmap_iter_t*)iter); \ - } - -#if SIZEOF_INT == 4 -#define BITARRAY_SHIFT 5 -#elif SIZEOF_INT == 8 -#define BITARRAY_SHIFT 6 -#else -#error "int is neither 4 nor 8 bytes. I can't deal with that." -#endif /* SIZEOF_INT == 4 || ... */ -#define BITARRAY_MASK ((1u<<BITARRAY_SHIFT)-1) - -/** A random-access array of one-bit-wide elements. */ -typedef unsigned int bitarray_t; -/** Create a new bit array that can hold <b>n_bits</b> bits. */ -static inline bitarray_t * -bitarray_init_zero(unsigned int n_bits) -{ - /* round up to the next int. */ - size_t sz = (n_bits+BITARRAY_MASK) >> BITARRAY_SHIFT; - return tor_calloc(sz, sizeof(unsigned int)); -} -/** Expand <b>ba</b> from holding <b>n_bits_old</b> to <b>n_bits_new</b>, - * clearing all new bits. Returns a possibly changed pointer to the - * bitarray. */ -static inline bitarray_t * -bitarray_expand(bitarray_t *ba, - unsigned int n_bits_old, unsigned int n_bits_new) -{ - size_t sz_old = (n_bits_old+BITARRAY_MASK) >> BITARRAY_SHIFT; - size_t sz_new = (n_bits_new+BITARRAY_MASK) >> BITARRAY_SHIFT; - char *ptr; - if (sz_new <= sz_old) - return ba; - ptr = tor_reallocarray(ba, sz_new, sizeof(unsigned int)); - /* This memset does nothing to the older excess bytes. But they were - * already set to 0 by bitarry_init_zero. */ - memset(ptr+sz_old*sizeof(unsigned int), 0, - (sz_new-sz_old)*sizeof(unsigned int)); - return (bitarray_t*) ptr; -} -/** Free the bit array <b>ba</b>. */ -static inline void -bitarray_free_(bitarray_t *ba) -{ - tor_free(ba); -} -#define bitarray_free(ba) FREE_AND_NULL(bitarray_t, bitarray_free_, (ba)) - -/** Set the <b>bit</b>th bit in <b>b</b> to 1. */ -static inline void -bitarray_set(bitarray_t *b, int bit) -{ - b[bit >> BITARRAY_SHIFT] |= (1u << (bit & BITARRAY_MASK)); -} -/** Set the <b>bit</b>th bit in <b>b</b> to 0. */ -static inline void -bitarray_clear(bitarray_t *b, int bit) -{ - b[bit >> BITARRAY_SHIFT] &= ~ (1u << (bit & BITARRAY_MASK)); -} -/** Return true iff <b>bit</b>th bit in <b>b</b> is nonzero. NOTE: does - * not necessarily return 1 on true. */ -static inline unsigned int -bitarray_is_set(bitarray_t *b, int bit) -{ - return b[bit >> BITARRAY_SHIFT] & (1u << (bit & BITARRAY_MASK)); -} - -/** A set of digests, implemented as a Bloom filter. */ -typedef struct { - int mask; /**< One less than the number of bits in <b>ba</b>; always one less - * than a power of two. */ - bitarray_t *ba; /**< A bit array to implement the Bloom filter. */ -} digestset_t; - -#define BIT(n) ((n) & set->mask) -/** Add the digest <b>digest</b> to <b>set</b>. */ -static inline void -digestset_add(digestset_t *set, const char *digest) -{ - const uint64_t x = siphash24g(digest, 20); - const uint32_t d1 = (uint32_t) x; - const uint32_t d2 = (uint32_t)( (x>>16) + x); - const uint32_t d3 = (uint32_t)( (x>>32) + x); - const uint32_t d4 = (uint32_t)( (x>>48) + x); - bitarray_set(set->ba, BIT(d1)); - bitarray_set(set->ba, BIT(d2)); - bitarray_set(set->ba, BIT(d3)); - bitarray_set(set->ba, BIT(d4)); -} - -/** If <b>digest</b> is in <b>set</b>, return nonzero. Otherwise, - * <em>probably</em> return zero. */ -static inline int -digestset_contains(const digestset_t *set, const char *digest) -{ - const uint64_t x = siphash24g(digest, 20); - const uint32_t d1 = (uint32_t) x; - const uint32_t d2 = (uint32_t)( (x>>16) + x); - const uint32_t d3 = (uint32_t)( (x>>32) + x); - const uint32_t d4 = (uint32_t)( (x>>48) + x); - return bitarray_is_set(set->ba, BIT(d1)) && - bitarray_is_set(set->ba, BIT(d2)) && - bitarray_is_set(set->ba, BIT(d3)) && - bitarray_is_set(set->ba, BIT(d4)); -} -#undef BIT - -digestset_t *digestset_new(int max_elements); -void digestset_free_(digestset_t* set); -#define digestset_free(set) FREE_AND_NULL(digestset_t, digestset_free_, (set)) - -/* These functions, given an <b>array</b> of <b>n_elements</b>, return the - * <b>nth</b> lowest element. <b>nth</b>=0 gives the lowest element; - * <b>n_elements</b>-1 gives the highest; and (<b>n_elements</b>-1) / 2 gives - * the median. As a side effect, the elements of <b>array</b> are sorted. */ -int find_nth_int(int *array, int n_elements, int nth); -time_t find_nth_time(time_t *array, int n_elements, int nth); -double find_nth_double(double *array, int n_elements, int nth); -int32_t find_nth_int32(int32_t *array, int n_elements, int nth); -uint32_t find_nth_uint32(uint32_t *array, int n_elements, int nth); -long find_nth_long(long *array, int n_elements, int nth); -static inline int -median_int(int *array, int n_elements) -{ - return find_nth_int(array, n_elements, (n_elements-1)/2); -} -static inline time_t -median_time(time_t *array, int n_elements) -{ - return find_nth_time(array, n_elements, (n_elements-1)/2); -} -static inline double -median_double(double *array, int n_elements) -{ - return find_nth_double(array, n_elements, (n_elements-1)/2); -} -static inline uint32_t -median_uint32(uint32_t *array, int n_elements) -{ - return find_nth_uint32(array, n_elements, (n_elements-1)/2); -} -static inline int32_t -median_int32(int32_t *array, int n_elements) -{ - return find_nth_int32(array, n_elements, (n_elements-1)/2); -} - -static inline uint32_t -third_quartile_uint32(uint32_t *array, int n_elements) -{ - return find_nth_uint32(array, n_elements, (n_elements*3)/4); -} - -#endif /* !defined(TOR_CONTAINER_H) */ - diff --git a/src/common/crypto.c b/src/common/crypto.c deleted file mode 100644 index d5b7c96916..0000000000 --- a/src/common/crypto.c +++ /dev/null @@ -1,1118 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto.c - * \brief Wrapper functions to present a consistent interface to - * public-key and symmetric cryptography operations from OpenSSL and - * other places. - **/ - -#include "orconfig.h" - -#ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#include <wincrypt.h> -/* Windows defines this; so does OpenSSL 0.9.8h and later. We don't actually - * use either definition. */ -#undef OCSP_RESPONSE -#endif /* defined(_WIN32) */ - -#define CRYPTO_PRIVATE -#include "compat_openssl.h" -#include "crypto.h" -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_ed25519.h" -#include "crypto_format.h" -#include "crypto_rand.h" -#include "crypto_rsa.h" -#include "crypto_util.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/err.h> -#include <openssl/evp.h> -#include <openssl/engine.h> -#include <openssl/bn.h> -#include <openssl/dh.h> -#include <openssl/conf.h> -#include <openssl/hmac.h> -#include <openssl/ssl.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#if __GNUC__ && GCC_VERSION >= 402 -#if GCC_VERSION >= 406 -#pragma GCC diagnostic pop -#else -#pragma GCC diagnostic warning "-Wredundant-decls" -#endif -#endif /* __GNUC__ && GCC_VERSION >= 402 */ - -#ifdef HAVE_CTYPE_H -#include <ctype.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include "torlog.h" -#include "torint.h" -#include "aes.h" -#include "util.h" -#include "container.h" -#include "compat.h" -#include "sandbox.h" -#include "util_format.h" - -#include "keccak-tiny/keccak-tiny.h" - -/** A structure to hold the first half (x, g^x) of a Diffie-Hellman handshake - * while we're waiting for the second.*/ -struct crypto_dh_t { - DH *dh; /**< The openssl DH object */ -}; - -static int tor_check_dh_key(int severity, const BIGNUM *bn); - -/** Boolean: has OpenSSL's crypto been initialized? */ -static int crypto_early_initialized_ = 0; - -/** Boolean: has OpenSSL's crypto been initialized? */ -static int crypto_global_initialized_ = 0; - -/** Log all pending crypto errors at level <b>severity</b>. Use - * <b>doing</b> to describe our current activities. - */ -static void -crypto_log_errors(int severity, const char *doing) -{ - unsigned long err; - const char *msg, *lib, *func; - 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 (!msg) msg = "(null)"; - if (!lib) lib = "(null)"; - if (!func) func = "(null)"; - if (BUG(!doing)) doing = "(null)"; - tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", - doing, msg, lib, func); - } -} - -#ifndef DISABLE_ENGINES -/** Log any OpenSSL engines we're using at NOTICE. */ -static void -log_engine(const char *fn, ENGINE *e) -{ - if (e) { - const char *name, *id; - name = ENGINE_get_name(e); - id = ENGINE_get_id(e); - log_notice(LD_CRYPTO, "Default OpenSSL engine for %s is %s [%s]", - fn, name?name:"?", id?id:"?"); - } else { - log_info(LD_CRYPTO, "Using default implementation for %s", fn); - } -} -#endif /* !defined(DISABLE_ENGINES) */ - -#ifndef DISABLE_ENGINES -/** Try to load an engine in a shared library via fully qualified path. - */ -static ENGINE * -try_load_engine(const char *path, const char *engine) -{ - ENGINE *e = ENGINE_by_id("dynamic"); - if (e) { - if (!ENGINE_ctrl_cmd_string(e, "ID", engine, 0) || - !ENGINE_ctrl_cmd_string(e, "DIR_LOAD", "2", 0) || - !ENGINE_ctrl_cmd_string(e, "DIR_ADD", path, 0) || - !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { - ENGINE_free(e); - e = NULL; - } - } - return e; -} -#endif /* !defined(DISABLE_ENGINES) */ - -static int have_seeded_siphash = 0; - -/** Set up the siphash key if we haven't already done so. */ -int -crypto_init_siphash_key(void) -{ - struct sipkey key; - if (have_seeded_siphash) - return 0; - - crypto_rand((char*) &key, sizeof(key)); - siphash_set_global_key(&key); - have_seeded_siphash = 1; - return 0; -} - -/** Initialize the crypto library. Return 0 on success, -1 on failure. - */ -int -crypto_early_init(void) -{ - if (!crypto_early_initialized_) { - - crypto_early_initialized_ = 1; - -#ifdef OPENSSL_1_1_API - OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | - OPENSSL_INIT_LOAD_CRYPTO_STRINGS | - OPENSSL_INIT_ADD_ALL_CIPHERS | - OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); -#else - ERR_load_crypto_strings(); - OpenSSL_add_all_algorithms(); -#endif - - setup_openssl_threading(); - - unsigned long version_num = OpenSSL_version_num(); - const char *version_str = OpenSSL_version(OPENSSL_VERSION); - if (version_num == OPENSSL_VERSION_NUMBER && - !strcmp(version_str, OPENSSL_VERSION_TEXT)) { - log_info(LD_CRYPTO, "OpenSSL version matches version from headers " - "(%lx: %s).", version_num, version_str); - } else { - log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the " - "version we're running with. If you get weird crashes, that " - "might be why. (Compiled with %lx: %s; running with %lx: %s).", - (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT, - version_num, version_str); - } - - crypto_force_rand_ssleay(); - - if (crypto_seed_rng() < 0) - return -1; - if (crypto_init_siphash_key() < 0) - return -1; - - curve25519_init(); - ed25519_init(); - } - return 0; -} - -/** Initialize the crypto library. Return 0 on success, -1 on failure. - */ -int -crypto_global_init(int useAccel, const char *accelName, const char *accelDir) -{ - if (!crypto_global_initialized_) { - if (crypto_early_init() < 0) - return -1; - - crypto_global_initialized_ = 1; - - if (useAccel > 0) { -#ifdef DISABLE_ENGINES - (void)accelName; - (void)accelDir; - log_warn(LD_CRYPTO, "No OpenSSL hardware acceleration support enabled."); -#else - ENGINE *e = NULL; - - log_info(LD_CRYPTO, "Initializing OpenSSL engine support."); - ENGINE_load_builtin_engines(); - ENGINE_register_all_complete(); - - if (accelName) { - if (accelDir) { - log_info(LD_CRYPTO, "Trying to load dynamic OpenSSL engine \"%s\"" - " via path \"%s\".", accelName, accelDir); - e = try_load_engine(accelName, accelDir); - } else { - log_info(LD_CRYPTO, "Initializing dynamic OpenSSL engine \"%s\"" - " acceleration support.", accelName); - e = ENGINE_by_id(accelName); - } - if (!e) { - log_warn(LD_CRYPTO, "Unable to load dynamic OpenSSL engine \"%s\".", - accelName); - } else { - log_info(LD_CRYPTO, "Loaded dynamic OpenSSL engine \"%s\".", - accelName); - } - } - if (e) { - log_info(LD_CRYPTO, "Loaded OpenSSL hardware acceleration engine," - " setting default ciphers."); - ENGINE_set_default(e, ENGINE_METHOD_ALL); - } - /* Log, if available, the intersection of the set of algorithms - used by Tor and the set of algorithms available in the engine */ - log_engine("RSA", ENGINE_get_default_RSA()); - log_engine("DH", ENGINE_get_default_DH()); -#ifdef OPENSSL_1_1_API - log_engine("EC", ENGINE_get_default_EC()); -#else - log_engine("ECDH", ENGINE_get_default_ECDH()); - log_engine("ECDSA", ENGINE_get_default_ECDSA()); -#endif /* defined(OPENSSL_1_1_API) */ - log_engine("RAND", ENGINE_get_default_RAND()); - log_engine("RAND (which we will not use)", ENGINE_get_default_RAND()); - log_engine("SHA1", ENGINE_get_digest_engine(NID_sha1)); - log_engine("3DES-CBC", ENGINE_get_cipher_engine(NID_des_ede3_cbc)); - log_engine("AES-128-ECB", ENGINE_get_cipher_engine(NID_aes_128_ecb)); - log_engine("AES-128-CBC", ENGINE_get_cipher_engine(NID_aes_128_cbc)); -#ifdef NID_aes_128_ctr - log_engine("AES-128-CTR", ENGINE_get_cipher_engine(NID_aes_128_ctr)); -#endif -#ifdef NID_aes_128_gcm - log_engine("AES-128-GCM", ENGINE_get_cipher_engine(NID_aes_128_gcm)); -#endif - log_engine("AES-256-CBC", ENGINE_get_cipher_engine(NID_aes_256_cbc)); -#ifdef NID_aes_256_gcm - log_engine("AES-256-GCM", ENGINE_get_cipher_engine(NID_aes_256_gcm)); -#endif - -#endif /* defined(DISABLE_ENGINES) */ - } else { - log_info(LD_CRYPTO, "NOT using OpenSSL engine support."); - } - - if (crypto_force_rand_ssleay()) { - if (crypto_seed_rng() < 0) - return -1; - } - - evaluate_evp_for_aes(-1); - evaluate_ctr_for_aes(); - } - return 0; -} - -/** Free crypto resources held by this thread. */ -void -crypto_thread_cleanup(void) -{ -#ifndef NEW_THREAD_API - ERR_remove_thread_state(NULL); -#endif -} - -/** Used by tortls.c: Get the DH* from a crypto_dh_t. - */ -DH * -crypto_dh_get_dh_(crypto_dh_t *dh) -{ - return dh->dh; -} - -/** Allocate and return a new symmetric cipher using the provided key and iv. - * The key is <b>bits</b> bits long; the IV is CIPHER_IV_LEN bytes. Both - * must be provided. Key length must be 128, 192, or 256 */ -crypto_cipher_t * -crypto_cipher_new_with_iv_and_bits(const uint8_t *key, - const uint8_t *iv, - int bits) -{ - tor_assert(key); - tor_assert(iv); - - return aes_new_cipher((const uint8_t*)key, (const uint8_t*)iv, bits); -} - -/** Allocate and return a new symmetric cipher using the provided key and iv. - * The key is CIPHER_KEY_LEN bytes; the IV is CIPHER_IV_LEN bytes. Both - * must be provided. - */ -crypto_cipher_t * -crypto_cipher_new_with_iv(const char *key, const char *iv) -{ - return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)iv, - 128); -} - -/** Return a new crypto_cipher_t with the provided <b>key</b> and an IV of all - * zero bytes and key length <b>bits</b>. Key length must be 128, 192, or - * 256. */ -crypto_cipher_t * -crypto_cipher_new_with_bits(const char *key, int bits) -{ - char zeroiv[CIPHER_IV_LEN]; - memset(zeroiv, 0, sizeof(zeroiv)); - return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)zeroiv, - bits); -} - -/** Return a new crypto_cipher_t with the provided <b>key</b> (of - * CIPHER_KEY_LEN bytes) and an IV of all zero bytes. */ -crypto_cipher_t * -crypto_cipher_new(const char *key) -{ - return crypto_cipher_new_with_bits(key, 128); -} - -/** Free a symmetric cipher. - */ -void -crypto_cipher_free_(crypto_cipher_t *env) -{ - if (!env) - return; - - aes_cipher_free(env); -} - -/** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces - * every four characters. */ -void -crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in) -{ - int n = 0; - char *end = out+outlen; - tor_assert(outlen < SIZE_T_CEILING); - - while (*in && out<end) { - *out++ = *in++; - if (++n == 4 && *in && out<end) { - n = 0; - *out++ = ' '; - } - } - tor_assert(out<end); - *out = '\0'; -} - -/* symmetric crypto */ - -/** Encrypt <b>fromlen</b> bytes from <b>from</b> using the cipher - * <b>env</b>; on success, store the result to <b>to</b> and return 0. - * Does not check for failure. - */ -int -crypto_cipher_encrypt(crypto_cipher_t *env, char *to, - const char *from, size_t fromlen) -{ - tor_assert(env); - tor_assert(env); - tor_assert(from); - tor_assert(fromlen); - tor_assert(to); - tor_assert(fromlen < SIZE_T_CEILING); - - memcpy(to, from, fromlen); - aes_crypt_inplace(env, to, fromlen); - return 0; -} - -/** Decrypt <b>fromlen</b> bytes from <b>from</b> using the cipher - * <b>env</b>; on success, store the result to <b>to</b> and return 0. - * Does not check for failure. - */ -int -crypto_cipher_decrypt(crypto_cipher_t *env, char *to, - const char *from, size_t fromlen) -{ - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < SIZE_T_CEILING); - - memcpy(to, from, fromlen); - aes_crypt_inplace(env, to, fromlen); - return 0; -} - -/** Encrypt <b>len</b> bytes on <b>from</b> using the cipher in <b>env</b>; - * on success. Does not check for failure. - */ -void -crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *buf, size_t len) -{ - tor_assert(len < SIZE_T_CEILING); - aes_crypt_inplace(env, buf, len); -} - -/** Encrypt <b>fromlen</b> bytes (at least 1) from <b>from</b> with the key in - * <b>key</b> to the buffer in <b>to</b> of length - * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> plus - * CIPHER_IV_LEN bytes for the initialization vector. On success, return the - * number of bytes written, on failure, return -1. - */ -int -crypto_cipher_encrypt_with_iv(const char *key, - char *to, size_t tolen, - const char *from, size_t fromlen) -{ - crypto_cipher_t *cipher; - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < INT_MAX); - - if (fromlen < 1) - return -1; - if (tolen < fromlen + CIPHER_IV_LEN) - return -1; - - char iv[CIPHER_IV_LEN]; - crypto_rand(iv, sizeof(iv)); - cipher = crypto_cipher_new_with_iv(key, iv); - - memcpy(to, iv, CIPHER_IV_LEN); - crypto_cipher_encrypt(cipher, to+CIPHER_IV_LEN, from, fromlen); - crypto_cipher_free(cipher); - memwipe(iv, 0, sizeof(iv)); - return (int)(fromlen + CIPHER_IV_LEN); -} - -/** Decrypt <b>fromlen</b> bytes (at least 1+CIPHER_IV_LEN) from <b>from</b> - * with the key in <b>key</b> to the buffer in <b>to</b> of length - * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> minus - * CIPHER_IV_LEN bytes for the initialization vector. On success, return the - * number of bytes written, on failure, return -1. - */ -int -crypto_cipher_decrypt_with_iv(const char *key, - char *to, size_t tolen, - const char *from, size_t fromlen) -{ - crypto_cipher_t *cipher; - tor_assert(key); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < INT_MAX); - - if (fromlen <= CIPHER_IV_LEN) - return -1; - if (tolen < fromlen - CIPHER_IV_LEN) - return -1; - - cipher = crypto_cipher_new_with_iv(key, from); - - crypto_cipher_encrypt(cipher, to, from+CIPHER_IV_LEN, fromlen-CIPHER_IV_LEN); - crypto_cipher_free(cipher); - return (int)(fromlen - CIPHER_IV_LEN); -} - -/* DH */ - -/** Our DH 'g' parameter */ -#define DH_GENERATOR 2 - -/** Shared P parameter for our circuit-crypto DH key exchanges. */ -static BIGNUM *dh_param_p = NULL; -/** Shared P parameter for our TLS DH key exchanges. */ -static BIGNUM *dh_param_p_tls = NULL; -/** Shared G parameter for our DH key exchanges. */ -static BIGNUM *dh_param_g = NULL; - -/** Validate a given set of Diffie-Hellman parameters. This is moderately - * computationally expensive (milliseconds), so should only be called when - * the DH parameters change. Returns 0 on success, * -1 on failure. - */ -static int -crypto_validate_dh_params(const BIGNUM *p, const BIGNUM *g) -{ - DH *dh = NULL; - int ret = -1; - - /* Copy into a temporary DH object, just so that DH_check() can be called. */ - if (!(dh = DH_new())) - goto out; -#ifdef OPENSSL_1_1_API - BIGNUM *dh_p, *dh_g; - if (!(dh_p = BN_dup(p))) - goto out; - if (!(dh_g = BN_dup(g))) - goto out; - if (!DH_set0_pqg(dh, dh_p, NULL, dh_g)) - goto out; -#else /* !(defined(OPENSSL_1_1_API)) */ - if (!(dh->p = BN_dup(p))) - goto out; - if (!(dh->g = BN_dup(g))) - goto out; -#endif /* defined(OPENSSL_1_1_API) */ - - /* Perform the validation. */ - int codes = 0; - if (!DH_check(dh, &codes)) - goto out; - if (BN_is_word(g, DH_GENERATOR_2)) { - /* Per https://wiki.openssl.org/index.php/Diffie-Hellman_parameters - * - * OpenSSL checks the prime is congruent to 11 when g = 2; while the - * IETF's primes are congruent to 23 when g = 2. - */ - BN_ULONG residue = BN_mod_word(p, 24); - if (residue == 11 || residue == 23) - codes &= ~DH_NOT_SUITABLE_GENERATOR; - } - if (codes != 0) /* Specifics on why the params suck is irrelevant. */ - goto out; - - /* Things are probably not evil. */ - ret = 0; - - out: - if (dh) - DH_free(dh); - return ret; -} - -/** Set the global Diffie-Hellman generator, used for both TLS and internal - * DH stuff. - */ -static void -crypto_set_dh_generator(void) -{ - BIGNUM *generator; - int r; - - if (dh_param_g) - return; - - generator = BN_new(); - tor_assert(generator); - - r = BN_set_word(generator, DH_GENERATOR); - tor_assert(r); - - dh_param_g = generator; -} - -/** Set the global TLS Diffie-Hellman modulus. Use the Apache mod_ssl DH - * modulus. */ -void -crypto_set_tls_dh_prime(void) -{ - BIGNUM *tls_prime = NULL; - int r; - - /* If the space is occupied, free the previous TLS DH prime */ - if (BUG(dh_param_p_tls)) { - /* LCOV_EXCL_START - * - * We shouldn't be calling this twice. - */ - BN_clear_free(dh_param_p_tls); - dh_param_p_tls = NULL; - /* LCOV_EXCL_STOP */ - } - - tls_prime = BN_new(); - tor_assert(tls_prime); - - /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see - * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this - * prime. - */ - r = BN_hex2bn(&tls_prime, - "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98" - "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A" - "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7" - "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68" - "B0E7393E0F24218EB3"); - tor_assert(r); - - tor_assert(tls_prime); - - dh_param_p_tls = tls_prime; - crypto_set_dh_generator(); - tor_assert(0 == crypto_validate_dh_params(dh_param_p_tls, dh_param_g)); -} - -/** Initialize dh_param_p and dh_param_g if they are not already - * set. */ -static void -init_dh_param(void) -{ - BIGNUM *circuit_dh_prime; - int r; - if (BUG(dh_param_p && dh_param_g)) - return; // LCOV_EXCL_LINE This function isn't supposed to be called twice. - - circuit_dh_prime = BN_new(); - tor_assert(circuit_dh_prime); - - /* This is from rfc2409, section 6.2. It's a safe prime, and - supposedly it equals: - 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }. - */ - r = BN_hex2bn(&circuit_dh_prime, - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" - "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" - "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" - "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE65381FFFFFFFFFFFFFFFF"); - tor_assert(r); - - /* Set the new values as the global DH parameters. */ - dh_param_p = circuit_dh_prime; - crypto_set_dh_generator(); - tor_assert(0 == crypto_validate_dh_params(dh_param_p, dh_param_g)); - - if (!dh_param_p_tls) { - crypto_set_tls_dh_prime(); - } -} - -/** Number of bits to use when choosing the x or y value in a Diffie-Hellman - * handshake. Since we exponentiate by this value, choosing a smaller one - * lets our handhake go faster. - */ -#define DH_PRIVATE_KEY_BITS 320 - -/** Allocate and return a new DH object for a key exchange. Returns NULL on - * failure. - */ -crypto_dh_t * -crypto_dh_new(int dh_type) -{ - crypto_dh_t *res = tor_malloc_zero(sizeof(crypto_dh_t)); - - tor_assert(dh_type == DH_TYPE_CIRCUIT || dh_type == DH_TYPE_TLS || - dh_type == DH_TYPE_REND); - - if (!dh_param_p) - init_dh_param(); - - if (!(res->dh = DH_new())) - goto err; - -#ifdef OPENSSL_1_1_API - BIGNUM *dh_p = NULL, *dh_g = NULL; - - if (dh_type == DH_TYPE_TLS) { - dh_p = BN_dup(dh_param_p_tls); - } else { - dh_p = BN_dup(dh_param_p); - } - if (!dh_p) - goto err; - - dh_g = BN_dup(dh_param_g); - if (!dh_g) { - BN_free(dh_p); - goto err; - } - - if (!DH_set0_pqg(res->dh, dh_p, NULL, dh_g)) { - goto err; - } - - if (!DH_set_length(res->dh, DH_PRIVATE_KEY_BITS)) - goto err; -#else /* !(defined(OPENSSL_1_1_API)) */ - if (dh_type == DH_TYPE_TLS) { - if (!(res->dh->p = BN_dup(dh_param_p_tls))) - goto err; - } else { - if (!(res->dh->p = BN_dup(dh_param_p))) - goto err; - } - - if (!(res->dh->g = BN_dup(dh_param_g))) - goto err; - - res->dh->length = DH_PRIVATE_KEY_BITS; -#endif /* defined(OPENSSL_1_1_API) */ - - return res; - - /* LCOV_EXCL_START - * This error condition is only reached when an allocation fails */ - err: - crypto_log_errors(LOG_WARN, "creating DH object"); - if (res->dh) DH_free(res->dh); /* frees p and g too */ - tor_free(res); - return NULL; - /* LCOV_EXCL_STOP */ -} - -/** Return a copy of <b>dh</b>, sharing its internal state. */ -crypto_dh_t * -crypto_dh_dup(const crypto_dh_t *dh) -{ - crypto_dh_t *dh_new = tor_malloc_zero(sizeof(crypto_dh_t)); - tor_assert(dh); - tor_assert(dh->dh); - dh_new->dh = dh->dh; - DH_up_ref(dh->dh); - return dh_new; -} - -/** Return the length of the DH key in <b>dh</b>, in bytes. - */ -int -crypto_dh_get_bytes(crypto_dh_t *dh) -{ - tor_assert(dh); - return DH_size(dh->dh); -} - -/** Generate \<x,g^x\> for our part of the key exchange. Return 0 on - * success, -1 on failure. - */ -int -crypto_dh_generate_public(crypto_dh_t *dh) -{ -#ifndef OPENSSL_1_1_API - again: -#endif - if (!DH_generate_key(dh->dh)) { - /* LCOV_EXCL_START - * To test this we would need some way to tell openssl to break DH. */ - crypto_log_errors(LOG_WARN, "generating DH key"); - return -1; - /* LCOV_EXCL_STOP */ - } -#ifdef OPENSSL_1_1_API - /* OpenSSL 1.1.x doesn't appear to let you regenerate a DH key, without - * recreating the DH object. I have no idea what sort of aliasing madness - * can occur here, so do the check, and just bail on failure. - */ - const BIGNUM *pub_key, *priv_key; - DH_get0_key(dh->dh, &pub_key, &priv_key); - if (tor_check_dh_key(LOG_WARN, pub_key)<0) { - log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" - "the-universe chances really do happen. Treating as a failure."); - return -1; - } -#else /* !(defined(OPENSSL_1_1_API)) */ - if (tor_check_dh_key(LOG_WARN, dh->dh->pub_key)<0) { - /* LCOV_EXCL_START - * If this happens, then openssl's DH implementation is busted. */ - log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" - "the-universe chances really do happen. Trying again."); - /* Free and clear the keys, so OpenSSL will actually try again. */ - BN_clear_free(dh->dh->pub_key); - BN_clear_free(dh->dh->priv_key); - dh->dh->pub_key = dh->dh->priv_key = NULL; - goto again; - /* LCOV_EXCL_STOP */ - } -#endif /* defined(OPENSSL_1_1_API) */ - return 0; -} - -/** Generate g^x as necessary, and write the g^x for the key exchange - * as a <b>pubkey_len</b>-byte value into <b>pubkey</b>. Return 0 on - * success, -1 on failure. <b>pubkey_len</b> must be \>= DH_BYTES. - */ -int -crypto_dh_get_public(crypto_dh_t *dh, char *pubkey, size_t pubkey_len) -{ - int bytes; - tor_assert(dh); - - const BIGNUM *dh_pub; - -#ifdef OPENSSL_1_1_API - const BIGNUM *dh_priv; - DH_get0_key(dh->dh, &dh_pub, &dh_priv); -#else - dh_pub = dh->dh->pub_key; -#endif /* defined(OPENSSL_1_1_API) */ - - if (!dh_pub) { - if (crypto_dh_generate_public(dh)<0) - return -1; - else { -#ifdef OPENSSL_1_1_API - DH_get0_key(dh->dh, &dh_pub, &dh_priv); -#else - dh_pub = dh->dh->pub_key; -#endif - } - } - - tor_assert(dh_pub); - bytes = BN_num_bytes(dh_pub); - tor_assert(bytes >= 0); - if (pubkey_len < (size_t)bytes) { - log_warn(LD_CRYPTO, - "Weird! pubkey_len (%d) was smaller than DH_BYTES (%d)", - (int) pubkey_len, bytes); - return -1; - } - - memset(pubkey, 0, pubkey_len); - BN_bn2bin(dh_pub, (unsigned char*)(pubkey+(pubkey_len-bytes))); - - return 0; -} - -/** Check for bad Diffie-Hellman public keys (g^x). Return 0 if the key is - * okay (in the subgroup [2,p-2]), or -1 if it's bad. - * See http://www.cl.cam.ac.uk/ftp/users/rja14/psandqs.ps.gz for some tips. - */ -static int -tor_check_dh_key(int severity, const BIGNUM *bn) -{ - BIGNUM *x; - char *s; - tor_assert(bn); - x = BN_new(); - tor_assert(x); - if (BUG(!dh_param_p)) - init_dh_param(); //LCOV_EXCL_LINE we already checked whether we did this. - BN_set_word(x, 1); - if (BN_cmp(bn,x)<=0) { - log_fn(severity, LD_CRYPTO, "DH key must be at least 2."); - goto err; - } - BN_copy(x,dh_param_p); - BN_sub_word(x, 1); - if (BN_cmp(bn,x)>=0) { - log_fn(severity, LD_CRYPTO, "DH key must be at most p-2."); - goto err; - } - BN_clear_free(x); - return 0; - err: - BN_clear_free(x); - s = BN_bn2hex(bn); - log_fn(severity, LD_CRYPTO, "Rejecting insecure DH key [%s]", s); - OPENSSL_free(s); - return -1; -} - -/** Given a DH key exchange object, and our peer's value of g^y (as a - * <b>pubkey_len</b>-byte value in <b>pubkey</b>) generate - * <b>secret_bytes_out</b> bytes of shared key material and write them - * to <b>secret_out</b>. Return the number of bytes generated on success, - * or -1 on failure. - * - * (We generate key material by computing - * SHA1( g^xy || "\x00" ) || SHA1( g^xy || "\x01" ) || ... - * where || is concatenation.) - */ -ssize_t -crypto_dh_compute_secret(int severity, crypto_dh_t *dh, - const char *pubkey, size_t pubkey_len, - char *secret_out, size_t secret_bytes_out) -{ - char *secret_tmp = NULL; - BIGNUM *pubkey_bn = NULL; - size_t secret_len=0, secret_tmp_len=0; - int result=0; - tor_assert(dh); - tor_assert(secret_bytes_out/DIGEST_LEN <= 255); - tor_assert(pubkey_len < INT_MAX); - - if (!(pubkey_bn = BN_bin2bn((const unsigned char*)pubkey, - (int)pubkey_len, NULL))) - goto error; - if (tor_check_dh_key(severity, pubkey_bn)<0) { - /* Check for invalid public keys. */ - log_fn(severity, LD_CRYPTO,"Rejected invalid g^x"); - goto error; - } - secret_tmp_len = crypto_dh_get_bytes(dh); - secret_tmp = tor_malloc(secret_tmp_len); - result = DH_compute_key((unsigned char*)secret_tmp, pubkey_bn, dh->dh); - if (result < 0) { - log_warn(LD_CRYPTO,"DH_compute_key() failed."); - goto error; - } - secret_len = result; - if (crypto_expand_key_material_TAP((uint8_t*)secret_tmp, secret_len, - (uint8_t*)secret_out, secret_bytes_out)<0) - goto error; - secret_len = secret_bytes_out; - - goto done; - error: - result = -1; - done: - crypto_log_errors(LOG_WARN, "completing DH handshake"); - if (pubkey_bn) - BN_clear_free(pubkey_bn); - if (secret_tmp) { - memwipe(secret_tmp, 0, secret_tmp_len); - tor_free(secret_tmp); - } - if (result < 0) - return result; - else - return secret_len; -} - -/** Given <b>key_in_len</b> bytes of negotiated randomness in <b>key_in</b> - * ("K"), expand it into <b>key_out_len</b> bytes of negotiated key material in - * <b>key_out</b> by taking the first <b>key_out_len</b> bytes of - * H(K | [00]) | H(K | [01]) | .... - * - * This is the key expansion algorithm used in the "TAP" circuit extension - * mechanism; it shouldn't be used for new protocols. - * - * Return 0 on success, -1 on failure. - */ -int -crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len, - uint8_t *key_out, size_t key_out_len) -{ - int i, r = -1; - uint8_t *cp, *tmp = tor_malloc(key_in_len+1); - uint8_t digest[DIGEST_LEN]; - - /* If we try to get more than this amount of key data, we'll repeat blocks.*/ - tor_assert(key_out_len <= DIGEST_LEN*256); - - memcpy(tmp, key_in, key_in_len); - for (cp = key_out, i=0; cp < key_out+key_out_len; - ++i, cp += DIGEST_LEN) { - tmp[key_in_len] = i; - if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1) < 0) - goto exit; - memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out))); - } - - r = 0; - exit: - memwipe(tmp, 0, key_in_len+1); - tor_free(tmp); - memwipe(digest, 0, sizeof(digest)); - return r; -} - -/** Expand some secret key material according to RFC5869, using SHA256 as the - * underlying hash. The <b>key_in_len</b> bytes at <b>key_in</b> are the - * secret key material; the <b>salt_in_len</b> bytes at <b>salt_in</b> and the - * <b>info_in_len</b> bytes in <b>info_in_len</b> are the algorithm's "salt" - * and "info" parameters respectively. On success, write <b>key_out_len</b> - * bytes to <b>key_out</b> and return 0. Assert on failure. - */ -int -crypto_expand_key_material_rfc5869_sha256( - const uint8_t *key_in, size_t key_in_len, - const uint8_t *salt_in, size_t salt_in_len, - const uint8_t *info_in, size_t info_in_len, - uint8_t *key_out, size_t key_out_len) -{ - uint8_t prk[DIGEST256_LEN]; - uint8_t tmp[DIGEST256_LEN + 128 + 1]; - uint8_t mac[DIGEST256_LEN]; - int i; - uint8_t *outp; - size_t tmp_len; - - crypto_hmac_sha256((char*)prk, - (const char*)salt_in, salt_in_len, - (const char*)key_in, key_in_len); - - /* If we try to get more than this amount of key data, we'll repeat blocks.*/ - tor_assert(key_out_len <= DIGEST256_LEN * 256); - tor_assert(info_in_len <= 128); - memset(tmp, 0, sizeof(tmp)); - outp = key_out; - i = 1; - - while (key_out_len) { - size_t n; - if (i > 1) { - memcpy(tmp, mac, DIGEST256_LEN); - memcpy(tmp+DIGEST256_LEN, info_in, info_in_len); - tmp[DIGEST256_LEN+info_in_len] = i; - tmp_len = DIGEST256_LEN + info_in_len + 1; - } else { - memcpy(tmp, info_in, info_in_len); - tmp[info_in_len] = i; - tmp_len = info_in_len + 1; - } - crypto_hmac_sha256((char*)mac, - (const char*)prk, DIGEST256_LEN, - (const char*)tmp, tmp_len); - n = key_out_len < DIGEST256_LEN ? key_out_len : DIGEST256_LEN; - memcpy(outp, mac, n); - key_out_len -= n; - outp += n; - ++i; - } - - memwipe(tmp, 0, sizeof(tmp)); - memwipe(mac, 0, sizeof(mac)); - return 0; -} - -/** Free a DH key exchange object. - */ -void -crypto_dh_free_(crypto_dh_t *dh) -{ - if (!dh) - return; - tor_assert(dh->dh); - DH_free(dh->dh); - tor_free(dh); -} - -/** @{ */ -/** Uninitialize the crypto library. Return 0 on success. Does not detect - * failure. - */ -int -crypto_global_cleanup(void) -{ -#ifndef OPENSSL_1_1_API - EVP_cleanup(); -#endif -#ifndef NEW_THREAD_API - ERR_remove_thread_state(NULL); -#endif -#ifndef OPENSSL_1_1_API - ERR_free_strings(); -#endif - - if (dh_param_p) - BN_clear_free(dh_param_p); - if (dh_param_p_tls) - BN_clear_free(dh_param_p_tls); - if (dh_param_g) - BN_clear_free(dh_param_g); - - dh_param_p = dh_param_p_tls = dh_param_g = NULL; - -#ifndef DISABLE_ENGINES -#ifndef OPENSSL_1_1_API - ENGINE_cleanup(); -#endif -#endif - - CONF_modules_unload(1); -#ifndef OPENSSL_1_1_API - CRYPTO_cleanup_all_ex_data(); -#endif - - crypto_openssl_free_all(); - - crypto_early_initialized_ = 0; - crypto_global_initialized_ = 0; - have_seeded_siphash = 0; - siphash_unset_global_key(); - - return 0; -} - -/** @} */ - -#ifdef USE_DMALLOC -/** Tell the crypto library to use Tor's allocation functions rather than - * calling libc's allocation functions directly. Return 0 on success, -1 - * on failure. */ -int -crypto_use_tor_alloc_functions(void) -{ - int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_); - return r ? 0 : -1; -} -#endif /* defined(USE_DMALLOC) */ - diff --git a/src/common/handles.h b/src/common/handles.h index aef8cd89ef..21ec0dfeec 100644 --- a/src/common/handles.h +++ b/src/common/handles.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -50,8 +50,9 @@ #define TOR_HANDLE_H #include "orconfig.h" -#include "tor_queue.h" -#include "util.h" + +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" #define HANDLE_ENTRY(name, structname) \ struct name ## _handle_head_t *handle_head @@ -150,4 +151,3 @@ } #endif /* !defined(TOR_HANDLE_H) */ - diff --git a/src/common/include.am b/src/common/include.am index cfaf993674..7427c69445 100644 --- a/src/common/include.am +++ b/src/common/include.am @@ -1,136 +1,31 @@ noinst_LIBRARIES += \ src/common/libor.a \ - src/common/libor-ctime.a \ - src/common/libor-crypto.a \ src/common/libor-event.a if UNITTESTS_ENABLED noinst_LIBRARIES += \ src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-crypto-testing.a \ src/common/libor-event-testing.a endif EXTRA_DIST += src/common/Makefile.nmake -#CFLAGS = -Wall -Wpointer-arith -O2 -AM_CPPFLAGS += -I$(srcdir)/src/common -Isrc/common -I$(srcdir)/src/ext/trunnel -I$(srcdir)/src/trunnel - if USE_OPENBSD_MALLOC libor_extra_source=src/ext/OpenBSD_malloc_Linux.c else libor_extra_source= endif -src_common_libcurve25519_donna_a_CFLAGS= - -if BUILD_CURVE25519_DONNA -src_common_libcurve25519_donna_a_SOURCES=\ - src/ext/curve25519_donna/curve25519-donna.c -# See bug 13538 -- this code is known to have signed overflow issues. -src_common_libcurve25519_donna_a_CFLAGS+=\ - @F_OMIT_FRAME_POINTER@ @CFLAGS_CONSTTIME@ -noinst_LIBRARIES+=src/common/libcurve25519_donna.a -LIBDONNA=src/common/libcurve25519_donna.a -else -if BUILD_CURVE25519_DONNA_C64 -src_common_libcurve25519_donna_a_CFLAGS+=@CFLAGS_CONSTTIME@ -src_common_libcurve25519_donna_a_SOURCES=\ - src/ext/curve25519_donna/curve25519-donna-c64.c -noinst_LIBRARIES+=src/common/libcurve25519_donna.a -LIBDONNA=src/common/libcurve25519_donna.a -else -LIBDONNA= -endif -endif - -LIBDONNA += $(LIBED25519_REF10) -LIBDONNA += $(LIBED25519_DONNA) - -if THREADS_PTHREADS -threads_impl_source=src/common/compat_pthreads.c -endif -if THREADS_WIN32 -threads_impl_source=src/common/compat_winthreads.c -endif - -if BUILD_READPASSPHRASE_C -readpassphrase_source=src/ext/readpassphrase.c -else -readpassphrase_source= -endif - -if ADD_MULODI4 -mulodi4_source=src/ext/mulodi/mulodi4.c -else -mulodi4_source= -endif - -LIBOR_CTIME_A_SRC = \ - $(mulodi4_source) \ - src/ext/csiphash.c \ - src/common/di_ops.c - -src_common_libor_ctime_a_SOURCES = $(LIBOR_CTIME_A_SRC) -if UNITTESTS_ENABLED -src_common_libor_ctime_testing_a_SOURCES = $(LIBOR_CTIME_A_SRC) -else -src_common_libor_ctime_testing_a_SOURCES = -endif -src_common_libor_ctime_a_CFLAGS = @CFLAGS_CONSTTIME@ -src_common_libor_ctime_testing_a_CFLAGS = @CFLAGS_CONSTTIME@ $(TEST_CFLAGS) - LIBOR_A_SRC = \ - src/common/address.c \ src/common/address_set.c \ - src/common/backtrace.c \ - src/common/buffers.c \ - src/common/compat.c \ - src/common/compat_threads.c \ - src/common/compat_time.c \ - src/common/confline.c \ - src/common/container.c \ - src/common/log.c \ - src/common/memarea.c \ - src/common/pubsub.c \ - src/common/util.c \ - src/common/util_bug.c \ - src/common/util_format.c \ - src/common/util_process.c \ - src/common/sandbox.c \ - src/common/storagedir.c \ src/common/token_bucket.c \ src/common/workqueue.c \ - $(libor_extra_source) \ - $(threads_impl_source) \ - $(readpassphrase_source) + $(libor_extra_source) src/common/src_common_libor_testing_a-log.$(OBJEXT) \ src/common/log.$(OBJEXT): micro-revision.i -LIBOR_CRYPTO_A_SRC = \ - src/common/aes.c \ - src/common/buffers_tls.c \ - src/common/compress.c \ - src/common/compress_lzma.c \ - src/common/compress_none.c \ - src/common/compress_zlib.c \ - src/common/compress_zstd.c \ - src/common/crypto.c \ - src/common/crypto_digest.c \ - src/common/crypto_format.c \ - src/common/crypto_openssl_mgt.c \ - src/common/crypto_pwbox.c \ - src/common/crypto_rand.c \ - src/common/crypto_rsa.c \ - src/common/crypto_s2k.c \ - src/common/crypto_util.c \ - src/common/tortls.c \ - src/common/crypto_curve25519.c \ - src/common/crypto_ed25519.c - LIBOR_EVENT_A_SRC = \ src/common/compat_libevent.c \ src/common/procmon.c \ @@ -138,76 +33,30 @@ LIBOR_EVENT_A_SRC = \ src/ext/timeouts/timeout.c src_common_libor_a_SOURCES = $(LIBOR_A_SRC) -src_common_libor_crypto_a_SOURCES = $(LIBOR_CRYPTO_A_SRC) src_common_libor_event_a_SOURCES = $(LIBOR_EVENT_A_SRC) if UNITTESTS_ENABLED src_common_libor_testing_a_SOURCES = $(LIBOR_A_SRC) -src_common_libor_crypto_testing_a_SOURCES = $(LIBOR_CRYPTO_A_SRC) src_common_libor_event_testing_a_SOURCES = $(LIBOR_EVENT_A_SRC) else src_common_libor_testing_a_SOURCES = -src_common_libor_crypto_testing_a_SOURCES = src_common_libor_event_testing_a_SOURCES = endif src_common_libor_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) -src_common_libor_crypto_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_common_libor_event_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_common_libor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) -src_common_libor_crypto_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) COMMONHEADERS = \ - src/common/address.h \ src/common/address_set.h \ - src/common/backtrace.h \ - src/common/buffers.h \ - src/common/buffers_tls.h \ - src/common/aes.h \ - src/common/ciphers.inc \ - src/common/compat.h \ src/common/compat_libevent.h \ - src/common/compat_openssl.h \ - src/common/compat_threads.h \ - src/common/compat_time.h \ - src/common/compress.h \ - src/common/compress_lzma.h \ - src/common/compress_none.h \ - src/common/compress_zlib.h \ - src/common/compress_zstd.h \ - src/common/confline.h \ - src/common/container.h \ - src/common/crypto.h \ - src/common/crypto_digest.h \ - src/common/crypto_curve25519.h \ - src/common/crypto_ed25519.h \ - src/common/crypto_format.h \ - src/common/crypto_openssl_mgt.h \ - src/common/crypto_pwbox.h \ - src/common/crypto_rand.h \ - src/common/crypto_rsa.h \ - src/common/crypto_s2k.h \ - src/common/crypto_util.h \ - src/common/di_ops.h \ src/common/handles.h \ - src/common/memarea.h \ - src/common/linux_syscalls.inc \ src/common/procmon.h \ - src/common/pubsub.h \ - src/common/sandbox.h \ - src/common/storagedir.h \ - src/common/testsupport.h \ + src/common/socks5_status.h \ src/common/timers.h \ src/common/token_bucket.h \ - src/common/torint.h \ - src/common/torlog.h \ - src/common/tortls.h \ src/common/util.h \ - src/common/util_bug.h \ - src/common/util_format.h \ - src/common/util_process.h \ src/common/workqueue.h noinst_HEADERS+= $(COMMONHEADERS) - diff --git a/src/common/procmon.c b/src/common/procmon.c index 73c14cd584..c1bee041f8 100644 --- a/src/common/procmon.c +++ b/src/common/procmon.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ +/* Copyright (c) 2011-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,9 +6,13 @@ * \brief Process-termination monitor functions **/ -#include "procmon.h" +#include "common/procmon.h" -#include "util.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/log/win32err.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/parse_int.h" #ifdef HAVE_SIGNAL_H #include <signal.h> @@ -329,4 +333,3 @@ tor_process_monitor_free_(tor_process_monitor_t *procmon) tor_free(procmon); } - diff --git a/src/common/procmon.h b/src/common/procmon.h index 63777e4111..b8daeed0db 100644 --- a/src/common/procmon.h +++ b/src/common/procmon.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ +/* Copyright (c) 2011-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,10 +9,9 @@ #ifndef TOR_PROCMON_H #define TOR_PROCMON_H -#include "compat.h" -#include "compat_libevent.h" +#include "common/compat_libevent.h" -#include "torlog.h" +#include "lib/log/torlog.h" typedef struct tor_process_monitor_t tor_process_monitor_t; diff --git a/src/common/pubsub.c b/src/common/pubsub.c deleted file mode 100644 index 336e8a6e7f..0000000000 --- a/src/common/pubsub.c +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file pubsub.c - * - * \brief DOCDOC - */ - -#include "orconfig.h" -#include "pubsub.h" -#include "container.h" - -/** Helper: insert <b>s</b> into <b>topic's</b> list of subscribers, keeping - * them sorted in priority order. */ -static void -subscriber_insert(pubsub_topic_t *topic, pubsub_subscriber_t *s) -{ - int i; - smartlist_t *sl = topic->subscribers; - for (i = 0; i < smartlist_len(sl); ++i) { - pubsub_subscriber_t *other = smartlist_get(sl, i); - if (s->priority < other->priority) { - break; - } - } - smartlist_insert(sl, i, s); -} - -/** - * Add a new subscriber to <b>topic</b>, where (when an event is triggered), - * we'll notify the function <b>fn</b> by passing it <b>subscriber_data</b>. - * Return a handle to the subscribe which can later be passed to - * pubsub_unsubscribe_(). - * - * Functions are called in priority order, from lowest to highest. - * - * See pubsub.h for <b>subscribe_flags</b>. - */ -const pubsub_subscriber_t * -pubsub_subscribe_(pubsub_topic_t *topic, - pubsub_subscriber_fn_t fn, - void *subscriber_data, - unsigned subscribe_flags, - unsigned priority) -{ - tor_assert(! topic->locked); - if (subscribe_flags & SUBSCRIBE_ATSTART) { - tor_assert(topic->n_events_fired == 0); - } - pubsub_subscriber_t *r = tor_malloc_zero(sizeof(*r)); - r->priority = priority; - r->subscriber_flags = subscribe_flags; - r->fn = fn; - r->subscriber_data = subscriber_data; - if (topic->subscribers == NULL) { - topic->subscribers = smartlist_new(); - } - subscriber_insert(topic, r); - return r; -} - -/** - * Remove the subscriber <b>s</b> from <b>topic</b>. After calling this - * function, <b>s</b> may no longer be used. - */ -int -pubsub_unsubscribe_(pubsub_topic_t *topic, - const pubsub_subscriber_t *s) -{ - tor_assert(! topic->locked); - smartlist_t *sl = topic->subscribers; - if (sl == NULL) - return -1; - int i = smartlist_pos(sl, s); - if (i == -1) - return -1; - pubsub_subscriber_t *tmp = smartlist_get(sl, i); - tor_assert(tmp == s); - smartlist_del_keeporder(sl, i); - tor_free(tmp); - return 0; -} - -/** - * For every subscriber s in <b>topic</b>, invoke notify_fn on s and - * event_data. Return 0 if there were no nonzero return values, and -1 if - * there were any. - */ -int -pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn, - void *event_data, unsigned notify_flags) -{ - tor_assert(! topic->locked); - (void) notify_flags; - smartlist_t *sl = topic->subscribers; - int n_bad = 0; - ++topic->n_events_fired; - if (sl == NULL) - return -1; - topic->locked = 1; - SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) { - int r = notify_fn(s, event_data); - if (r != 0) - ++n_bad; - } SMARTLIST_FOREACH_END(s); - topic->locked = 0; - return (n_bad == 0) ? 0 : -1; -} - -/** - * Release all storage held by <b>topic</b>. - */ -void -pubsub_clear_(pubsub_topic_t *topic) -{ - tor_assert(! topic->locked); - - smartlist_t *sl = topic->subscribers; - if (sl == NULL) - return; - SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) { - tor_free(s); - } SMARTLIST_FOREACH_END(s); - smartlist_free(sl); - topic->subscribers = NULL; - topic->n_events_fired = 0; -} - diff --git a/src/common/pubsub.h b/src/common/pubsub.h deleted file mode 100644 index 2bee3af085..0000000000 --- a/src/common/pubsub.h +++ /dev/null @@ -1,179 +0,0 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file pubsub.h - * \brief Macros to implement publish/subscribe abstractions. - * - * To use these macros, call DECLARE_PUBSUB_TOPIC() with an identifier to use - * as your topic. Below, I'm going to assume you say DECLARE_PUBSUB_TOPIC(T). - * - * Doing this will declare the following types: - * typedef struct T_event_data_t T_event_data_t; // you define this struct - * typedef struct T_subscriber_data_t T_subscriber_data_t; // this one too. - * typedef struct T_subscriber_t T_subscriber_t; // opaque - * typedef int (*T_subscriber_fn_t)(T_event_data_t*, T_subscriber_data_t*); - * - * and it will declare the following functions: - * const T_subscriber_t *T_subscribe(T_subscriber_fn_t, - * T_subscriber_data_t *, - * unsigned flags, - * unsigned priority); - * int T_unsubscribe(const T_subscriber_t *) - * - * Elsewhere you can say DECLARE_NOTIFY_PUBSUB_TOPIC(static, T), which - * declares: - * - * static int T_notify(T_event_data_t *, unsigned notify_flags); - * static void T_clear(void); - * - * And in some C file, you would define these functions with: - * IMPLEMENT_PUBSUB_TOPIC(static, T). - * - * The implementations will be small typesafe wrappers over generic versions - * of the above functions. - * - * To use the typesafe functions, you add any number of subscribers with - * T_subscribe(). Each has an associated function pointer, data pointer, - * and priority. Later, you can invoke T_notify() to declare that the - * event has occurred. Each of the subscribers will be invoked once. - **/ - -#ifndef TOR_PUBSUB_H -#define TOR_PUBSUB_H - -#include "torint.h" - -/** - * Flag for T_subscribe: die with an assertion failure if the event - * have ever been published before. Used when a subscriber must absolutely - * never have missed an event. - */ -#define SUBSCRIBE_ATSTART (1u<<0) - -#define DECLARE_PUBSUB_STRUCT_TYPES(name) \ - /* You define this type. */ \ - typedef struct name ## _event_data_t name ## _event_data_t; \ - /* You define this type. */ \ - typedef struct name ## _subscriber_data_t name ## _subscriber_data_t; - -#define DECLARE_PUBSUB_TOPIC(name) \ - /* This type is opaque. */ \ - typedef struct name ## _subscriber_t name ## _subscriber_t; \ - /* You declare functions matching this type. */ \ - typedef int (*name ## _subscriber_fn_t)( \ - name ## _event_data_t *data, \ - name ## _subscriber_data_t *extra); \ - /* Call this function to subscribe to a topic. */ \ - const name ## _subscriber_t *name ## _subscribe( \ - name##_subscriber_fn_t subscriber, \ - name##_subscriber_data_t *extra_data, \ - unsigned flags, \ - unsigned priority); \ - /* Call this function to unsubscribe from a topic. */ \ - int name ## _unsubscribe(const name##_subscriber_t *s); - -#define DECLARE_NOTIFY_PUBSUB_TOPIC(linkage, name) \ - /* Call this function to notify all subscribers. Flags not yet used. */ \ - linkage int name ## _notify(name ## _event_data_t *data, unsigned flags); \ - /* Call this function to release storage held by the topic. */ \ - linkage void name ## _clear(void); - -/** - * Type used to hold a generic function for a subscriber. - * - * [Yes, it is safe to cast to this, so long as we cast back to the original - * type before calling. From C99: "A pointer to a function of one type may be - * converted to a pointer to a function of another type and back again; the - * result shall compare equal to the original pointer."] -*/ -typedef int (*pubsub_subscriber_fn_t)(void *, void *); - -/** - * Helper type to implement pubsub abstraction. Don't use this directly. - * It represents a subscriber. - */ -typedef struct pubsub_subscriber_t { - /** Function to invoke when the event triggers. */ - pubsub_subscriber_fn_t fn; - /** Data associated with this subscriber. */ - void *subscriber_data; - /** Priority for this subscriber. Low priorities happen first. */ - unsigned priority; - /** Flags set on this subscriber. Not yet used.*/ - unsigned subscriber_flags; -} pubsub_subscriber_t; - -/** - * Helper type to implement pubsub abstraction. Don't use this directly. - * It represents a topic, and keeps a record of subscribers. - */ -typedef struct pubsub_topic_t { - /** List of subscribers to this topic. May be NULL. */ - struct smartlist_t *subscribers; - /** Total number of times that pubsub_notify_() has ever been called on this - * topic. */ - uint64_t n_events_fired; - /** True iff we're running 'notify' on this topic, and shouldn't allow - * any concurrent modifications or events. */ - unsigned locked; -} pubsub_topic_t; - -const pubsub_subscriber_t *pubsub_subscribe_(pubsub_topic_t *topic, - pubsub_subscriber_fn_t fn, - void *subscriber_data, - unsigned subscribe_flags, - unsigned priority); -int pubsub_unsubscribe_(pubsub_topic_t *topic, const pubsub_subscriber_t *sub); -void pubsub_clear_(pubsub_topic_t *topic); -typedef int (*pubsub_notify_fn_t)(pubsub_subscriber_t *subscriber, - void *notify_data); -int pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn, - void *notify_data, unsigned notify_flags); - -#define IMPLEMENT_PUBSUB_TOPIC(notify_linkage, name) \ - static pubsub_topic_t name ## _topic_ = { NULL, 0, 0 }; \ - const name ## _subscriber_t * \ - name ## _subscribe(name##_subscriber_fn_t subscriber, \ - name##_subscriber_data_t *extra_data, \ - unsigned flags, \ - unsigned priority) \ - { \ - const pubsub_subscriber_t *s; \ - s = pubsub_subscribe_(&name##_topic_, \ - (pubsub_subscriber_fn_t)subscriber, \ - extra_data, \ - flags, \ - priority); \ - return (const name##_subscriber_t *)s; \ - } \ - int \ - name ## _unsubscribe(const name##_subscriber_t *subscriber) \ - { \ - return pubsub_unsubscribe_(&name##_topic_, \ - (const pubsub_subscriber_t *)subscriber); \ - } \ - static int \ - name##_call_the_notify_fn_(pubsub_subscriber_t *subscriber, \ - void *notify_data) \ - { \ - name ## _subscriber_fn_t fn; \ - fn = (name ## _subscriber_fn_t) subscriber->fn; \ - return fn(notify_data, subscriber->subscriber_data); \ - } \ - notify_linkage int \ - name ## _notify(name ## _event_data_t *event_data, unsigned flags) \ - { \ - return pubsub_notify_(&name##_topic_, \ - name##_call_the_notify_fn_, \ - event_data, \ - flags); \ - } \ - notify_linkage void \ - name ## _clear(void) \ - { \ - pubsub_clear_(&name##_topic_); \ - } - -#endif /* !defined(TOR_PUBSUB_H) */ - diff --git a/src/common/socks5_status.h b/src/common/socks5_status.h new file mode 100644 index 0000000000..74b9c91023 --- /dev/null +++ b/src/common/socks5_status.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SOCKS5_STATUS_H +#define TOR_SOCKS5_STATUS_H + +/** Specified SOCKS5 status codes. */ +typedef enum { + SOCKS5_SUCCEEDED = 0x00, + SOCKS5_GENERAL_ERROR = 0x01, + SOCKS5_NOT_ALLOWED = 0x02, + SOCKS5_NET_UNREACHABLE = 0x03, + SOCKS5_HOST_UNREACHABLE = 0x04, + SOCKS5_CONNECTION_REFUSED = 0x05, + SOCKS5_TTL_EXPIRED = 0x06, + SOCKS5_COMMAND_NOT_SUPPORTED = 0x07, + SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08, +} socks5_reply_status_t; + +#endif diff --git a/src/common/timers.c b/src/common/timers.c index 6f6236ed3b..ff92a2e447 100644 --- a/src/common/timers.c +++ b/src/common/timers.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -31,11 +31,18 @@ #define TOR_TIMERS_PRIVATE -#include "compat.h" -#include "compat_libevent.h" -#include "timers.h" -#include "torlog.h" -#include "util.h" +#include "common/compat_libevent.h" +#include "common/timers.h" +#include "lib/intmath/muldiv.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/time/compat_time.h" + +#ifdef _WIN32 +// For struct timeval. +#include <winsock2.h> +#endif struct timeout_cb { timer_cb_fn_t cb; @@ -315,4 +322,3 @@ timer_disable(tor_timer_t *t) /* We don't reschedule the libevent timer here, since it's okay if it fires * early. */ } - diff --git a/src/common/timers.h b/src/common/timers.h index 6d27f3e01e..2348c7b7c1 100644 --- a/src/common/timers.h +++ b/src/common/timers.h @@ -1,11 +1,11 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TIMERS_H #define TOR_TIMERS_H #include "orconfig.h" -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" struct monotime_t; typedef struct timeout tor_timer_t; diff --git a/src/common/token_bucket.c b/src/common/token_bucket.c index f2396ec58a..f7b092f612 100644 --- a/src/common/token_bucket.c +++ b/src/common/token_bucket.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -18,8 +18,12 @@ #define TOKEN_BUCKET_PRIVATE -#include "token_bucket.h" -#include "util_bug.h" +#include "common/token_bucket.h" +#include "lib/log/util_bug.h" +#include "lib/intmath/cmp.h" +#include "lib/time/compat_time.h" + +#include <string.h> /** * Set the <b>rate</b> and <b>burst</b> value in a token_bucket_cfg. @@ -252,4 +256,3 @@ token_bucket_rw_dec(token_bucket_rw_t *bucket, flags |= TB_WRITE; return flags; } - diff --git a/src/common/token_bucket.h b/src/common/token_bucket.h index 0e7832e838..787317fa1f 100644 --- a/src/common/token_bucket.h +++ b/src/common/token_bucket.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,8 @@ #ifndef TOR_TOKEN_BUCKET_H #define TOR_TOKEN_BUCKET_H -#include "torint.h" -#include "testsupport.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" /** Largest allowable burst value for a token buffer. */ #define TOKEN_BUCKET_MAX_BURST INT32_MAX diff --git a/src/common/util.c b/src/common/util.c deleted file mode 100644 index dece5877f1..0000000000 --- a/src/common/util.c +++ /dev/null @@ -1,5378 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file util.c - * \brief Common functions for strings, IO, network, data structures, - * process control. - **/ - -#include "orconfig.h" -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#define UTIL_PRIVATE -#include "util.h" -#include "torlog.h" -#include "crypto_digest.h" -#include "torint.h" -#include "container.h" -#include "address.h" -#include "sandbox.h" -#include "backtrace.h" -#include "util_process.h" -#include "util_format.h" - -#ifdef _WIN32 -#include <io.h> -#include <direct.h> -#include <process.h> -#include <tchar.h> -#include <winbase.h> -#else /* !(defined(_WIN32)) */ -#include <dirent.h> -#include <pwd.h> -#include <grp.h> -#endif /* defined(_WIN32) */ - -/* math.h needs this on Linux */ -#ifndef _USE_ISOC99_ -#define _USE_ISOC99_ 1 -#endif -#include <math.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <signal.h> - -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_SYS_FCNTL_H -#include <sys/fcntl.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_MALLOC_MALLOC_H -#include <malloc/malloc.h> -#endif -#ifdef HAVE_MALLOC_H -#if !defined(OpenBSD) && !defined(__FreeBSD__) -/* OpenBSD has a malloc.h, but for our purposes, it only exists in order to - * scold us for being so stupid as to autodetect its presence. To be fair, - * they've done this since 1996, when autoconf was only 5 years old. */ -#include <malloc.h> -#endif /* !defined(OpenBSD) && !defined(__FreeBSD__) */ -#endif /* defined(HAVE_MALLOC_H) */ -#ifdef HAVE_MALLOC_NP_H -#include <malloc_np.h> -#endif -#ifdef HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) -#include <sys/prctl.h> -#endif - -#ifdef __clang_analyzer__ -#undef MALLOC_ZERO_WORKS -#endif - -/* ===== - * Memory management - * ===== */ -#ifdef USE_DMALLOC - #undef strndup - #include <dmalloc.h> - /* Macro to pass the extra dmalloc args to another function. */ - #define DMALLOC_FN_ARGS , file, line - - #if defined(HAVE_DMALLOC_STRDUP) - /* the dmalloc_strdup should be fine as defined */ - #elif defined(HAVE_DMALLOC_STRNDUP) - #define dmalloc_strdup(file, line, string, xalloc_b) \ - dmalloc_strndup(file, line, (string), -1, xalloc_b) - #else - #error "No dmalloc_strdup or equivalent" -#endif /* defined(HAVE_DMALLOC_STRDUP) || ... */ - -#else /* !(defined(USE_DMALLOC)) */ - - #define DMALLOC_FN_ARGS -#endif /* defined(USE_DMALLOC) */ - -/** Allocate a chunk of <b>size</b> bytes of memory, and return a pointer to - * result. On error, log and terminate the process. (Same as malloc(size), - * but never returns NULL.) - * - * <b>file</b> and <b>line</b> are used if dmalloc is enabled, and - * ignored otherwise. - */ -void * -tor_malloc_(size_t size DMALLOC_PARAMS) -{ - void *result; - - tor_assert(size < SIZE_T_CEILING); - -#ifndef MALLOC_ZERO_WORKS - /* Some libc mallocs don't work when size==0. Override them. */ - if (size==0) { - size=1; - } -#endif /* !defined(MALLOC_ZERO_WORKS) */ - -#ifdef USE_DMALLOC - result = dmalloc_malloc(file, line, size, DMALLOC_FUNC_MALLOC, 0, 0); -#else - result = raw_malloc(size); -#endif - - if (PREDICT_UNLIKELY(result == NULL)) { - /* LCOV_EXCL_START */ - log_err(LD_MM,"Out of memory on malloc(). Dying."); - /* If these functions die within a worker process, they won't call - * spawn_exit, but that's ok, since the parent will run out of memory soon - * anyway. */ - exit(1); // exit ok: alloc failed. - /* LCOV_EXCL_STOP */ - } - return result; -} - -/** Allocate a chunk of <b>size</b> bytes of memory, fill the memory with - * zero bytes, and return a pointer to the result. Log and terminate - * the process on error. (Same as calloc(size,1), but never returns NULL.) - */ -void * -tor_malloc_zero_(size_t size DMALLOC_PARAMS) -{ - /* You may ask yourself, "wouldn't it be smart to use calloc instead of - * malloc+memset? Perhaps libc's calloc knows some nifty optimization trick - * we don't!" Indeed it does, but its optimizations are only a big win when - * we're allocating something very big (it knows if it just got the memory - * from the OS in a pre-zeroed state). We don't want to use tor_malloc_zero - * for big stuff, so we don't bother with calloc. */ - void *result = tor_malloc_(size DMALLOC_FN_ARGS); - memset(result, 0, size); - return result; -} - -/* The square root of SIZE_MAX + 1. If a is less than this, and b is less - * than this, then a*b is less than SIZE_MAX. (For example, if size_t is - * 32 bits, then SIZE_MAX is 0xffffffff and this value is 0x10000. If a and - * b are less than this, then their product is at most (65535*65535) == - * 0xfffe0001. */ -#define SQRT_SIZE_MAX_P1 (((size_t)1) << (sizeof(size_t)*4)) - -/** Return non-zero if and only if the product of the arguments is exact, - * and cannot overflow. */ -int -size_mul_check(const size_t x, const size_t y) -{ - /* This first check is equivalent to - (x < SQRT_SIZE_MAX_P1 && y < SQRT_SIZE_MAX_P1) - - Rationale: if either one of x or y is >= SQRT_SIZE_MAX_P1, then it - will have some bit set in its most significant half. - */ - return ((x|y) < SQRT_SIZE_MAX_P1 || - y == 0 || - x <= SIZE_MAX / y); -} - -/** Allocate a chunk of <b>nmemb</b>*<b>size</b> bytes of memory, fill - * the memory with zero bytes, and return a pointer to the result. - * Log and terminate the process on error. (Same as - * calloc(<b>nmemb</b>,<b>size</b>), but never returns NULL.) - * The second argument (<b>size</b>) should preferably be non-zero - * and a compile-time constant. - */ -void * -tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS) -{ - tor_assert(size_mul_check(nmemb, size)); - return tor_malloc_zero_((nmemb * size) DMALLOC_FN_ARGS); -} - -/** Change the size of the memory block pointed to by <b>ptr</b> to <b>size</b> - * bytes long; return the new memory block. On error, log and - * terminate. (Like realloc(ptr,size), but never returns NULL.) - */ -void * -tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS) -{ - void *result; - - tor_assert(size < SIZE_T_CEILING); - -#ifndef MALLOC_ZERO_WORKS - /* Some libc mallocs don't work when size==0. Override them. */ - if (size==0) { - size=1; - } -#endif /* !defined(MALLOC_ZERO_WORKS) */ - -#ifdef USE_DMALLOC - result = dmalloc_realloc(file, line, ptr, size, DMALLOC_FUNC_REALLOC, 0); -#else - result = raw_realloc(ptr, size); -#endif - - if (PREDICT_UNLIKELY(result == NULL)) { - /* LCOV_EXCL_START */ - log_err(LD_MM,"Out of memory on realloc(). Dying."); - exit(1); // exit ok: alloc failed. - /* LCOV_EXCL_STOP */ - } - return result; -} - -/** - * Try to realloc <b>ptr</b> so that it takes up sz1 * sz2 bytes. Check for - * overflow. Unlike other allocation functions, return NULL on overflow. - */ -void * -tor_reallocarray_(void *ptr, size_t sz1, size_t sz2 DMALLOC_PARAMS) -{ - /* XXXX we can make this return 0, but we would need to check all the - * reallocarray users. */ - tor_assert(size_mul_check(sz1, sz2)); - - return tor_realloc(ptr, (sz1 * sz2) DMALLOC_FN_ARGS); -} - -/** Return a newly allocated copy of the NUL-terminated string s. On - * error, log and terminate. (Like strdup(s), but never returns - * NULL.) - */ -char * -tor_strdup_(const char *s DMALLOC_PARAMS) -{ - char *duplicate; - tor_assert(s); - -#ifdef USE_DMALLOC - duplicate = dmalloc_strdup(file, line, s, 0); -#else - duplicate = raw_strdup(s); -#endif - if (PREDICT_UNLIKELY(duplicate == NULL)) { - /* LCOV_EXCL_START */ - log_err(LD_MM,"Out of memory on strdup(). Dying."); - exit(1); // exit ok: alloc failed. - /* LCOV_EXCL_STOP */ - } - return duplicate; -} - -/** Allocate and return a new string containing the first <b>n</b> - * characters of <b>s</b>. If <b>s</b> is longer than <b>n</b> - * characters, only the first <b>n</b> are copied. The result is - * always NUL-terminated. (Like strndup(s,n), but never returns - * NULL.) - */ -char * -tor_strndup_(const char *s, size_t n DMALLOC_PARAMS) -{ - char *duplicate; - tor_assert(s); - tor_assert(n < SIZE_T_CEILING); - duplicate = tor_malloc_((n+1) DMALLOC_FN_ARGS); - /* Performance note: Ordinarily we prefer strlcpy to strncpy. But - * this function gets called a whole lot, and platform strncpy is - * much faster than strlcpy when strlen(s) is much longer than n. - */ - strncpy(duplicate, s, n); - duplicate[n]='\0'; - return duplicate; -} - -/** Allocate a chunk of <b>len</b> bytes, with the same contents as the - * <b>len</b> bytes starting at <b>mem</b>. */ -void * -tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS) -{ - char *duplicate; - tor_assert(len < SIZE_T_CEILING); - tor_assert(mem); - duplicate = tor_malloc_(len DMALLOC_FN_ARGS); - memcpy(duplicate, mem, len); - return duplicate; -} - -/** As tor_memdup(), but add an extra 0 byte at the end of the resulting - * memory. */ -void * -tor_memdup_nulterm_(const void *mem, size_t len DMALLOC_PARAMS) -{ - char *duplicate; - tor_assert(len < SIZE_T_CEILING+1); - tor_assert(mem); - duplicate = tor_malloc_(len+1 DMALLOC_FN_ARGS); - memcpy(duplicate, mem, len); - duplicate[len] = '\0'; - return duplicate; -} - -/** Helper for places that need to take a function pointer to the right - * spelling of "free()". */ -void -tor_free_(void *mem) -{ - tor_free(mem); -} - -DISABLE_GCC_WARNING(aggregate-return) -/** Call the platform malloc info function, and dump the results to the log at - * level <b>severity</b>. If no such function exists, do nothing. */ -void -tor_log_mallinfo(int severity) -{ -#ifdef HAVE_MALLINFO - struct mallinfo mi; - memset(&mi, 0, sizeof(mi)); - mi = mallinfo(); - tor_log(severity, LD_MM, - "mallinfo() said: arena=%d, ordblks=%d, smblks=%d, hblks=%d, " - "hblkhd=%d, usmblks=%d, fsmblks=%d, uordblks=%d, fordblks=%d, " - "keepcost=%d", - mi.arena, mi.ordblks, mi.smblks, mi.hblks, - mi.hblkhd, mi.usmblks, mi.fsmblks, mi.uordblks, mi.fordblks, - mi.keepcost); -#else /* !(defined(HAVE_MALLINFO)) */ - (void)severity; -#endif /* defined(HAVE_MALLINFO) */ -#ifdef USE_DMALLOC - dmalloc_log_changed(0, /* Since the program started. */ - 1, /* Log info about non-freed pointers. */ - 0, /* Do not log info about freed pointers. */ - 0 /* Do not log individual pointers. */ - ); -#endif /* defined(USE_DMALLOC) */ -} -ENABLE_GCC_WARNING(aggregate-return) - -/* ===== - * Math - * ===== */ - -/** - * Returns the natural logarithm of d base e. We defined this wrapper here so - * to avoid conflicts with old versions of tor_log(), which were named log(). - */ -double -tor_mathlog(double d) -{ - return log(d); -} - -/** Return the long integer closest to <b>d</b>. We define this wrapper - * here so that not all users of math.h need to use the right incantations - * to get the c99 functions. */ -long -tor_lround(double d) -{ -#if defined(HAVE_LROUND) - return lround(d); -#elif defined(HAVE_RINT) - return (long)rint(d); -#else - return (long)(d > 0 ? d + 0.5 : ceil(d - 0.5)); -#endif /* defined(HAVE_LROUND) || ... */ -} - -/** Return the 64-bit integer closest to d. We define this wrapper here so - * that not all users of math.h need to use the right incantations to get the - * c99 functions. */ -int64_t -tor_llround(double d) -{ -#if defined(HAVE_LLROUND) - return (int64_t)llround(d); -#elif defined(HAVE_RINT) - return (int64_t)rint(d); -#else - return (int64_t)(d > 0 ? d + 0.5 : ceil(d - 0.5)); -#endif /* defined(HAVE_LLROUND) || ... */ -} - -/** Returns floor(log2(u64)). If u64 is 0, (incorrectly) returns 0. */ -int -tor_log2(uint64_t u64) -{ - int r = 0; - if (u64 >= (U64_LITERAL(1)<<32)) { - u64 >>= 32; - r = 32; - } - if (u64 >= (U64_LITERAL(1)<<16)) { - u64 >>= 16; - r += 16; - } - if (u64 >= (U64_LITERAL(1)<<8)) { - u64 >>= 8; - r += 8; - } - if (u64 >= (U64_LITERAL(1)<<4)) { - u64 >>= 4; - r += 4; - } - if (u64 >= (U64_LITERAL(1)<<2)) { - u64 >>= 2; - r += 2; - } - if (u64 >= (U64_LITERAL(1)<<1)) { - // u64 >>= 1; // not using this any more. - r += 1; - } - return r; -} - -/** Return the power of 2 in range [1,UINT64_MAX] closest to <b>u64</b>. If - * there are two powers of 2 equally close, round down. */ -uint64_t -round_to_power_of_2(uint64_t u64) -{ - int lg2; - uint64_t low; - uint64_t high; - if (u64 == 0) - return 1; - - lg2 = tor_log2(u64); - low = U64_LITERAL(1) << lg2; - - if (lg2 == 63) - return low; - - high = U64_LITERAL(1) << (lg2+1); - if (high - u64 < u64 - low) - return high; - else - return low; -} - -/** Return the lowest x such that x is at least <b>number</b>, and x modulo - * <b>divisor</b> == 0. If no such x can be expressed as an unsigned, return - * UINT_MAX. Asserts if divisor is zero. */ -unsigned -round_to_next_multiple_of(unsigned number, unsigned divisor) -{ - tor_assert(divisor > 0); - if (UINT_MAX - divisor + 1 < number) - return UINT_MAX; - number += divisor - 1; - number -= number % divisor; - return number; -} - -/** Return the lowest x such that x is at least <b>number</b>, and x modulo - * <b>divisor</b> == 0. If no such x can be expressed as a uint32_t, return - * UINT32_MAX. Asserts if divisor is zero. */ -uint32_t -round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor) -{ - tor_assert(divisor > 0); - if (UINT32_MAX - divisor + 1 < number) - return UINT32_MAX; - - number += divisor - 1; - number -= number % divisor; - return number; -} - -/** Return the lowest x such that x is at least <b>number</b>, and x modulo - * <b>divisor</b> == 0. If no such x can be expressed as a uint64_t, return - * UINT64_MAX. Asserts if divisor is zero. */ -uint64_t -round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor) -{ - tor_assert(divisor > 0); - if (UINT64_MAX - divisor + 1 < number) - return UINT64_MAX; - number += divisor - 1; - number -= number % divisor; - return number; -} - -/** Transform a random value <b>p</b> from the uniform distribution in - * [0.0, 1.0[ into a Laplace distributed value with location parameter - * <b>mu</b> and scale parameter <b>b</b>. Truncate the final result - * to be an integer in [INT64_MIN, INT64_MAX]. */ -int64_t -sample_laplace_distribution(double mu, double b, double p) -{ - double result; - tor_assert(p >= 0.0 && p < 1.0); - - /* This is the "inverse cumulative distribution function" from: - * http://en.wikipedia.org/wiki/Laplace_distribution */ - if (p <= 0.0) { - /* Avoid taking log(0.0) == -INFINITY, as some processors or compiler - * options can cause the program to trap. */ - return INT64_MIN; - } - - result = mu - b * (p > 0.5 ? 1.0 : -1.0) - * tor_mathlog(1.0 - 2.0 * fabs(p - 0.5)); - - return clamp_double_to_int64(result); -} - -/** Add random noise between INT64_MIN and INT64_MAX coming from a Laplace - * distribution with mu = 0 and b = <b>delta_f</b>/<b>epsilon</b> to - * <b>signal</b> based on the provided <b>random</b> value in [0.0, 1.0[. - * The epsilon value must be between ]0.0, 1.0]. delta_f must be greater - * than 0. */ -int64_t -add_laplace_noise(int64_t signal_, double random_, double delta_f, - double epsilon) -{ - int64_t noise; - - /* epsilon MUST be between ]0.0, 1.0] */ - tor_assert(epsilon > 0.0 && epsilon <= 1.0); - /* delta_f MUST be greater than 0. */ - tor_assert(delta_f > 0.0); - - /* Just add noise, no further signal */ - noise = sample_laplace_distribution(0.0, - delta_f / epsilon, - random_); - - /* Clip (signal + noise) to [INT64_MIN, INT64_MAX] */ - if (noise > 0 && INT64_MAX - noise < signal_) - return INT64_MAX; - else if (noise < 0 && INT64_MIN - noise > signal_) - return INT64_MIN; - else - return signal_ + noise; -} - -/* Helper: safely add two uint32_t's, capping at UINT32_MAX rather - * than overflow */ -uint32_t -tor_add_u32_nowrap(uint32_t a, uint32_t b) -{ - /* a+b > UINT32_MAX check, without overflow */ - if (PREDICT_UNLIKELY(a > UINT32_MAX - b)) { - return UINT32_MAX; - } else { - return a+b; - } -} - -/* Helper: return greatest common divisor of a,b */ -static uint64_t -gcd64(uint64_t a, uint64_t b) -{ - while (b) { - uint64_t t = b; - b = a % b; - a = t; - } - return a; -} - -/* Given a fraction *<b>numer</b> / *<b>denom</b>, simplify it. - * Requires that the denominator is greater than 0. */ -void -simplify_fraction64(uint64_t *numer, uint64_t *denom) -{ - tor_assert(denom); - uint64_t gcd = gcd64(*numer, *denom); - *numer /= gcd; - *denom /= gcd; -} - -/** Return the number of bits set in <b>v</b>. */ -int -n_bits_set_u8(uint8_t v) -{ - static const int nybble_table[] = { - 0, /* 0000 */ - 1, /* 0001 */ - 1, /* 0010 */ - 2, /* 0011 */ - 1, /* 0100 */ - 2, /* 0101 */ - 2, /* 0110 */ - 3, /* 0111 */ - 1, /* 1000 */ - 2, /* 1001 */ - 2, /* 1010 */ - 3, /* 1011 */ - 2, /* 1100 */ - 3, /* 1101 */ - 3, /* 1110 */ - 4, /* 1111 */ - }; - - return nybble_table[v & 15] + nybble_table[v>>4]; -} - -/* ===== - * String manipulation - * ===== */ - -/** Remove from the string <b>s</b> every character which appears in - * <b>strip</b>. */ -void -tor_strstrip(char *s, const char *strip) -{ - char *readp = s; - while (*readp) { - if (strchr(strip, *readp)) { - ++readp; - } else { - *s++ = *readp++; - } - } - *s = '\0'; -} - -/** Return a pointer to a NUL-terminated hexadecimal string encoding - * the first <b>fromlen</b> bytes of <b>from</b>. (fromlen must be \<= 32.) The - * result does not need to be deallocated, but repeated calls to - * hex_str will trash old results. - */ -const char * -hex_str(const char *from, size_t fromlen) -{ - static char buf[65]; - if (fromlen>(sizeof(buf)-1)/2) - fromlen = (sizeof(buf)-1)/2; - base16_encode(buf,sizeof(buf),from,fromlen); - return buf; -} - -/** Convert all alphabetic characters in the nul-terminated string <b>s</b> to - * lowercase. */ -void -tor_strlower(char *s) -{ - while (*s) { - *s = TOR_TOLOWER(*s); - ++s; - } -} - -/** Convert all alphabetic characters in the nul-terminated string <b>s</b> to - * lowercase. */ -void -tor_strupper(char *s) -{ - while (*s) { - *s = TOR_TOUPPER(*s); - ++s; - } -} - -/** Return 1 if every character in <b>s</b> is printable, else return 0. - */ -int -tor_strisprint(const char *s) -{ - while (*s) { - if (!TOR_ISPRINT(*s)) - return 0; - s++; - } - return 1; -} - -/** Return 1 if no character in <b>s</b> is uppercase, else return 0. - */ -int -tor_strisnonupper(const char *s) -{ - while (*s) { - if (TOR_ISUPPER(*s)) - return 0; - s++; - } - return 1; -} - -/** Return true iff every character in <b>s</b> is whitespace space; else - * return false. */ -int -tor_strisspace(const char *s) -{ - while (*s) { - if (!TOR_ISSPACE(*s)) - return 0; - s++; - } - return 1; -} - -/** As strcmp, except that either string may be NULL. The NULL string is - * considered to be before any non-NULL string. */ -int -strcmp_opt(const char *s1, const char *s2) -{ - if (!s1) { - if (!s2) - return 0; - else - return -1; - } else if (!s2) { - return 1; - } else { - return strcmp(s1, s2); - } -} - -/** Compares the first strlen(s2) characters of s1 with s2. Returns as for - * strcmp. - */ -int -strcmpstart(const char *s1, const char *s2) -{ - size_t n = strlen(s2); - return strncmp(s1, s2, n); -} - -/** Compare the s1_len-byte string <b>s1</b> with <b>s2</b>, - * without depending on a terminating nul in s1. Sorting order is first by - * length, then lexically; return values are as for strcmp. - */ -int -strcmp_len(const char *s1, const char *s2, size_t s1_len) -{ - size_t s2_len = strlen(s2); - if (s1_len < s2_len) - return -1; - if (s1_len > s2_len) - return 1; - return fast_memcmp(s1, s2, s2_len); -} - -/** Compares the first strlen(s2) characters of s1 with s2. Returns as for - * strcasecmp. - */ -int -strcasecmpstart(const char *s1, const char *s2) -{ - size_t n = strlen(s2); - return strncasecmp(s1, s2, n); -} - -/** Compares the last strlen(s2) characters of s1 with s2. Returns as for - * strcmp. - */ -int -strcmpend(const char *s1, const char *s2) -{ - size_t n1 = strlen(s1), n2 = strlen(s2); - if (n2>n1) - return strcmp(s1,s2); - else - return strncmp(s1+(n1-n2), s2, n2); -} - -/** Compares the last strlen(s2) characters of s1 with s2. Returns as for - * strcasecmp. - */ -int -strcasecmpend(const char *s1, const char *s2) -{ - size_t n1 = strlen(s1), n2 = strlen(s2); - if (n2>n1) /* then they can't be the same; figure out which is bigger */ - return strcasecmp(s1,s2); - else - return strncasecmp(s1+(n1-n2), s2, n2); -} - -/** Compare the value of the string <b>prefix</b> with the start of the - * <b>memlen</b>-byte memory chunk at <b>mem</b>. Return as for strcmp. - * - * [As fast_memcmp(mem, prefix, strlen(prefix)) but returns -1 if memlen is - * less than strlen(prefix).] - */ -int -fast_memcmpstart(const void *mem, size_t memlen, - const char *prefix) -{ - size_t plen = strlen(prefix); - if (memlen < plen) - return -1; - return fast_memcmp(mem, prefix, plen); -} - -/** Return a pointer to the first char of s that is not whitespace and - * not a comment, or to the terminating NUL if no such character exists. - */ -const char * -eat_whitespace(const char *s) -{ - tor_assert(s); - - while (1) { - switch (*s) { - case '\0': - default: - return s; - case ' ': - case '\t': - case '\n': - case '\r': - ++s; - break; - case '#': - ++s; - while (*s && *s != '\n') - ++s; - } - } -} - -/** Return a pointer to the first char of s that is not whitespace and - * not a comment, or to the terminating NUL if no such character exists. - */ -const char * -eat_whitespace_eos(const char *s, const char *eos) -{ - tor_assert(s); - tor_assert(eos && s <= eos); - - while (s < eos) { - switch (*s) { - case '\0': - default: - return s; - case ' ': - case '\t': - case '\n': - case '\r': - ++s; - break; - case '#': - ++s; - while (s < eos && *s && *s != '\n') - ++s; - } - } - return s; -} - -/** Return a pointer to the first char of s that is not a space or a tab - * or a \\r, or to the terminating NUL if no such character exists. */ -const char * -eat_whitespace_no_nl(const char *s) -{ - while (*s == ' ' || *s == '\t' || *s == '\r') - ++s; - return s; -} - -/** As eat_whitespace_no_nl, but stop at <b>eos</b> whether we have - * found a non-whitespace character or not. */ -const char * -eat_whitespace_eos_no_nl(const char *s, const char *eos) -{ - while (s < eos && (*s == ' ' || *s == '\t' || *s == '\r')) - ++s; - return s; -} - -/** Return a pointer to the first char of s that is whitespace or <b>#</b>, - * or to the terminating NUL if no such character exists. - */ -const char * -find_whitespace(const char *s) -{ - /* tor_assert(s); */ - while (1) { - switch (*s) - { - case '\0': - case '#': - case ' ': - case '\r': - case '\n': - case '\t': - return s; - default: - ++s; - } - } -} - -/** As find_whitespace, but stop at <b>eos</b> whether we have found a - * whitespace or not. */ -const char * -find_whitespace_eos(const char *s, const char *eos) -{ - /* tor_assert(s); */ - while (s < eos) { - switch (*s) - { - case '\0': - case '#': - case ' ': - case '\r': - case '\n': - case '\t': - return s; - default: - ++s; - } - } - return s; -} - -/** Return the first occurrence of <b>needle</b> in <b>haystack</b> that - * occurs at the start of a line (that is, at the beginning of <b>haystack</b> - * or immediately after a newline). Return NULL if no such string is found. - */ -const char * -find_str_at_start_of_line(const char *haystack, const char *needle) -{ - size_t needle_len = strlen(needle); - - do { - if (!strncmp(haystack, needle, needle_len)) - return haystack; - - haystack = strchr(haystack, '\n'); - if (!haystack) - return NULL; - else - ++haystack; - } while (*haystack); - - return NULL; -} - -/** Returns true if <b>string</b> could be a C identifier. - A C identifier must begin with a letter or an underscore and the - rest of its characters can be letters, numbers or underscores. No - length limit is imposed. */ -int -string_is_C_identifier(const char *string) -{ - size_t iter; - size_t length = strlen(string); - if (!length) - return 0; - - for (iter = 0; iter < length ; iter++) { - if (iter == 0) { - if (!(TOR_ISALPHA(string[iter]) || - string[iter] == '_')) - return 0; - } else { - if (!(TOR_ISALPHA(string[iter]) || - TOR_ISDIGIT(string[iter]) || - string[iter] == '_')) - return 0; - } - } - - return 1; -} - -/** Return true iff the 'len' bytes at 'mem' are all zero. */ -int -tor_mem_is_zero(const char *mem, size_t len) -{ - static const char ZERO[] = { - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - }; - while (len >= sizeof(ZERO)) { - /* It's safe to use fast_memcmp here, since the very worst thing an - * attacker could learn is how many initial bytes of a secret were zero */ - if (fast_memcmp(mem, ZERO, sizeof(ZERO))) - return 0; - len -= sizeof(ZERO); - mem += sizeof(ZERO); - } - /* Deal with leftover bytes. */ - if (len) - return fast_memeq(mem, ZERO, len); - - return 1; -} - -/** Return true iff the DIGEST_LEN bytes in digest are all zero. */ -int -tor_digest_is_zero(const char *digest) -{ - static const uint8_t ZERO_DIGEST[] = { - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 - }; - return tor_memeq(digest, ZERO_DIGEST, DIGEST_LEN); -} - -/** Return true if <b>string</b> is a valid 'key=[value]' string. - * "value" is optional, to indicate the empty string. Log at logging - * <b>severity</b> if something ugly happens. */ -int -string_is_key_value(int severity, const char *string) -{ - /* position of equal sign in string */ - const char *equal_sign_pos = NULL; - - tor_assert(string); - - if (strlen(string) < 2) { /* "x=" is shortest args string */ - tor_log(severity, LD_GENERAL, "'%s' is too short to be a k=v value.", - escaped(string)); - return 0; - } - - equal_sign_pos = strchr(string, '='); - if (!equal_sign_pos) { - tor_log(severity, LD_GENERAL, "'%s' is not a k=v value.", escaped(string)); - return 0; - } - - /* validate that the '=' is not in the beginning of the string. */ - if (equal_sign_pos == string) { - tor_log(severity, LD_GENERAL, "'%s' is not a valid k=v value.", - escaped(string)); - return 0; - } - - return 1; -} - -/** Return true if <b>string</b> represents a valid IPv4 adddress in - * 'a.b.c.d' form. - */ -int -string_is_valid_ipv4_address(const char *string) -{ - struct in_addr addr; - - return (tor_inet_pton(AF_INET,string,&addr) == 1); -} - -/** Return true if <b>string</b> represents a valid IPv6 address in - * a form that inet_pton() can parse. - */ -int -string_is_valid_ipv6_address(const char *string) -{ - struct in6_addr addr; - - return (tor_inet_pton(AF_INET6,string,&addr) == 1); -} - -/** Return true iff <b>string</b> is a valid destination address, - * i.e. either a DNS hostname or IPv4/IPv6 address string. - */ -int -string_is_valid_dest(const char *string) -{ - char *tmp = NULL; - int retval; - size_t len; - - if (string == NULL) - return 0; - - len = strlen(string); - - if (len == 0) - return 0; - - if (string[0] == '[' && string[len - 1] == ']') - string = tmp = tor_strndup(string + 1, len - 2); - - retval = string_is_valid_ipv4_address(string) || - string_is_valid_ipv6_address(string) || - string_is_valid_nonrfc_hostname(string); - - tor_free(tmp); - - return retval; -} - -/** Return true iff <b>string</b> matches a pattern of DNS names - * that we allow Tor clients to connect to. - * - * Note: This allows certain technically invalid characters ('_') to cope - * with misconfigured zones that have been encountered in the wild. - */ -int -string_is_valid_nonrfc_hostname(const char *string) -{ - int result = 1; - int has_trailing_dot; - char *last_label; - smartlist_t *components; - - if (!string || strlen(string) == 0) - return 0; - - if (string_is_valid_ipv4_address(string)) - return 0; - - components = smartlist_new(); - - smartlist_split_string(components,string,".",0,0); - - if (BUG(smartlist_len(components) == 0)) - return 0; // LCOV_EXCL_LINE should be impossible given the earlier checks. - - /* Allow a single terminating '.' used rarely to indicate domains - * are FQDNs rather than relative. */ - last_label = (char *)smartlist_get(components, - smartlist_len(components) - 1); - has_trailing_dot = (last_label[0] == '\0'); - if (has_trailing_dot) { - smartlist_pop_last(components); - tor_free(last_label); - last_label = NULL; - } - - SMARTLIST_FOREACH_BEGIN(components, char *, c) { - if ((c[0] == '-') || (*c == '_')) { - result = 0; - break; - } - - do { - result = (TOR_ISALNUM(*c) || (*c == '-') || (*c == '_')); - c++; - } while (result && *c); - - if (result == 0) { - break; - } - } SMARTLIST_FOREACH_END(c); - - SMARTLIST_FOREACH_BEGIN(components, char *, c) { - tor_free(c); - } SMARTLIST_FOREACH_END(c); - - smartlist_free(components); - - return result; -} - -/** Return true iff the DIGEST256_LEN bytes in digest are all zero. */ -int -tor_digest256_is_zero(const char *digest) -{ - return tor_mem_is_zero(digest, DIGEST256_LEN); -} - -/* Helper: common code to check whether the result of a strtol or strtoul or - * strtoll is correct. */ -#define CHECK_STRTOX_RESULT() \ - /* Did an overflow occur? */ \ - if (errno == ERANGE) \ - goto err; \ - /* Was at least one character converted? */ \ - if (endptr == s) \ - goto err; \ - /* Were there unexpected unconverted characters? */ \ - if (!next && *endptr) \ - goto err; \ - /* Illogical (max, min) inputs? */ \ - if (BUG(max < min)) \ - goto err; \ - /* Is r within limits? */ \ - if (r < min || r > max) \ - goto err; \ - if (ok) *ok = 1; \ - if (next) *next = endptr; \ - return r; \ - err: \ - if (ok) *ok = 0; \ - if (next) *next = endptr; \ - return 0 - -/** Extract a long from the start of <b>s</b>, in the given numeric - * <b>base</b>. If <b>base</b> is 0, <b>s</b> is parsed as a decimal, - * octal, or hex number in the syntax of a C integer literal. If - * there is unconverted data and <b>next</b> is provided, set - * *<b>next</b> to the first unconverted character. An error has - * occurred if no characters are converted; or if there are - * unconverted characters and <b>next</b> is NULL; or if the parsed - * value is not between <b>min</b> and <b>max</b>. When no error - * occurs, return the parsed value and set *<b>ok</b> (if provided) to - * 1. When an error occurs, return 0 and set *<b>ok</b> (if provided) - * to 0. - */ -long -tor_parse_long(const char *s, int base, long min, long max, - int *ok, char **next) -{ - char *endptr; - long r; - - if (BUG(base < 0)) { - if (ok) - *ok = 0; - return 0; - } - - errno = 0; - r = strtol(s, &endptr, base); - CHECK_STRTOX_RESULT(); -} - -/** As tor_parse_long(), but return an unsigned long. */ -unsigned long -tor_parse_ulong(const char *s, int base, unsigned long min, - unsigned long max, int *ok, char **next) -{ - char *endptr; - unsigned long r; - - if (BUG(base < 0)) { - if (ok) - *ok = 0; - return 0; - } - - errno = 0; - r = strtoul(s, &endptr, base); - CHECK_STRTOX_RESULT(); -} - -/** As tor_parse_long(), but return a double. */ -double -tor_parse_double(const char *s, double min, double max, int *ok, char **next) -{ - char *endptr; - double r; - - errno = 0; - r = strtod(s, &endptr); - CHECK_STRTOX_RESULT(); -} - -/** As tor_parse_long, but return a uint64_t. Only base 10 is guaranteed to - * work for now. */ -uint64_t -tor_parse_uint64(const char *s, int base, uint64_t min, - uint64_t max, int *ok, char **next) -{ - char *endptr; - uint64_t r; - - if (BUG(base < 0)) { - if (ok) - *ok = 0; - return 0; - } - - errno = 0; -#ifdef HAVE_STRTOULL - r = (uint64_t)strtoull(s, &endptr, base); -#elif defined(_WIN32) - r = (uint64_t)_strtoui64(s, &endptr, base); -#elif SIZEOF_LONG == 8 - r = (uint64_t)strtoul(s, &endptr, base); -#else -#error "I don't know how to parse 64-bit numbers." -#endif /* defined(HAVE_STRTOULL) || ... */ - - CHECK_STRTOX_RESULT(); -} - -/** Allocate and return a new string representing the contents of <b>s</b>, - * surrounded by quotes and using standard C escapes. - * - * Generally, we use this for logging values that come in over the network to - * keep them from tricking users, and for sending certain values to the - * controller. - * - * We trust values from the resolver, OS, configuration file, and command line - * to not be maliciously ill-formed. We validate incoming routerdescs and - * SOCKS requests and addresses from BEGIN cells as they're parsed; - * afterwards, we trust them as non-malicious. - */ -char * -esc_for_log(const char *s) -{ - const char *cp; - char *result, *outp; - size_t len = 3; - if (!s) { - return tor_strdup("(null)"); - } - - for (cp = s; *cp; ++cp) { - switch (*cp) { - case '\\': - case '\"': - case '\'': - case '\r': - case '\n': - case '\t': - len += 2; - break; - default: - if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) - ++len; - else - len += 4; - break; - } - } - - tor_assert(len <= SSIZE_MAX); - - result = outp = tor_malloc(len); - *outp++ = '\"'; - for (cp = s; *cp; ++cp) { - /* This assertion should always succeed, since we will write at least - * one char here, and two chars for closing quote and nul later */ - tor_assert((outp-result) < (ssize_t)len-2); - switch (*cp) { - case '\\': - case '\"': - case '\'': - *outp++ = '\\'; - *outp++ = *cp; - break; - case '\n': - *outp++ = '\\'; - *outp++ = 'n'; - break; - case '\t': - *outp++ = '\\'; - *outp++ = 't'; - break; - case '\r': - *outp++ = '\\'; - *outp++ = 'r'; - break; - default: - if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) { - *outp++ = *cp; - } else { - tor_assert((outp-result) < (ssize_t)len-4); - tor_snprintf(outp, 5, "\\%03o", (int)(uint8_t) *cp); - outp += 4; - } - break; - } - } - - tor_assert((outp-result) <= (ssize_t)len-2); - *outp++ = '\"'; - *outp++ = 0; - - return result; -} - -/** Similar to esc_for_log. Allocate and return a new string representing - * the first n characters in <b>chars</b>, surround by quotes and using - * standard C escapes. If a NUL character is encountered in <b>chars</b>, - * the resulting string will be terminated there. - */ -char * -esc_for_log_len(const char *chars, size_t n) -{ - char *string = tor_strndup(chars, n); - char *string_escaped = esc_for_log(string); - tor_free(string); - return string_escaped; -} - -/** Allocate and return a new string representing the contents of <b>s</b>, - * surrounded by quotes and using standard C escapes. - * - * THIS FUNCTION IS NOT REENTRANT. Don't call it from outside the main - * thread. Also, each call invalidates the last-returned value, so don't - * try log_warn(LD_GENERAL, "%s %s", escaped(a), escaped(b)); - */ -const char * -escaped(const char *s) -{ - static char *escaped_val_ = NULL; - tor_free(escaped_val_); - - if (s) - escaped_val_ = esc_for_log(s); - else - escaped_val_ = NULL; - - return escaped_val_; -} - -/** Return a newly allocated string equal to <b>string</b>, except that every - * character in <b>chars_to_escape</b> is preceded by a backslash. */ -char * -tor_escape_str_for_pt_args(const char *string, const char *chars_to_escape) -{ - char *new_string = NULL; - char *new_cp = NULL; - size_t length, new_length; - - tor_assert(string); - - length = strlen(string); - - if (!length) /* If we were given the empty string, return the same. */ - return tor_strdup(""); - /* (new_length > SIZE_MAX) => ((length * 2) + 1 > SIZE_MAX) => - (length*2 > SIZE_MAX - 1) => (length > (SIZE_MAX - 1)/2) */ - if (length > (SIZE_MAX - 1)/2) /* check for overflow */ - return NULL; - - /* this should be enough even if all characters must be escaped */ - new_length = (length * 2) + 1; - - new_string = new_cp = tor_malloc(new_length); - - while (*string) { - if (strchr(chars_to_escape, *string)) - *new_cp++ = '\\'; - - *new_cp++ = *string++; - } - - *new_cp = '\0'; /* NUL-terminate the new string */ - - return new_string; -} - -/* ===== - * Time - * ===== */ - -#define TOR_USEC_PER_SEC 1000000 - -/** Return the difference between start->tv_sec and end->tv_sec. - * Returns INT64_MAX on overflow and underflow. - */ -static int64_t -tv_secdiff_impl(const struct timeval *start, const struct timeval *end) -{ - const int64_t s = (int64_t)start->tv_sec; - const int64_t e = (int64_t)end->tv_sec; - - /* This may not be the most efficient way of implemeting this check, - * but it's easy to see that it's correct and doesn't overflow */ - - if (s > 0 && e < INT64_MIN + s) { - /* s is positive: equivalent to e - s < INT64_MIN, but without any - * overflow */ - return INT64_MAX; - } else if (s < 0 && e > INT64_MAX + s) { - /* s is negative: equivalent to e - s > INT64_MAX, but without any - * overflow */ - return INT64_MAX; - } - - return e - s; -} - -/** Return the number of microseconds elapsed between *start and *end. - * Returns LONG_MAX on overflow and underflow. - */ -long -tv_udiff(const struct timeval *start, const struct timeval *end) -{ - /* Sanity check tv_usec */ - if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " - "start tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(start->tv_usec)); - return LONG_MAX; - } - - if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " - "end tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(end->tv_usec)); - return LONG_MAX; - } - - /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit - */ - int64_t udiff; - const int64_t secdiff = tv_secdiff_impl(start, end); - - /* end->tv_usec - start->tv_usec can be up to 1 second either way */ - if (secdiff > (int64_t)(LONG_MAX/1000000 - 1) || - secdiff < (int64_t)(LONG_MIN/1000000 + 1)) { - log_warn(LD_GENERAL, "comparing times on microsecond detail too far " - "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); - return LONG_MAX; - } - - /* we'll never get an overflow here, because we check that both usecs are - * between 0 and TV_USEC_PER_SEC. */ - udiff = secdiff*1000000 + ((int64_t)end->tv_usec - (int64_t)start->tv_usec); - - /* Some compilers are smart enough to work out this is a no-op on L64 */ -#if SIZEOF_LONG < 8 - if (udiff > (int64_t)LONG_MAX || udiff < (int64_t)LONG_MIN) { - return LONG_MAX; - } -#endif - - return (long)udiff; -} - -/** Return the number of milliseconds elapsed between *start and *end. - * If the tv_usec difference is 500, rounds away from zero. - * Returns LONG_MAX on overflow and underflow. - */ -long -tv_mdiff(const struct timeval *start, const struct timeval *end) -{ - /* Sanity check tv_usec */ - if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " - "start tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(start->tv_usec)); - return LONG_MAX; - } - - if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " - "end tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(end->tv_usec)); - return LONG_MAX; - } - - /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit - */ - int64_t mdiff; - const int64_t secdiff = tv_secdiff_impl(start, end); - - /* end->tv_usec - start->tv_usec can be up to 1 second either way, but the - * mdiff calculation may add another temporary second for rounding. - * Whether this actually causes overflow depends on the compiler's constant - * folding and order of operations. */ - if (secdiff > (int64_t)(LONG_MAX/1000 - 2) || - secdiff < (int64_t)(LONG_MIN/1000 + 1)) { - log_warn(LD_GENERAL, "comparing times on millisecond detail too far " - "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); - return LONG_MAX; - } - - /* Subtract and round */ - mdiff = secdiff*1000 + - /* We add a million usec here to ensure that the result is positive, - * so that the round-towards-zero behavior of the division will give - * the right result for rounding to the nearest msec. Later we subtract - * 1000 in order to get the correct result. - * We'll never get an overflow here, because we check that both usecs are - * between 0 and TV_USEC_PER_SEC. */ - ((int64_t)end->tv_usec - (int64_t)start->tv_usec + 500 + 1000000) / 1000 - - 1000; - - /* Some compilers are smart enough to work out this is a no-op on L64 */ -#if SIZEOF_LONG < 8 - if (mdiff > (int64_t)LONG_MAX || mdiff < (int64_t)LONG_MIN) { - return LONG_MAX; - } -#endif - - return (long)mdiff; -} - -/** - * Converts timeval to milliseconds. - */ -int64_t -tv_to_msec(const struct timeval *tv) -{ - int64_t conv = ((int64_t)tv->tv_sec)*1000L; - /* Round ghetto-style */ - conv += ((int64_t)tv->tv_usec+500)/1000L; - return conv; -} - -/** Yield true iff <b>y</b> is a leap-year. */ -#define IS_LEAPYEAR(y) (!(y % 4) && ((y % 100) || !(y % 400))) -/** Helper: Return the number of leap-days between Jan 1, y1 and Jan 1, y2. */ -static int -n_leapdays(int year1, int year2) -{ - --year1; - --year2; - return (year2/4 - year1/4) - (year2/100 - year1/100) - + (year2/400 - year1/400); -} -/** Number of days per month in non-leap year; used by tor_timegm and - * parse_rfc1123_time. */ -static const int days_per_month[] = - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - -/** Compute a time_t given a struct tm. The result is given in UTC, and - * does not account for leap seconds. Return 0 on success, -1 on failure. - */ -int -tor_timegm(const struct tm *tm, time_t *time_out) -{ - /* This is a pretty ironclad timegm implementation, snarfed from Python2.2. - * It's way more brute-force than fiddling with tzset(). - * - * We use int64_t rather than time_t to avoid overflow on multiplication on - * platforms with 32-bit time_t. Since year is clipped to INT32_MAX, and - * since 365 * 24 * 60 * 60 is approximately 31 million, it's not possible - * for INT32_MAX years to overflow int64_t when converted to seconds. */ - int64_t year, days, hours, minutes, seconds; - int i, invalid_year, dpm; - - /* Initialize time_out to 0 for now, to avoid bad usage in case this function - fails and the caller ignores the return value. */ - tor_assert(time_out); - *time_out = 0; - - /* avoid int overflow on addition */ - if (tm->tm_year < INT32_MAX-1900) { - year = tm->tm_year + 1900; - } else { - /* clamp year */ - year = INT32_MAX; - } - invalid_year = (year < 1970 || tm->tm_year >= INT32_MAX-1900); - - if (tm->tm_mon >= 0 && tm->tm_mon <= 11) { - dpm = days_per_month[tm->tm_mon]; - if (tm->tm_mon == 1 && !invalid_year && IS_LEAPYEAR(tm->tm_year)) { - dpm = 29; - } - } else { - /* invalid month - default to 0 days per month */ - dpm = 0; - } - - if (invalid_year || - tm->tm_mon < 0 || tm->tm_mon > 11 || - tm->tm_mday < 1 || tm->tm_mday > dpm || - tm->tm_hour < 0 || tm->tm_hour > 23 || - tm->tm_min < 0 || tm->tm_min > 59 || - tm->tm_sec < 0 || tm->tm_sec > 60) { - log_warn(LD_BUG, "Out-of-range argument to tor_timegm"); - return -1; - } - days = 365 * (year-1970) + n_leapdays(1970,(int)year); - for (i = 0; i < tm->tm_mon; ++i) - days += days_per_month[i]; - if (tm->tm_mon > 1 && IS_LEAPYEAR(year)) - ++days; - days += tm->tm_mday - 1; - hours = days*24 + tm->tm_hour; - - minutes = hours*60 + tm->tm_min; - seconds = minutes*60 + tm->tm_sec; - /* Check that "seconds" will fit in a time_t. On platforms where time_t is - * 32-bit, this check will fail for dates in and after 2038. - * - * We already know that "seconds" can't be negative because "year" >= 1970 */ -#if SIZEOF_TIME_T < 8 - if (seconds < TIME_MIN || seconds > TIME_MAX) { - log_warn(LD_BUG, "Result does not fit in tor_timegm"); - return -1; - } -#endif /* SIZEOF_TIME_T < 8 */ - *time_out = (time_t)seconds; - return 0; -} - -/* strftime is locale-specific, so we need to replace those parts */ - -/** A c-locale array of 3-letter names of weekdays, starting with Sun. */ -static const char *WEEKDAY_NAMES[] = - { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; -/** A c-locale array of 3-letter names of months, starting with Jan. */ -static const char *MONTH_NAMES[] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - -/** Set <b>buf</b> to the RFC1123 encoding of the UTC value of <b>t</b>. - * The buffer must be at least RFC1123_TIME_LEN+1 bytes long. - * - * (RFC1123 format is "Fri, 29 Sep 2006 15:54:20 GMT". Note the "GMT" - * rather than "UTC".) - */ -void -format_rfc1123_time(char *buf, time_t t) -{ - struct tm tm; - - tor_gmtime_r(&t, &tm); - - strftime(buf, RFC1123_TIME_LEN+1, "___, %d ___ %Y %H:%M:%S GMT", &tm); - tor_assert(tm.tm_wday >= 0); - tor_assert(tm.tm_wday <= 6); - memcpy(buf, WEEKDAY_NAMES[tm.tm_wday], 3); - tor_assert(tm.tm_mon >= 0); - tor_assert(tm.tm_mon <= 11); - memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3); -} - -/** Parse the (a subset of) the RFC1123 encoding of some time (in UTC) from - * <b>buf</b>, and store the result in *<b>t</b>. - * - * Note that we only accept the subset generated by format_rfc1123_time above, - * not the full range of formats suggested by RFC 1123. - * - * Return 0 on success, -1 on failure. -*/ -int -parse_rfc1123_time(const char *buf, time_t *t) -{ - struct tm tm; - char month[4]; - char weekday[4]; - int i, m, invalid_year; - unsigned tm_mday, tm_year, tm_hour, tm_min, tm_sec; - unsigned dpm; - - if (strlen(buf) != RFC1123_TIME_LEN) - return -1; - memset(&tm, 0, sizeof(tm)); - if (tor_sscanf(buf, "%3s, %2u %3s %u %2u:%2u:%2u GMT", weekday, - &tm_mday, month, &tm_year, &tm_hour, - &tm_min, &tm_sec) < 7) { - char *esc = esc_for_log(buf); - log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc); - tor_free(esc); - return -1; - } - - m = -1; - for (i = 0; i < 12; ++i) { - if (!strcmp(month, MONTH_NAMES[i])) { - m = i; - break; - } - } - if (m<0) { - char *esc = esc_for_log(buf); - log_warn(LD_GENERAL, "Got invalid RFC1123 time %s: No such month", esc); - tor_free(esc); - return -1; - } - tm.tm_mon = m; - - invalid_year = (tm_year >= INT32_MAX || tm_year < 1970); - tor_assert(m >= 0 && m <= 11); - dpm = days_per_month[m]; - if (m == 1 && !invalid_year && IS_LEAPYEAR(tm_year)) { - dpm = 29; - } - - if (invalid_year || tm_mday < 1 || tm_mday > dpm || - tm_hour > 23 || tm_min > 59 || tm_sec > 60) { - char *esc = esc_for_log(buf); - log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc); - tor_free(esc); - return -1; - } - tm.tm_mday = (int)tm_mday; - tm.tm_year = (int)tm_year; - tm.tm_hour = (int)tm_hour; - tm.tm_min = (int)tm_min; - tm.tm_sec = (int)tm_sec; - - if (tm.tm_year < 1970) { - /* LCOV_EXCL_START - * XXXX I think this is dead code; we already checked for - * invalid_year above. */ - tor_assert_nonfatal_unreached(); - char *esc = esc_for_log(buf); - log_warn(LD_GENERAL, - "Got invalid RFC1123 time %s. (Before 1970)", esc); - tor_free(esc); - return -1; - /* LCOV_EXCL_STOP */ - } - tm.tm_year -= 1900; - - return tor_timegm(&tm, t); -} - -/** Set <b>buf</b> to the ISO8601 encoding of the local value of <b>t</b>. - * The buffer must be at least ISO_TIME_LEN+1 bytes long. - * - * (ISO8601 format is 2006-10-29 10:57:20) - */ -void -format_local_iso_time(char *buf, time_t t) -{ - struct tm tm; - strftime(buf, ISO_TIME_LEN+1, "%Y-%m-%d %H:%M:%S", tor_localtime_r(&t, &tm)); -} - -/** Set <b>buf</b> to the ISO8601 encoding of the GMT value of <b>t</b>. - * The buffer must be at least ISO_TIME_LEN+1 bytes long. - */ -void -format_iso_time(char *buf, time_t t) -{ - struct tm tm; - strftime(buf, ISO_TIME_LEN+1, "%Y-%m-%d %H:%M:%S", tor_gmtime_r(&t, &tm)); -} - -/** As format_local_iso_time, but use the yyyy-mm-ddThh:mm:ss format to avoid - * embedding an internal space. */ -void -format_local_iso_time_nospace(char *buf, time_t t) -{ - format_local_iso_time(buf, t); - buf[10] = 'T'; -} - -/** As format_iso_time, but use the yyyy-mm-ddThh:mm:ss format to avoid - * embedding an internal space. */ -void -format_iso_time_nospace(char *buf, time_t t) -{ - format_iso_time(buf, t); - buf[10] = 'T'; -} - -/** As format_iso_time_nospace, but include microseconds in decimal - * fixed-point format. Requires that buf be at least ISO_TIME_USEC_LEN+1 - * bytes long. */ -void -format_iso_time_nospace_usec(char *buf, const struct timeval *tv) -{ - tor_assert(tv); - format_iso_time_nospace(buf, (time_t)tv->tv_sec); - tor_snprintf(buf+ISO_TIME_LEN, 8, ".%06d", (int)tv->tv_usec); -} - -/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>, - * parse it and store its value in *<b>t</b>. Return 0 on success, -1 on - * failure. Ignore extraneous stuff in <b>cp</b> after the end of the time - * string, unless <b>strict</b> is set. If <b>nospace</b> is set, - * expect the YYYY-MM-DDTHH:MM:SS format. */ -int -parse_iso_time_(const char *cp, time_t *t, int strict, int nospace) -{ - struct tm st_tm; - unsigned int year=0, month=0, day=0, hour=0, minute=0, second=0; - int n_fields; - char extra_char, separator_char; - n_fields = tor_sscanf(cp, "%u-%2u-%2u%c%2u:%2u:%2u%c", - &year, &month, &day, - &separator_char, - &hour, &minute, &second, &extra_char); - if (strict ? (n_fields != 7) : (n_fields < 7)) { - char *esc = esc_for_log(cp); - log_warn(LD_GENERAL, "ISO time %s was unparseable", esc); - tor_free(esc); - return -1; - } - if (separator_char != (nospace ? 'T' : ' ')) { - char *esc = esc_for_log(cp); - log_warn(LD_GENERAL, "ISO time %s was unparseable", esc); - tor_free(esc); - return -1; - } - if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || - hour > 23 || minute > 59 || second > 60 || year >= INT32_MAX) { - char *esc = esc_for_log(cp); - log_warn(LD_GENERAL, "ISO time %s was nonsensical", esc); - tor_free(esc); - return -1; - } - st_tm.tm_year = (int)year-1900; - st_tm.tm_mon = month-1; - st_tm.tm_mday = day; - st_tm.tm_hour = hour; - st_tm.tm_min = minute; - st_tm.tm_sec = second; - st_tm.tm_wday = 0; /* Should be ignored. */ - - if (st_tm.tm_year < 70) { - /* LCOV_EXCL_START - * XXXX I think this is dead code; we already checked for - * year < 1970 above. */ - tor_assert_nonfatal_unreached(); - char *esc = esc_for_log(cp); - log_warn(LD_GENERAL, "Got invalid ISO time %s. (Before 1970)", esc); - tor_free(esc); - return -1; - /* LCOV_EXCL_STOP */ - } - return tor_timegm(&st_tm, t); -} - -/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>, - * parse it and store its value in *<b>t</b>. Return 0 on success, -1 on - * failure. Reject the string if any characters are present after the time. - */ -int -parse_iso_time(const char *cp, time_t *t) -{ - return parse_iso_time_(cp, t, 1, 0); -} - -/** - * As parse_iso_time, but parses a time encoded by format_iso_time_nospace(). - */ -int -parse_iso_time_nospace(const char *cp, time_t *t) -{ - return parse_iso_time_(cp, t, 1, 1); -} - -/** Given a <b>date</b> in one of the three formats allowed by HTTP (ugh), - * parse it into <b>tm</b>. Return 0 on success, negative on failure. */ -int -parse_http_time(const char *date, struct tm *tm) -{ - const char *cp; - char month[4]; - char wkday[4]; - int i; - unsigned tm_mday, tm_year, tm_hour, tm_min, tm_sec; - - tor_assert(tm); - memset(tm, 0, sizeof(*tm)); - - /* First, try RFC1123 or RFC850 format: skip the weekday. */ - if ((cp = strchr(date, ','))) { - ++cp; - if (*cp != ' ') - return -1; - ++cp; - if (tor_sscanf(cp, "%2u %3s %4u %2u:%2u:%2u GMT", - &tm_mday, month, &tm_year, - &tm_hour, &tm_min, &tm_sec) == 6) { - /* rfc1123-date */ - tm_year -= 1900; - } else if (tor_sscanf(cp, "%2u-%3s-%2u %2u:%2u:%2u GMT", - &tm_mday, month, &tm_year, - &tm_hour, &tm_min, &tm_sec) == 6) { - /* rfc850-date */ - } else { - return -1; - } - } else { - /* No comma; possibly asctime() format. */ - if (tor_sscanf(date, "%3s %3s %2u %2u:%2u:%2u %4u", - wkday, month, &tm_mday, - &tm_hour, &tm_min, &tm_sec, &tm_year) == 7) { - tm_year -= 1900; - } else { - return -1; - } - } - tm->tm_mday = (int)tm_mday; - tm->tm_year = (int)tm_year; - tm->tm_hour = (int)tm_hour; - tm->tm_min = (int)tm_min; - tm->tm_sec = (int)tm_sec; - tm->tm_wday = 0; /* Leave this unset. */ - - month[3] = '\0'; - /* Okay, now decode the month. */ - /* set tm->tm_mon to dummy value so the check below fails. */ - tm->tm_mon = -1; - for (i = 0; i < 12; ++i) { - if (!strcasecmp(MONTH_NAMES[i], month)) { - tm->tm_mon = i; - } - } - - if (tm->tm_year < 0 || - tm->tm_mon < 0 || tm->tm_mon > 11 || - tm->tm_mday < 1 || tm->tm_mday > 31 || - tm->tm_hour < 0 || tm->tm_hour > 23 || - tm->tm_min < 0 || tm->tm_min > 59 || - tm->tm_sec < 0 || tm->tm_sec > 60) - return -1; /* Out of range, or bad month. */ - - return 0; -} - -/** Given an <b>interval</b> in seconds, try to write it to the - * <b>out_len</b>-byte buffer in <b>out</b> in a human-readable form. - * Returns a non-negative integer on success, -1 on failure. - */ -int -format_time_interval(char *out, size_t out_len, long interval) -{ - /* We only report seconds if there's no hours. */ - long sec = 0, min = 0, hour = 0, day = 0; - - /* -LONG_MIN is LONG_MAX + 1, which causes signed overflow */ - if (interval < -LONG_MAX) - interval = LONG_MAX; - else if (interval < 0) - interval = -interval; - - if (interval >= 86400) { - day = interval / 86400; - interval %= 86400; - } - if (interval >= 3600) { - hour = interval / 3600; - interval %= 3600; - } - if (interval >= 60) { - min = interval / 60; - interval %= 60; - } - sec = interval; - - if (day) { - return tor_snprintf(out, out_len, "%ld days, %ld hours, %ld minutes", - day, hour, min); - } else if (hour) { - return tor_snprintf(out, out_len, "%ld hours, %ld minutes", hour, min); - } else if (min) { - return tor_snprintf(out, out_len, "%ld minutes, %ld seconds", min, sec); - } else { - return tor_snprintf(out, out_len, "%ld seconds", sec); - } -} - -/* ===== - * Cached time - * ===== */ - -#ifndef TIME_IS_FAST -/** Cached estimate of the current time. Updated around once per second; - * may be a few seconds off if we are really busy. This is a hack to avoid - * calling time(NULL) (which not everybody has optimized) on critical paths. - */ -static time_t cached_approx_time = 0; - -/** Return a cached estimate of the current time from when - * update_approx_time() was last called. This is a hack to avoid calling - * time(NULL) on critical paths: please do not even think of calling it - * anywhere else. */ -time_t -approx_time(void) -{ - return cached_approx_time; -} - -/** Update the cached estimate of the current time. This function SHOULD be - * called once per second, and MUST be called before the first call to - * get_approx_time. */ -void -update_approx_time(time_t now) -{ - cached_approx_time = now; -} -#endif /* !defined(TIME_IS_FAST) */ - -/* ===== - * Rate limiting - * ===== */ - -/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number - * of calls to rate_limit_is_ready (including this one!) since the last time - * rate_limit_is_ready returned nonzero. Otherwise return 0. - * If the call number hits <b>RATELIM_TOOMANY</b> limit, drop a warning - * about this event and stop counting. */ -static int -rate_limit_is_ready(ratelim_t *lim, time_t now) -{ - if (lim->rate + lim->last_allowed <= now) { - int res = lim->n_calls_since_last_time + 1; - lim->last_allowed = now; - lim->n_calls_since_last_time = 0; - return res; - } else { - if (lim->n_calls_since_last_time <= RATELIM_TOOMANY) { - ++lim->n_calls_since_last_time; - } - - return 0; - } -} - -/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return a newly - * allocated string indicating how many messages were suppressed, suitable to - * append to a log message. Otherwise return NULL. */ -char * -rate_limit_log(ratelim_t *lim, time_t now) -{ - int n; - if ((n = rate_limit_is_ready(lim, now))) { - if (n == 1) { - return tor_strdup(""); - } else { - char *cp=NULL; - const char *opt_over = (n >= RATELIM_TOOMANY) ? "over " : ""; - /* XXXX this is not exactly correct: the messages could have occurred - * any time between the old value of lim->allowed and now. */ - tor_asprintf(&cp, - " [%s%d similar message(s) suppressed in last %d seconds]", - opt_over, n-1, lim->rate); - return cp; - } - } else { - return NULL; - } -} - -/* ===== - * File helpers - * ===== */ - -/** Write <b>count</b> bytes from <b>buf</b> to <b>fd</b>. <b>isSocket</b> - * must be 1 if fd was returned by socket() or accept(), and 0 if fd - * was returned by open(). Return the number of bytes written, or -1 - * on error. Only use if fd is a blocking fd. */ -ssize_t -write_all(tor_socket_t fd, const char *buf, size_t count, int isSocket) -{ - size_t written = 0; - ssize_t result; - tor_assert(count < SSIZE_MAX); - - while (written != count) { - if (isSocket) - result = tor_socket_send(fd, buf+written, count-written, 0); - else - result = write((int)fd, buf+written, count-written); - if (result<0) - return -1; - written += result; - } - return (ssize_t)count; -} - -/** Read from <b>fd</b> to <b>buf</b>, until we get <b>count</b> bytes - * or reach the end of the file. <b>isSocket</b> must be 1 if fd - * was returned by socket() or accept(), and 0 if fd was returned by - * open(). Return the number of bytes read, or -1 on error. Only use - * if fd is a blocking fd. */ -ssize_t -read_all(tor_socket_t fd, char *buf, size_t count, int isSocket) -{ - size_t numread = 0; - ssize_t result; - - if (count > SIZE_T_CEILING || count > SSIZE_MAX) { - errno = EINVAL; - return -1; - } - - while (numread < count) { - if (isSocket) - result = tor_socket_recv(fd, buf+numread, count-numread, 0); - else - result = read((int)fd, buf+numread, count-numread); - if (result<0) - return -1; - else if (result == 0) - break; - numread += result; - } - return (ssize_t)numread; -} - -/* - * Filesystem operations. - */ - -/** Clean up <b>name</b> so that we can use it in a call to "stat". On Unix, - * we do nothing. On Windows, we remove a trailing slash, unless the path is - * the root of a disk. */ -static void -clean_name_for_stat(char *name) -{ -#ifdef _WIN32 - size_t len = strlen(name); - if (!len) - return; - if (name[len-1]=='\\' || name[len-1]=='/') { - if (len == 1 || (len==3 && name[1]==':')) - return; - name[len-1]='\0'; - } -#else /* !(defined(_WIN32)) */ - (void)name; -#endif /* defined(_WIN32) */ -} - -/** Wrapper for unlink() to make it mockable for the test suite; returns 0 - * if unlinking the file succeeded, -1 and sets errno if unlinking fails. - */ - -MOCK_IMPL(int, -tor_unlink,(const char *pathname)) -{ - return unlink(pathname); -} - -/** Return: - * FN_ERROR if filename can't be read, is NULL, or is zero-length, - * FN_NOENT if it doesn't exist, - * FN_FILE if it is a non-empty regular file, or a FIFO on unix-like systems, - * FN_EMPTY for zero-byte regular files, - * FN_DIR if it's a directory, and - * FN_ERROR for any other file type. - * On FN_ERROR and FN_NOENT, sets errno. (errno is not set when FN_ERROR - * is returned due to an unhandled file type.) */ -file_status_t -file_status(const char *fname) -{ - struct stat st; - char *f; - int r; - if (!fname || strlen(fname) == 0) { - return FN_ERROR; - } - f = tor_strdup(fname); - clean_name_for_stat(f); - log_debug(LD_FS, "stat()ing %s", f); - r = stat(sandbox_intern_string(f), &st); - tor_free(f); - if (r) { - if (errno == ENOENT) { - return FN_NOENT; - } - return FN_ERROR; - } - if (st.st_mode & S_IFDIR) { - return FN_DIR; - } else if (st.st_mode & S_IFREG) { - if (st.st_size > 0) { - return FN_FILE; - } else if (st.st_size == 0) { - return FN_EMPTY; - } else { - return FN_ERROR; - } -#ifndef _WIN32 - } else if (st.st_mode & S_IFIFO) { - return FN_FILE; -#endif - } else { - return FN_ERROR; - } -} - -/** Check whether <b>dirname</b> exists and is private. If yes return 0. - * If <b>dirname</b> does not exist: - * - if <b>check</b>&CPD_CREATE, try to create it and return 0 on success. - * - if <b>check</b>&CPD_CHECK, and we think we can create it, return 0. - * - if <b>check</b>&CPD_CHECK is false, and the directory exists, return 0. - * - otherwise, return -1. - * If CPD_GROUP_OK is set, then it's okay if the directory - * is group-readable, but in all cases we create the directory mode 0700. - * If CPD_GROUP_READ is set, existing directory behaves as CPD_GROUP_OK and - * if the directory is created it will use mode 0750 with group read - * permission. Group read privileges also assume execute permission - * as norm for directories. If CPD_CHECK_MODE_ONLY is set, then we don't - * alter the directory permissions if they are too permissive: - * we just return -1. - * When effective_user is not NULL, check permissions against the given user - * and its primary group. - */ -MOCK_IMPL(int, -check_private_dir,(const char *dirname, cpd_check_t check, - const char *effective_user)) -{ - int r; - struct stat st; - - tor_assert(dirname); - -#ifndef _WIN32 - int fd; - const struct passwd *pw = NULL; - uid_t running_uid; - gid_t running_gid; - - /* - * Goal is to harden the implementation by removing any - * potential for race between stat() and chmod(). - * chmod() accepts filename as argument. If an attacker can move - * the file between stat() and chmod(), a potential race exists. - * - * Several suggestions taken from: - * https://developer.apple.com/library/mac/documentation/ - * Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html - */ - - /* Open directory. - * O_NOFOLLOW to ensure that it does not follow symbolic links */ - fd = open(sandbox_intern_string(dirname), O_NOFOLLOW); - - /* Was there an error? Maybe the directory does not exist? */ - if (fd == -1) { - - if (errno != ENOENT) { - /* Other directory error */ - log_warn(LD_FS, "Directory %s cannot be read: %s", dirname, - strerror(errno)); - return -1; - } - - /* Received ENOENT: Directory does not exist */ - - /* Should we create the directory? */ - if (check & CPD_CREATE) { - log_info(LD_GENERAL, "Creating directory %s", dirname); - if (check & CPD_GROUP_READ) { - r = mkdir(dirname, 0750); - } else { - r = mkdir(dirname, 0700); - } - - /* check for mkdir() error */ - if (r) { - log_warn(LD_FS, "Error creating directory %s: %s", dirname, - strerror(errno)); - return -1; - } - - /* we just created the directory. try to open it again. - * permissions on the directory will be checked again below.*/ - fd = open(sandbox_intern_string(dirname), O_NOFOLLOW); - - if (fd == -1) { - log_warn(LD_FS, "Could not reopen recently created directory %s: %s", - dirname, - strerror(errno)); - return -1; - } else { - close(fd); - } - - } else if (!(check & CPD_CHECK)) { - log_warn(LD_FS, "Directory %s does not exist.", dirname); - return -1; - } - - /* XXXX In the case where check==CPD_CHECK, we should look at the - * parent directory a little harder. */ - return 0; - } - - tor_assert(fd >= 0); - - //f = tor_strdup(dirname); - //clean_name_for_stat(f); - log_debug(LD_FS, "stat()ing %s", dirname); - //r = stat(sandbox_intern_string(f), &st); - r = fstat(fd, &st); - if (r == -1) { - log_warn(LD_FS, "fstat() on directory %s failed.", dirname); - close(fd); - return -1; - } - //tor_free(f); - - /* check that dirname is a directory */ - if (!(st.st_mode & S_IFDIR)) { - log_warn(LD_FS, "%s is not a directory", dirname); - close(fd); - return -1; - } - - if (effective_user) { - /* Look up the user and group information. - * If we have a problem, bail out. */ - pw = tor_getpwnam(effective_user); - if (pw == NULL) { - log_warn(LD_CONFIG, "Error setting configured user: %s not found", - effective_user); - close(fd); - return -1; - } - running_uid = pw->pw_uid; - running_gid = pw->pw_gid; - } else { - running_uid = getuid(); - running_gid = getgid(); - } - if (st.st_uid != running_uid) { - char *process_ownername = NULL, *file_ownername = NULL; - - { - const struct passwd *pw_running = tor_getpwuid(running_uid); - process_ownername = pw_running ? tor_strdup(pw_running->pw_name) : - tor_strdup("<unknown>"); - } - - { - const struct passwd *pw_stat = tor_getpwuid(st.st_uid); - file_ownername = pw_stat ? tor_strdup(pw_stat->pw_name) : - tor_strdup("<unknown>"); - } - - log_warn(LD_FS, "%s is not owned by this user (%s, %d) but by " - "%s (%d). Perhaps you are running Tor as the wrong user?", - dirname, process_ownername, (int)running_uid, - file_ownername, (int)st.st_uid); - - tor_free(process_ownername); - tor_free(file_ownername); - close(fd); - return -1; - } - if ( (check & (CPD_GROUP_OK|CPD_GROUP_READ)) - && (st.st_gid != running_gid) && (st.st_gid != 0)) { - struct group *gr; - char *process_groupname = NULL; - gr = getgrgid(running_gid); - process_groupname = gr ? tor_strdup(gr->gr_name) : tor_strdup("<unknown>"); - gr = getgrgid(st.st_gid); - - log_warn(LD_FS, "%s is not owned by this group (%s, %d) but by group " - "%s (%d). Are you running Tor as the wrong user?", - dirname, process_groupname, (int)running_gid, - gr ? gr->gr_name : "<unknown>", (int)st.st_gid); - - tor_free(process_groupname); - close(fd); - return -1; - } - unsigned unwanted_bits = 0; - if (check & (CPD_GROUP_OK|CPD_GROUP_READ)) { - unwanted_bits = 0027; - } else { - unwanted_bits = 0077; - } - unsigned check_bits_filter = ~0; - if (check & CPD_RELAX_DIRMODE_CHECK) { - check_bits_filter = 0022; - } - if ((st.st_mode & unwanted_bits & check_bits_filter) != 0) { - unsigned new_mode; - if (check & CPD_CHECK_MODE_ONLY) { - log_warn(LD_FS, "Permissions on directory %s are too permissive.", - dirname); - close(fd); - return -1; - } - log_warn(LD_FS, "Fixing permissions on directory %s", dirname); - new_mode = st.st_mode; - new_mode |= 0700; /* Owner should have rwx */ - if (check & CPD_GROUP_READ) { - new_mode |= 0050; /* Group should have rx */ - } - new_mode &= ~unwanted_bits; /* Clear the bits that we didn't want set...*/ - if (fchmod(fd, new_mode)) { - log_warn(LD_FS, "Could not chmod directory %s: %s", dirname, - strerror(errno)); - close(fd); - return -1; - } else { - close(fd); - return 0; - } - } - close(fd); -#else /* !(!defined(_WIN32)) */ - /* Win32 case: we can't open() a directory. */ - (void)effective_user; - - char *f = tor_strdup(dirname); - clean_name_for_stat(f); - log_debug(LD_FS, "stat()ing %s", f); - r = stat(sandbox_intern_string(f), &st); - tor_free(f); - if (r) { - if (errno != ENOENT) { - log_warn(LD_FS, "Directory %s cannot be read: %s", dirname, - strerror(errno)); - return -1; - } - if (check & CPD_CREATE) { - log_info(LD_GENERAL, "Creating directory %s", dirname); - r = mkdir(dirname); - if (r) { - log_warn(LD_FS, "Error creating directory %s: %s", dirname, - strerror(errno)); - return -1; - } - } else if (!(check & CPD_CHECK)) { - log_warn(LD_FS, "Directory %s does not exist.", dirname); - return -1; - } - return 0; - } - if (!(st.st_mode & S_IFDIR)) { - log_warn(LD_FS, "%s is not a directory", dirname); - return -1; - } - -#endif /* !defined(_WIN32) */ - return 0; -} - -/** Create a file named <b>fname</b> with the contents <b>str</b>. Overwrite - * the previous <b>fname</b> if possible. Return 0 on success, -1 on failure. - * - * This function replaces the old file atomically, if possible. This - * function, and all other functions in util.c that create files, create them - * with mode 0600. - */ -MOCK_IMPL(int, -write_str_to_file,(const char *fname, const char *str, int bin)) -{ -#ifdef _WIN32 - if (!bin && strchr(str, '\r')) { - log_warn(LD_BUG, - "We're writing a text string that already contains a CR to %s", - escaped(fname)); - } -#endif /* defined(_WIN32) */ - return write_bytes_to_file(fname, str, strlen(str), bin); -} - -/** Represents a file that we're writing to, with support for atomic commit: - * we can write into a temporary file, and either remove the file on - * failure, or replace the original file on success. */ -struct open_file_t { - char *tempname; /**< Name of the temporary file. */ - char *filename; /**< Name of the original file. */ - unsigned rename_on_close:1; /**< Are we using the temporary file or not? */ - unsigned binary:1; /**< Did we open in binary mode? */ - int fd; /**< fd for the open file. */ - FILE *stdio_file; /**< stdio wrapper for <b>fd</b>. */ -}; - -/** Try to start writing to the file in <b>fname</b>, passing the flags - * <b>open_flags</b> to the open() syscall, creating the file (if needed) with - * access value <b>mode</b>. If the O_APPEND flag is set, we append to the - * original file. Otherwise, we open a new temporary file in the same - * directory, and either replace the original or remove the temporary file - * when we're done. - * - * Return the fd for the newly opened file, and store working data in - * *<b>data_out</b>. The caller should not close the fd manually: - * instead, call finish_writing_to_file() or abort_writing_to_file(). - * Returns -1 on failure. - * - * NOTE: When not appending, the flags O_CREAT and O_TRUNC are treated - * as true and the flag O_EXCL is treated as false. - * - * NOTE: Ordinarily, O_APPEND means "seek to the end of the file before each - * write()". We don't do that. - */ -int -start_writing_to_file(const char *fname, int open_flags, int mode, - open_file_t **data_out) -{ - open_file_t *new_file = tor_malloc_zero(sizeof(open_file_t)); - const char *open_name; - int append = 0; - - tor_assert(fname); - tor_assert(data_out); -#if (O_BINARY != 0 && O_TEXT != 0) - tor_assert((open_flags & (O_BINARY|O_TEXT)) != 0); -#endif - new_file->fd = -1; - new_file->filename = tor_strdup(fname); - if (open_flags & O_APPEND) { - open_name = fname; - new_file->rename_on_close = 0; - append = 1; - open_flags &= ~O_APPEND; - } else { - tor_asprintf(&new_file->tempname, "%s.tmp", fname); - open_name = new_file->tempname; - /* We always replace an existing temporary file if there is one. */ - open_flags |= O_CREAT|O_TRUNC; - open_flags &= ~O_EXCL; - new_file->rename_on_close = 1; - } -#if O_BINARY != 0 - if (open_flags & O_BINARY) - new_file->binary = 1; -#endif - - new_file->fd = tor_open_cloexec(open_name, open_flags, mode); - if (new_file->fd < 0) { - log_warn(LD_FS, "Couldn't open \"%s\" (%s) for writing: %s", - open_name, fname, strerror(errno)); - goto err; - } - if (append) { - if (tor_fd_seekend(new_file->fd) < 0) { - log_warn(LD_FS, "Couldn't seek to end of file \"%s\": %s", open_name, - strerror(errno)); - goto err; - } - } - - *data_out = new_file; - - return new_file->fd; - - err: - if (new_file->fd >= 0) - close(new_file->fd); - *data_out = NULL; - tor_free(new_file->filename); - tor_free(new_file->tempname); - tor_free(new_file); - return -1; -} - -/** Given <b>file_data</b> from start_writing_to_file(), return a stdio FILE* - * that can be used to write to the same file. The caller should not mix - * stdio calls with non-stdio calls. */ -FILE * -fdopen_file(open_file_t *file_data) -{ - tor_assert(file_data); - if (file_data->stdio_file) - return file_data->stdio_file; - tor_assert(file_data->fd >= 0); - if (!(file_data->stdio_file = fdopen(file_data->fd, - file_data->binary?"ab":"a"))) { - log_warn(LD_FS, "Couldn't fdopen \"%s\" [%d]: %s", file_data->filename, - file_data->fd, strerror(errno)); - } - return file_data->stdio_file; -} - -/** Combines start_writing_to_file with fdopen_file(): arguments are as - * for start_writing_to_file, but */ -FILE * -start_writing_to_stdio_file(const char *fname, int open_flags, int mode, - open_file_t **data_out) -{ - FILE *res; - if (start_writing_to_file(fname, open_flags, mode, data_out)<0) - return NULL; - if (!(res = fdopen_file(*data_out))) { - abort_writing_to_file(*data_out); - *data_out = NULL; - } - return res; -} - -/** Helper function: close and free the underlying file and memory in - * <b>file_data</b>. If we were writing into a temporary file, then delete - * that file (if abort_write is true) or replaces the target file with - * the temporary file (if abort_write is false). */ -static int -finish_writing_to_file_impl(open_file_t *file_data, int abort_write) -{ - int r = 0; - - tor_assert(file_data && file_data->filename); - if (file_data->stdio_file) { - if (fclose(file_data->stdio_file)) { - log_warn(LD_FS, "Error closing \"%s\": %s", file_data->filename, - strerror(errno)); - abort_write = r = -1; - } - } else if (file_data->fd >= 0 && close(file_data->fd) < 0) { - log_warn(LD_FS, "Error flushing \"%s\": %s", file_data->filename, - strerror(errno)); - abort_write = r = -1; - } - - if (file_data->rename_on_close) { - tor_assert(file_data->tempname && file_data->filename); - if (!abort_write) { - tor_assert(strcmp(file_data->filename, file_data->tempname)); - if (replace_file(file_data->tempname, file_data->filename)) { - log_warn(LD_FS, "Error replacing \"%s\": %s", file_data->filename, - strerror(errno)); - abort_write = r = -1; - } - } - if (abort_write) { - int res = unlink(file_data->tempname); - if (res != 0) { - /* We couldn't unlink and we'll leave a mess behind */ - log_warn(LD_FS, "Failed to unlink %s: %s", - file_data->tempname, strerror(errno)); - r = -1; - } - } - } - - tor_free(file_data->filename); - tor_free(file_data->tempname); - tor_free(file_data); - - return r; -} - -/** Finish writing to <b>file_data</b>: close the file handle, free memory as - * needed, and if using a temporary file, replace the original file with - * the temporary file. */ -int -finish_writing_to_file(open_file_t *file_data) -{ - return finish_writing_to_file_impl(file_data, 0); -} - -/** Finish writing to <b>file_data</b>: close the file handle, free memory as - * needed, and if using a temporary file, delete it. */ -int -abort_writing_to_file(open_file_t *file_data) -{ - return finish_writing_to_file_impl(file_data, 1); -} - -/** Helper: given a set of flags as passed to open(2), open the file - * <b>fname</b> and write all the sized_chunk_t structs in <b>chunks</b> to - * the file. Do so as atomically as possible e.g. by opening temp files and - * renaming. */ -static int -write_chunks_to_file_impl(const char *fname, const smartlist_t *chunks, - int open_flags) -{ - open_file_t *file = NULL; - int fd; - ssize_t result; - fd = start_writing_to_file(fname, open_flags, 0600, &file); - if (fd<0) - return -1; - SMARTLIST_FOREACH(chunks, sized_chunk_t *, chunk, - { - result = write_all(fd, chunk->bytes, chunk->len, 0); - if (result < 0) { - log_warn(LD_FS, "Error writing to \"%s\": %s", fname, - strerror(errno)); - goto err; - } - tor_assert((size_t)result == chunk->len); - }); - - return finish_writing_to_file(file); - err: - abort_writing_to_file(file); - return -1; -} - -/** Given a smartlist of sized_chunk_t, write them to a file - * <b>fname</b>, overwriting or creating the file as necessary. - * If <b>no_tempfile</b> is 0 then the file will be written - * atomically. */ -int -write_chunks_to_file(const char *fname, const smartlist_t *chunks, int bin, - int no_tempfile) -{ - int flags = OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT); - - if (no_tempfile) { - /* O_APPEND stops write_chunks_to_file from using tempfiles */ - flags |= O_APPEND; - } - return write_chunks_to_file_impl(fname, chunks, flags); -} - -/** Write <b>len</b> bytes, starting at <b>str</b>, to <b>fname</b> - using the open() flags passed in <b>flags</b>. */ -static int -write_bytes_to_file_impl(const char *fname, const char *str, size_t len, - int flags) -{ - int r; - sized_chunk_t c = { str, len }; - smartlist_t *chunks = smartlist_new(); - smartlist_add(chunks, &c); - r = write_chunks_to_file_impl(fname, chunks, flags); - smartlist_free(chunks); - return r; -} - -/** As write_str_to_file, but does not assume a NUL-terminated - * string. Instead, we write <b>len</b> bytes, starting at <b>str</b>. */ -MOCK_IMPL(int, -write_bytes_to_file,(const char *fname, const char *str, size_t len, - int bin)) -{ - return write_bytes_to_file_impl(fname, str, len, - OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT)); -} - -/** As write_bytes_to_file, but if the file already exists, append the bytes - * to the end of the file instead of overwriting it. */ -int -append_bytes_to_file(const char *fname, const char *str, size_t len, - int bin) -{ - return write_bytes_to_file_impl(fname, str, len, - OPEN_FLAGS_APPEND|(bin?O_BINARY:O_TEXT)); -} - -/** Like write_str_to_file(), but also return -1 if there was a file - already residing in <b>fname</b>. */ -int -write_bytes_to_new_file(const char *fname, const char *str, size_t len, - int bin) -{ - return write_bytes_to_file_impl(fname, str, len, - OPEN_FLAGS_DONT_REPLACE| - (bin?O_BINARY:O_TEXT)); -} - -/** - * Read the contents of the open file <b>fd</b> presuming it is a FIFO - * (or similar) file descriptor for which the size of the file isn't - * known ahead of time. Return NULL on failure, and a NUL-terminated - * string on success. On success, set <b>sz_out</b> to the number of - * bytes read. - */ -char * -read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) -{ - ssize_t r; - size_t pos = 0; - char *string = NULL; - size_t string_max = 0; - - if (max_bytes_to_read+1 >= SIZE_T_CEILING) { - errno = EINVAL; - return NULL; - } - - do { - /* XXXX This "add 1K" approach is a little goofy; if we care about - * performance here, we should be doubling. But in practice we shouldn't - * be using this function on big files anyway. */ - string_max = pos + 1024; - if (string_max > max_bytes_to_read) - string_max = max_bytes_to_read + 1; - string = tor_realloc(string, string_max); - r = read(fd, string + pos, string_max - pos - 1); - if (r < 0) { - int save_errno = errno; - tor_free(string); - errno = save_errno; - return NULL; - } - - pos += r; - } while (r > 0 && pos < max_bytes_to_read); - - tor_assert(pos < string_max); - *sz_out = pos; - string[pos] = '\0'; - return string; -} - -/** Read the contents of <b>filename</b> into a newly allocated - * string; return the string on success or NULL on failure. - * - * If <b>stat_out</b> is provided, store the result of stat()ing the - * file into <b>stat_out</b>. - * - * If <b>flags</b> & RFTS_BIN, open the file in binary mode. - * If <b>flags</b> & RFTS_IGNORE_MISSING, don't warn if the file - * doesn't exist. - */ -/* - * This function <em>may</em> return an erroneous result if the file - * is modified while it is running, but must not crash or overflow. - * Right now, the error case occurs when the file length grows between - * the call to stat and the call to read_all: the resulting string will - * be truncated. - */ -MOCK_IMPL(char *, -read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) -{ - int fd; /* router file */ - struct stat statbuf; - char *string; - ssize_t r; - int bin = flags & RFTS_BIN; - - tor_assert(filename); - - fd = tor_open_cloexec(filename,O_RDONLY|(bin?O_BINARY:O_TEXT),0); - if (fd<0) { - int severity = LOG_WARN; - int save_errno = errno; - if (errno == ENOENT && (flags & RFTS_IGNORE_MISSING)) - severity = LOG_INFO; - log_fn(severity, LD_FS,"Could not open \"%s\": %s",filename, - strerror(errno)); - errno = save_errno; - return NULL; - } - - if (fstat(fd, &statbuf)<0) { - int save_errno = errno; - close(fd); - log_warn(LD_FS,"Could not fstat \"%s\".",filename); - errno = save_errno; - return NULL; - } - -#ifndef _WIN32 -/** When we detect that we're reading from a FIFO, don't read more than - * this many bytes. It's insane overkill for most uses. */ -#define FIFO_READ_MAX (1024*1024) - if (S_ISFIFO(statbuf.st_mode)) { - size_t sz = 0; - string = read_file_to_str_until_eof(fd, FIFO_READ_MAX, &sz); - int save_errno = errno; - if (string && stat_out) { - statbuf.st_size = sz; - memcpy(stat_out, &statbuf, sizeof(struct stat)); - } - close(fd); - if (!string) - errno = save_errno; - return string; - } -#endif /* !defined(_WIN32) */ - - if ((uint64_t)(statbuf.st_size)+1 >= SIZE_T_CEILING) { - close(fd); - errno = EINVAL; - return NULL; - } - - string = tor_malloc((size_t)(statbuf.st_size+1)); - - r = read_all(fd,string,(size_t)statbuf.st_size,0); - if (r<0) { - int save_errno = errno; - log_warn(LD_FS,"Error reading from file \"%s\": %s", filename, - strerror(errno)); - tor_free(string); - close(fd); - errno = save_errno; - return NULL; - } - string[r] = '\0'; /* NUL-terminate the result. */ - -#if defined(_WIN32) || defined(__CYGWIN__) - if (!bin && strchr(string, '\r')) { - log_debug(LD_FS, "We didn't convert CRLF to LF as well as we hoped " - "when reading %s. Coping.", - filename); - tor_strstrip(string, "\r"); - r = strlen(string); - } - if (!bin) { - statbuf.st_size = (size_t) r; - } else -#endif /* defined(_WIN32) || defined(__CYGWIN__) */ - if (r != statbuf.st_size) { - /* Unless we're using text mode on win32, we'd better have an exact - * match for size. */ - int save_errno = errno; - log_warn(LD_FS,"Could read only %d of %ld bytes of file \"%s\".", - (int)r, (long)statbuf.st_size,filename); - tor_free(string); - close(fd); - errno = save_errno; - return NULL; - } - close(fd); - if (stat_out) { - memcpy(stat_out, &statbuf, sizeof(struct stat)); - } - - return string; -} - -#define TOR_ISODIGIT(c) ('0' <= (c) && (c) <= '7') - -/** Given a c-style double-quoted escaped string in <b>s</b>, extract and - * decode its contents into a newly allocated string. On success, assign this - * string to *<b>result</b>, assign its length to <b>size_out</b> (if - * provided), and return a pointer to the position in <b>s</b> immediately - * after the string. On failure, return NULL. - */ -const char * -unescape_string(const char *s, char **result, size_t *size_out) -{ - const char *cp; - char *out; - if (s[0] != '\"') - return NULL; - cp = s+1; - while (1) { - switch (*cp) { - case '\0': - case '\n': - return NULL; - case '\"': - goto end_of_loop; - case '\\': - if (cp[1] == 'x' || cp[1] == 'X') { - if (!(TOR_ISXDIGIT(cp[2]) && TOR_ISXDIGIT(cp[3]))) - return NULL; - cp += 4; - } else if (TOR_ISODIGIT(cp[1])) { - cp += 2; - if (TOR_ISODIGIT(*cp)) ++cp; - if (TOR_ISODIGIT(*cp)) ++cp; - } else if (cp[1] == 'n' || cp[1] == 'r' || cp[1] == 't' || cp[1] == '"' - || cp[1] == '\\' || cp[1] == '\'') { - cp += 2; - } else { - return NULL; - } - break; - default: - ++cp; - break; - } - } - end_of_loop: - out = *result = tor_malloc(cp-s + 1); - cp = s+1; - while (1) { - switch (*cp) - { - case '\"': - *out = '\0'; - if (size_out) *size_out = out - *result; - return cp+1; - - /* LCOV_EXCL_START -- we caught this in parse_config_from_line. */ - case '\0': - tor_fragile_assert(); - tor_free(*result); - return NULL; - /* LCOV_EXCL_STOP */ - case '\\': - switch (cp[1]) - { - case 'n': *out++ = '\n'; cp += 2; break; - case 'r': *out++ = '\r'; cp += 2; break; - case 't': *out++ = '\t'; cp += 2; break; - case 'x': case 'X': - { - int x1, x2; - - x1 = hex_decode_digit(cp[2]); - x2 = hex_decode_digit(cp[3]); - if (x1 == -1 || x2 == -1) { - /* LCOV_EXCL_START */ - /* we caught this above in the initial loop. */ - tor_assert_nonfatal_unreached(); - tor_free(*result); - return NULL; - /* LCOV_EXCL_STOP */ - } - - *out++ = ((x1<<4) + x2); - cp += 4; - } - break; - case '0': case '1': case '2': case '3': case '4': case '5': - case '6': case '7': - { - int n = cp[1]-'0'; - cp += 2; - if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; } - if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; } - if (n > 255) { tor_free(*result); return NULL; } - *out++ = (char)n; - } - break; - case '\'': - case '\"': - case '\\': - case '\?': - *out++ = cp[1]; - cp += 2; - break; - - /* LCOV_EXCL_START */ - default: - /* we caught this above in the initial loop. */ - tor_assert_nonfatal_unreached(); - tor_free(*result); return NULL; - /* LCOV_EXCL_STOP */ - } - break; - default: - *out++ = *cp++; - } - } -} - -/** Removes enclosing quotes from <b>path</b> and unescapes quotes between the - * enclosing quotes. Backslashes are not unescaped. Return the unquoted - * <b>path</b> on success or 0 if <b>path</b> is not quoted correctly. */ -char * -get_unquoted_path(const char *path) -{ - size_t len = strlen(path); - - if (len == 0) { - return tor_strdup(""); - } - - int has_start_quote = (path[0] == '\"'); - int has_end_quote = (len > 0 && path[len-1] == '\"'); - if (has_start_quote != has_end_quote || (len == 1 && has_start_quote)) { - return NULL; - } - - char *unquoted_path = tor_malloc(len - has_start_quote - has_end_quote + 1); - char *s = unquoted_path; - size_t i; - for (i = has_start_quote; i < len - has_end_quote; i++) { - if (path[i] == '\"' && (i > 0 && path[i-1] == '\\')) { - *(s-1) = path[i]; - } else if (path[i] != '\"') { - *s++ = path[i]; - } else { /* unescaped quote */ - tor_free(unquoted_path); - return NULL; - } - } - *s = '\0'; - return unquoted_path; -} - -/** Expand any homedir prefix on <b>filename</b>; return a newly allocated - * string. */ -char * -expand_filename(const char *filename) -{ - tor_assert(filename); -#ifdef _WIN32 - /* Might consider using GetFullPathName() as described here: - * http://etutorials.org/Programming/secure+programming/ - * Chapter+3.+Input+Validation/3.7+Validating+Filenames+and+Paths/ - */ - return tor_strdup(filename); -#else /* !(defined(_WIN32)) */ - if (*filename == '~') { - char *home, *result=NULL; - const char *rest; - - if (filename[1] == '/' || filename[1] == '\0') { - home = getenv("HOME"); - if (!home) { - log_warn(LD_CONFIG, "Couldn't find $HOME environment variable while " - "expanding \"%s\"; defaulting to \"\".", filename); - home = tor_strdup(""); - } else { - home = tor_strdup(home); - } - rest = strlen(filename)>=2?(filename+2):""; - } else { -#ifdef HAVE_PWD_H - char *username, *slash; - slash = strchr(filename, '/'); - if (slash) - username = tor_strndup(filename+1,slash-filename-1); - else - username = tor_strdup(filename+1); - if (!(home = get_user_homedir(username))) { - log_warn(LD_CONFIG,"Couldn't get homedir for \"%s\"",username); - tor_free(username); - return NULL; - } - tor_free(username); - rest = slash ? (slash+1) : ""; -#else /* !(defined(HAVE_PWD_H)) */ - log_warn(LD_CONFIG, "Couldn't expand homedir on system without pwd.h"); - return tor_strdup(filename); -#endif /* defined(HAVE_PWD_H) */ - } - tor_assert(home); - /* Remove trailing slash. */ - if (strlen(home)>1 && !strcmpend(home,PATH_SEPARATOR)) { - home[strlen(home)-1] = '\0'; - } - tor_asprintf(&result,"%s"PATH_SEPARATOR"%s",home,rest); - tor_free(home); - return result; - } else { - return tor_strdup(filename); - } -#endif /* defined(_WIN32) */ -} - -#define MAX_SCANF_WIDTH 9999 - -/** Helper: given an ASCII-encoded decimal digit, return its numeric value. - * NOTE: requires that its input be in-bounds. */ -static int -digit_to_num(char d) -{ - int num = ((int)d) - (int)'0'; - tor_assert(num <= 9 && num >= 0); - return num; -} - -/** Helper: Read an unsigned int from *<b>bufp</b> of up to <b>width</b> - * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On - * success, store the result in <b>out</b>, advance bufp to the next - * character, and return 0. On failure, return -1. */ -static int -scan_unsigned(const char **bufp, unsigned long *out, int width, unsigned base) -{ - unsigned long result = 0; - int scanned_so_far = 0; - const int hex = base==16; - tor_assert(base == 10 || base == 16); - if (!bufp || !*bufp || !out) - return -1; - if (width<0) - width=MAX_SCANF_WIDTH; - - while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp)) - && scanned_so_far < width) { - unsigned digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++); - // Check for overflow beforehand, without actually causing any overflow - // This preserves functionality on compilers that don't wrap overflow - // (i.e. that trap or optimise away overflow) - // result * base + digit > ULONG_MAX - // result * base > ULONG_MAX - digit - if (result > (ULONG_MAX - digit)/base) - return -1; /* Processing this digit would overflow */ - result = result * base + digit; - ++scanned_so_far; - } - - if (!scanned_so_far) /* No actual digits scanned */ - return -1; - - *out = result; - return 0; -} - -/** Helper: Read an signed int from *<b>bufp</b> of up to <b>width</b> - * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On - * success, store the result in <b>out</b>, advance bufp to the next - * character, and return 0. On failure, return -1. */ -static int -scan_signed(const char **bufp, long *out, int width) -{ - int neg = 0; - unsigned long result = 0; - - if (!bufp || !*bufp || !out) - return -1; - if (width<0) - width=MAX_SCANF_WIDTH; - - if (**bufp == '-') { - neg = 1; - ++*bufp; - --width; - } - - if (scan_unsigned(bufp, &result, width, 10) < 0) - return -1; - - if (neg && result > 0) { - if (result > ((unsigned long)LONG_MAX) + 1) - return -1; /* Underflow */ - else if (result == ((unsigned long)LONG_MAX) + 1) - *out = LONG_MIN; - else { - /* We once had a far more clever no-overflow conversion here, but - * some versions of GCC apparently ran it into the ground. Now - * we just check for LONG_MIN explicitly. - */ - *out = -(long)result; - } - } else { - if (result > LONG_MAX) - return -1; /* Overflow */ - *out = (long)result; - } - - return 0; -} - -/** Helper: Read a decimal-formatted double from *<b>bufp</b> of up to - * <b>width</b> characters. (Handle arbitrary width if <b>width</b> is less - * than 0.) On success, store the result in <b>out</b>, advance bufp to the - * next character, and return 0. On failure, return -1. */ -static int -scan_double(const char **bufp, double *out, int width) -{ - int neg = 0; - double result = 0; - int scanned_so_far = 0; - - if (!bufp || !*bufp || !out) - return -1; - if (width<0) - width=MAX_SCANF_WIDTH; - - if (**bufp == '-') { - neg = 1; - ++*bufp; - } - - while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) { - const int digit = digit_to_num(*(*bufp)++); - result = result * 10 + digit; - ++scanned_so_far; - } - if (**bufp == '.') { - double fracval = 0, denominator = 1; - ++*bufp; - ++scanned_so_far; - while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) { - const int digit = digit_to_num(*(*bufp)++); - fracval = fracval * 10 + digit; - denominator *= 10; - ++scanned_so_far; - } - result += fracval / denominator; - } - - if (!scanned_so_far) /* No actual digits scanned */ - return -1; - - *out = neg ? -result : result; - return 0; -} - -/** Helper: copy up to <b>width</b> non-space characters from <b>bufp</b> to - * <b>out</b>. Make sure <b>out</b> is nul-terminated. Advance <b>bufp</b> - * to the next non-space character or the EOS. */ -static int -scan_string(const char **bufp, char *out, int width) -{ - int scanned_so_far = 0; - if (!bufp || !out || width < 0) - return -1; - while (**bufp && ! TOR_ISSPACE(**bufp) && scanned_so_far < width) { - *out++ = *(*bufp)++; - ++scanned_so_far; - } - *out = '\0'; - return 0; -} - -/** Locale-independent, minimal, no-surprises scanf variant, accepting only a - * restricted pattern format. For more info on what it supports, see - * tor_sscanf() documentation. */ -int -tor_vsscanf(const char *buf, const char *pattern, va_list ap) -{ - int n_matched = 0; - - while (*pattern) { - if (*pattern != '%') { - if (*buf == *pattern) { - ++buf; - ++pattern; - continue; - } else { - return n_matched; - } - } else { - int width = -1; - int longmod = 0; - ++pattern; - if (TOR_ISDIGIT(*pattern)) { - width = digit_to_num(*pattern++); - while (TOR_ISDIGIT(*pattern)) { - width *= 10; - width += digit_to_num(*pattern++); - if (width > MAX_SCANF_WIDTH) - return -1; - } - if (!width) /* No zero-width things. */ - return -1; - } - if (*pattern == 'l') { - longmod = 1; - ++pattern; - } - if (*pattern == 'u' || *pattern == 'x') { - unsigned long u; - const int base = (*pattern == 'u') ? 10 : 16; - if (!*buf) - return n_matched; - if (scan_unsigned(&buf, &u, width, base)<0) - return n_matched; - if (longmod) { - unsigned long *out = va_arg(ap, unsigned long *); - *out = u; - } else { - unsigned *out = va_arg(ap, unsigned *); - if (u > UINT_MAX) - return n_matched; - *out = (unsigned) u; - } - ++pattern; - ++n_matched; - } else if (*pattern == 'f') { - double *d = va_arg(ap, double *); - if (!longmod) - return -1; /* float not supported */ - if (!*buf) - return n_matched; - if (scan_double(&buf, d, width)<0) - return n_matched; - ++pattern; - ++n_matched; - } else if (*pattern == 'd') { - long lng=0; - if (scan_signed(&buf, &lng, width)<0) - return n_matched; - if (longmod) { - long *out = va_arg(ap, long *); - *out = lng; - } else { - int *out = va_arg(ap, int *); -#if LONG_MAX > INT_MAX - if (lng < INT_MIN || lng > INT_MAX) - return n_matched; -#endif - *out = (int)lng; - } - ++pattern; - ++n_matched; - } else if (*pattern == 's') { - char *s = va_arg(ap, char *); - if (longmod) - return -1; - if (width < 0) - return -1; - if (scan_string(&buf, s, width)<0) - return n_matched; - ++pattern; - ++n_matched; - } else if (*pattern == 'c') { - char *ch = va_arg(ap, char *); - if (longmod) - return -1; - if (width != -1) - return -1; - if (!*buf) - return n_matched; - *ch = *buf++; - ++pattern; - ++n_matched; - } else if (*pattern == '%') { - if (*buf != '%') - return n_matched; - if (longmod) - return -1; - ++buf; - ++pattern; - } else { - return -1; /* Unrecognized pattern component. */ - } - } - } - - return n_matched; -} - -/** Minimal sscanf replacement: parse <b>buf</b> according to <b>pattern</b> - * and store the results in the corresponding argument fields. Differs from - * sscanf in that: - * <ul><li>It only handles %u, %lu, %x, %lx, %[NUM]s, %d, %ld, %lf, and %c. - * <li>It only handles decimal inputs for %lf. (12.3, not 1.23e1) - * <li>It does not handle arbitrarily long widths. - * <li>Numbers do not consume any space characters. - * <li>It is locale-independent. - * <li>%u and %x do not consume any space. - * <li>It returns -1 on malformed patterns.</ul> - * - * (As with other locale-independent functions, we need this to parse data that - * is in ASCII without worrying that the C library's locale-handling will make - * miscellaneous characters look like numbers, spaces, and so on.) - */ -int -tor_sscanf(const char *buf, const char *pattern, ...) -{ - int r; - va_list ap; - va_start(ap, pattern); - r = tor_vsscanf(buf, pattern, ap); - va_end(ap); - return r; -} - -/** Append the string produced by tor_asprintf(<b>pattern</b>, <b>...</b>) - * to <b>sl</b>. */ -void -smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...) -{ - va_list ap; - va_start(ap, pattern); - smartlist_add_vasprintf(sl, pattern, ap); - va_end(ap); -} - -/** va_list-based backend of smartlist_add_asprintf. */ -void -smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern, - va_list args) -{ - char *str = NULL; - - tor_vasprintf(&str, pattern, args); - tor_assert(str != NULL); - - smartlist_add(sl, str); -} - -/** Append a copy of string to sl */ -void -smartlist_add_strdup(struct smartlist_t *sl, const char *string) -{ - char *copy; - - copy = tor_strdup(string); - - smartlist_add(sl, copy); -} - -/** Return a new list containing the filenames in the directory <b>dirname</b>. - * Return NULL on error or if <b>dirname</b> is not a directory. - */ -MOCK_IMPL(smartlist_t *, -tor_listdir, (const char *dirname)) -{ - smartlist_t *result; -#ifdef _WIN32 - char *pattern=NULL; - TCHAR tpattern[MAX_PATH] = {0}; - char name[MAX_PATH*2+1] = {0}; - HANDLE handle; - WIN32_FIND_DATA findData; - tor_asprintf(&pattern, "%s\\*", dirname); -#ifdef UNICODE - mbstowcs(tpattern,pattern,MAX_PATH); -#else - strlcpy(tpattern, pattern, MAX_PATH); -#endif - if (INVALID_HANDLE_VALUE == (handle = FindFirstFile(tpattern, &findData))) { - tor_free(pattern); - return NULL; - } - result = smartlist_new(); - while (1) { -#ifdef UNICODE - wcstombs(name,findData.cFileName,MAX_PATH); - name[sizeof(name)-1] = '\0'; -#else - strlcpy(name,findData.cFileName,sizeof(name)); -#endif /* defined(UNICODE) */ - if (strcmp(name, ".") && - strcmp(name, "..")) { - smartlist_add_strdup(result, name); - } - if (!FindNextFile(handle, &findData)) { - DWORD err; - if ((err = GetLastError()) != ERROR_NO_MORE_FILES) { - char *errstr = format_win32_error(err); - log_warn(LD_FS, "Error reading directory '%s': %s", dirname, errstr); - tor_free(errstr); - } - break; - } - } - FindClose(handle); - tor_free(pattern); -#else /* !(defined(_WIN32)) */ - const char *prot_dname = sandbox_intern_string(dirname); - DIR *d; - struct dirent *de; - if (!(d = opendir(prot_dname))) - return NULL; - - result = smartlist_new(); - while ((de = readdir(d))) { - if (!strcmp(de->d_name, ".") || - !strcmp(de->d_name, "..")) - continue; - smartlist_add_strdup(result, de->d_name); - } - closedir(d); -#endif /* defined(_WIN32) */ - return result; -} - -/** Return true iff <b>filename</b> is a relative path. */ -int -path_is_relative(const char *filename) -{ - if (filename && filename[0] == '/') - return 0; -#ifdef _WIN32 - else if (filename && filename[0] == '\\') - return 0; - else if (filename && strlen(filename)>3 && TOR_ISALPHA(filename[0]) && - filename[1] == ':' && filename[2] == '\\') - return 0; -#endif /* defined(_WIN32) */ - else - return 1; -} - -/* ===== - * Process helpers - * ===== */ - -#ifndef _WIN32 -/* Based on code contributed by christian grothoff */ -/** True iff we've called start_daemon(). */ -static int start_daemon_called = 0; -/** True iff we've called finish_daemon(). */ -static int finish_daemon_called = 0; -/** Socketpair used to communicate between parent and child process while - * daemonizing. */ -static int daemon_filedes[2]; -/** Start putting the process into daemon mode: fork and drop all resources - * except standard fds. The parent process never returns, but stays around - * until finish_daemon is called. (Note: it's safe to call this more - * than once: calls after the first are ignored.) - */ -void -start_daemon(void) -{ - pid_t pid; - - if (start_daemon_called) - return; - start_daemon_called = 1; - - if (pipe(daemon_filedes)) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"pipe failed; exiting. Error was %s", strerror(errno)); - exit(1); // exit ok: during daemonize, pipe failed. - /* LCOV_EXCL_STOP */ - } - pid = fork(); - if (pid < 0) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"fork failed. Exiting."); - exit(1); // exit ok: during daemonize, fork failed - /* LCOV_EXCL_STOP */ - } - if (pid) { /* Parent */ - int ok; - char c; - - close(daemon_filedes[1]); /* we only read */ - ok = -1; - while (0 < read(daemon_filedes[0], &c, sizeof(char))) { - if (c == '.') - ok = 1; - } - fflush(stdout); - if (ok == 1) - exit(0); // exit ok: during daemonize, daemonizing. - else - exit(1); /* child reported error. exit ok: daemonize failed. */ - } else { /* Child */ - close(daemon_filedes[0]); /* we only write */ - - (void) setsid(); /* Detach from controlling terminal */ - /* - * Fork one more time, so the parent (the session group leader) can exit. - * This means that we, as a non-session group leader, can never regain a - * controlling terminal. This part is recommended by Stevens's - * _Advanced Programming in the Unix Environment_. - */ - if (fork() != 0) { - exit(0); // exit ok: during daemonize, fork failed (2) - } - set_main_thread(); /* We are now the main thread. */ - - return; - } -} - -/** Finish putting the process into daemon mode: drop standard fds, and tell - * the parent process to exit. (Note: it's safe to call this more than once: - * calls after the first are ignored. Calls start_daemon first if it hasn't - * been called already.) - */ -void -finish_daemon(const char *desired_cwd) -{ - int nullfd; - char c = '.'; - if (finish_daemon_called) - return; - if (!start_daemon_called) - start_daemon(); - finish_daemon_called = 1; - - if (!desired_cwd) - desired_cwd = "/"; - /* Don't hold the wrong FS mounted */ - if (chdir(desired_cwd) < 0) { - log_err(LD_GENERAL,"chdir to \"%s\" failed. Exiting.",desired_cwd); - exit(1); // exit ok: during daemonize, chdir failed. - } - - nullfd = tor_open_cloexec("/dev/null", O_RDWR, 0); - if (nullfd < 0) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"/dev/null can't be opened. Exiting."); - exit(1); // exit ok: during daemonize, couldn't open /dev/null - /* LCOV_EXCL_STOP */ - } - /* close fds linking to invoking terminal, but - * close usual incoming fds, but redirect them somewhere - * useful so the fds don't get reallocated elsewhere. - */ - if (dup2(nullfd,0) < 0 || - dup2(nullfd,1) < 0 || - dup2(nullfd,2) < 0) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"dup2 failed. Exiting."); - exit(1); // exit ok: during daemonize, dup2 failed. - /* LCOV_EXCL_STOP */ - } - if (nullfd > 2) - close(nullfd); - /* signal success */ - if (write(daemon_filedes[1], &c, sizeof(char)) != sizeof(char)) { - log_err(LD_GENERAL,"write failed. Exiting."); - } - close(daemon_filedes[1]); -} -#else /* !(!defined(_WIN32)) */ -/* defined(_WIN32) */ -void -start_daemon(void) -{ -} -void -finish_daemon(const char *cp) -{ - (void)cp; -} -#endif /* !defined(_WIN32) */ - -/** Write the current process ID, followed by NL, into <b>filename</b>. - * Return 0 on success, -1 on failure. - */ -int -write_pidfile(const char *filename) -{ - FILE *pidfile; - - if ((pidfile = fopen(filename, "w")) == NULL) { - log_warn(LD_FS, "Unable to open \"%s\" for writing: %s", filename, - strerror(errno)); - return -1; - } else { -#ifdef _WIN32 - int pid = (int)_getpid(); -#else - int pid = (int)getpid(); -#endif - int rv = 0; - if (fprintf(pidfile, "%d\n", pid) < 0) - rv = -1; - if (fclose(pidfile) < 0) - rv = -1; - return rv; - } -} - -#ifdef _WIN32 -HANDLE -load_windows_system_library(const TCHAR *library_name) -{ - TCHAR path[MAX_PATH]; - unsigned n; - n = GetSystemDirectory(path, MAX_PATH); - if (n == 0 || n + _tcslen(library_name) + 2 >= MAX_PATH) - return 0; - _tcscat(path, TEXT("\\")); - _tcscat(path, library_name); - return LoadLibrary(path); -} -#endif /* defined(_WIN32) */ - -/** Format a single argument for being put on a Windows command line. - * Returns a newly allocated string */ -static char * -format_win_cmdline_argument(const char *arg) -{ - char *formatted_arg; - char need_quotes; - const char *c; - int i; - int bs_counter = 0; - /* Backslash we can point to when one is inserted into the string */ - const char backslash = '\\'; - - /* Smartlist of *char */ - smartlist_t *arg_chars; - arg_chars = smartlist_new(); - - /* Quote string if it contains whitespace or is empty */ - need_quotes = (strchr(arg, ' ') || strchr(arg, '\t') || '\0' == arg[0]); - - /* Build up smartlist of *chars */ - for (c=arg; *c != '\0'; c++) { - if ('"' == *c) { - /* Double up backslashes preceding a quote */ - for (i=0; i<(bs_counter*2); i++) - smartlist_add(arg_chars, (void*)&backslash); - bs_counter = 0; - /* Escape the quote */ - smartlist_add(arg_chars, (void*)&backslash); - smartlist_add(arg_chars, (void*)c); - } else if ('\\' == *c) { - /* Count backslashes until we know whether to double up */ - bs_counter++; - } else { - /* Don't double up slashes preceding a non-quote */ - for (i=0; i<bs_counter; i++) - smartlist_add(arg_chars, (void*)&backslash); - bs_counter = 0; - smartlist_add(arg_chars, (void*)c); - } - } - /* Don't double up trailing backslashes */ - for (i=0; i<bs_counter; i++) - smartlist_add(arg_chars, (void*)&backslash); - - /* Allocate space for argument, quotes (if needed), and terminator */ - const size_t formatted_arg_len = smartlist_len(arg_chars) + - (need_quotes ? 2 : 0) + 1; - formatted_arg = tor_malloc_zero(formatted_arg_len); - - /* Add leading quote */ - i=0; - if (need_quotes) - formatted_arg[i++] = '"'; - - /* Add characters */ - SMARTLIST_FOREACH(arg_chars, char*, ch, - { - formatted_arg[i++] = *ch; - }); - - /* Add trailing quote */ - if (need_quotes) - formatted_arg[i++] = '"'; - formatted_arg[i] = '\0'; - - smartlist_free(arg_chars); - return formatted_arg; -} - -/** Format a command line for use on Windows, which takes the command as a - * string rather than string array. Follows the rules from "Parsing C++ - * Command-Line Arguments" in MSDN. Algorithm based on list2cmdline in the - * Python subprocess module. Returns a newly allocated string */ -char * -tor_join_win_cmdline(const char *argv[]) -{ - smartlist_t *argv_list; - char *joined_argv; - int i; - - /* Format each argument and put the result in a smartlist */ - argv_list = smartlist_new(); - for (i=0; argv[i] != NULL; i++) { - smartlist_add(argv_list, (void *)format_win_cmdline_argument(argv[i])); - } - - /* Join the arguments with whitespace */ - joined_argv = smartlist_join_strings(argv_list, " ", 0, NULL); - - /* Free the newly allocated arguments, and the smartlist */ - SMARTLIST_FOREACH(argv_list, char *, arg, - { - tor_free(arg); - }); - smartlist_free(argv_list); - - return joined_argv; -} - -/* As format_{hex,dex}_number_sigsafe, but takes a <b>radix</b> argument - * in range 2..16 inclusive. */ -static int -format_number_sigsafe(unsigned long x, char *buf, int buf_len, - unsigned int radix) -{ - unsigned long tmp; - int len; - char *cp; - - /* NOT tor_assert. This needs to be safe to run from within a signal handler, - * and from within the 'tor_assert() has failed' code. */ - if (radix < 2 || radix > 16) - return 0; - - /* Count how many digits we need. */ - tmp = x; - len = 1; - while (tmp >= radix) { - tmp /= radix; - ++len; - } - - /* Not long enough */ - if (!buf || len >= buf_len) - return 0; - - cp = buf + len; - *cp = '\0'; - do { - unsigned digit = (unsigned) (x % radix); - tor_assert(cp > buf); - --cp; - *cp = "0123456789ABCDEF"[digit]; - x /= radix; - } while (x); - - /* NOT tor_assert; see above. */ - if (cp != buf) { - abort(); // LCOV_EXCL_LINE - } - - return len; -} - -/** - * Helper function to output hex numbers from within a signal handler. - * - * Writes the nul-terminated hexadecimal digits of <b>x</b> into a buffer - * <b>buf</b> of size <b>buf_len</b>, and return the actual number of digits - * written, not counting the terminal NUL. - * - * If there is insufficient space, write nothing and return 0. - * - * This accepts an unsigned int because format_helper_exit_status() needs to - * call it with a signed int and an unsigned char, and since the C standard - * does not guarantee that an int is wider than a char (an int must be at - * least 16 bits but it is permitted for a char to be that wide as well), we - * can't assume a signed int is sufficient to accommodate an unsigned char. - * Thus, format_helper_exit_status() will still need to emit any require '-' - * on its own. - * - * For most purposes, you'd want to use tor_snprintf("%x") instead of this - * function; it's designed to be used in code paths where you can't call - * arbitrary C functions. - */ -int -format_hex_number_sigsafe(unsigned long x, char *buf, int buf_len) -{ - return format_number_sigsafe(x, buf, buf_len, 16); -} - -/** As format_hex_number_sigsafe, but format the number in base 10. */ -int -format_dec_number_sigsafe(unsigned long x, char *buf, int buf_len) -{ - return format_number_sigsafe(x, buf, buf_len, 10); -} - -#ifndef _WIN32 -/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in - * <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler - * safe. - * - * <b>hex_errno</b> must have at least HEX_ERRNO_SIZE+1 bytes available. - * - * The format of <b>hex_errno</b> is: "CHILD_STATE/ERRNO\n", left-padded - * with spaces. CHILD_STATE indicates where - * in the process of starting the child process did the failure occur (see - * CHILD_STATE_* macros for definition), and SAVED_ERRNO is the value of - * errno when the failure occurred. - * - * On success return the number of characters added to hex_errno, not counting - * the terminating NUL; return -1 on error. - */ -STATIC int -format_helper_exit_status(unsigned char child_state, int saved_errno, - char *hex_errno) -{ - unsigned int unsigned_errno; - int written, left; - char *cur; - size_t i; - int res = -1; - - /* Fill hex_errno with spaces, and a trailing newline (memset may - not be signal handler safe, so we can't use it) */ - for (i = 0; i < (HEX_ERRNO_SIZE - 1); i++) - hex_errno[i] = ' '; - hex_errno[HEX_ERRNO_SIZE - 1] = '\n'; - - /* Convert errno to be unsigned for hex conversion */ - if (saved_errno < 0) { - // Avoid overflow on the cast to unsigned int when result is INT_MIN - // by adding 1 to the signed int negative value, - // then, after it has been negated and cast to unsigned, - // adding the original 1 back (the double-addition is intentional). - // Otherwise, the cast to signed could cause a temporary int - // to equal INT_MAX + 1, which is undefined. - unsigned_errno = ((unsigned int) -(saved_errno + 1)) + 1; - } else { - unsigned_errno = (unsigned int) saved_errno; - } - - /* - * Count how many chars of space we have left, and keep a pointer into the - * current point in the buffer. - */ - left = HEX_ERRNO_SIZE+1; - cur = hex_errno; - - /* Emit child_state */ - written = format_hex_number_sigsafe(child_state, cur, left); - - if (written <= 0) - goto err; - - /* Adjust left and cur */ - left -= written; - cur += written; - if (left <= 0) - goto err; - - /* Now the '/' */ - *cur = '/'; - - /* Adjust left and cur */ - ++cur; - --left; - if (left <= 0) - goto err; - - /* Need minus? */ - if (saved_errno < 0) { - *cur = '-'; - ++cur; - --left; - if (left <= 0) - goto err; - } - - /* Emit unsigned_errno */ - written = format_hex_number_sigsafe(unsigned_errno, cur, left); - - if (written <= 0) - goto err; - - /* Adjust left and cur */ - left -= written; - cur += written; - - /* Check that we have enough space left for a newline and a NUL */ - if (left <= 1) - goto err; - - /* Emit the newline and NUL */ - *cur++ = '\n'; - *cur++ = '\0'; - - res = (int)(cur - hex_errno - 1); - - goto done; - - err: - /* - * In error exit, just write a '\0' in the first char so whatever called - * this at least won't fall off the end. - */ - *hex_errno = '\0'; - - done: - return res; -} -#endif /* !defined(_WIN32) */ - -/* Maximum number of file descriptors, if we cannot get it via sysconf() */ -#define DEFAULT_MAX_FD 256 - -/** Terminate the process of <b>process_handle</b>, if that process has not - * already exited. - * - * Return 0 if we succeeded in terminating the process (or if the process - * already exited), and -1 if we tried to kill the process but failed. - * - * Based on code originally borrowed from Python's os.kill. */ -int -tor_terminate_process(process_handle_t *process_handle) -{ -#ifdef _WIN32 - if (tor_get_exit_code(process_handle, 0, NULL) == PROCESS_EXIT_RUNNING) { - HANDLE handle = process_handle->pid.hProcess; - - if (!TerminateProcess(handle, 0)) - return -1; - else - return 0; - } -#else /* !(defined(_WIN32)) */ - if (process_handle->waitpid_cb) { - /* We haven't got a waitpid yet, so we can just kill off the process. */ - return kill(process_handle->pid, SIGTERM); - } -#endif /* defined(_WIN32) */ - - return 0; /* We didn't need to kill the process, so report success */ -} - -/** Return the Process ID of <b>process_handle</b>. */ -int -tor_process_get_pid(process_handle_t *process_handle) -{ -#ifdef _WIN32 - return (int) process_handle->pid.dwProcessId; -#else - return (int) process_handle->pid; -#endif -} - -#ifdef _WIN32 -HANDLE -tor_process_get_stdout_pipe(process_handle_t *process_handle) -{ - return process_handle->stdout_pipe; -} -#else /* !(defined(_WIN32)) */ -/* DOCDOC tor_process_get_stdout_pipe */ -int -tor_process_get_stdout_pipe(process_handle_t *process_handle) -{ - return process_handle->stdout_pipe; -} -#endif /* defined(_WIN32) */ - -/* DOCDOC process_handle_new */ -static process_handle_t * -process_handle_new(void) -{ - process_handle_t *out = tor_malloc_zero(sizeof(process_handle_t)); - -#ifdef _WIN32 - out->stdin_pipe = INVALID_HANDLE_VALUE; - out->stdout_pipe = INVALID_HANDLE_VALUE; - out->stderr_pipe = INVALID_HANDLE_VALUE; -#else - out->stdin_pipe = -1; - out->stdout_pipe = -1; - out->stderr_pipe = -1; -#endif /* defined(_WIN32) */ - - return out; -} - -#ifndef _WIN32 -/** Invoked when a process that we've launched via tor_spawn_background() has - * been found to have terminated. - */ -static void -process_handle_waitpid_cb(int status, void *arg) -{ - process_handle_t *process_handle = arg; - - process_handle->waitpid_exit_status = status; - clear_waitpid_callback(process_handle->waitpid_cb); - if (process_handle->status == PROCESS_STATUS_RUNNING) - process_handle->status = PROCESS_STATUS_NOTRUNNING; - process_handle->waitpid_cb = 0; -} -#endif /* !defined(_WIN32) */ - -/** - * @name child-process states - * - * Each of these values represents a possible state that a child process can - * be in. They're used to determine what to say when telling the parent how - * far along we were before failure. - * - * @{ - */ -#define CHILD_STATE_INIT 0 -#define CHILD_STATE_PIPE 1 -#define CHILD_STATE_MAXFD 2 -#define CHILD_STATE_FORK 3 -#define CHILD_STATE_DUPOUT 4 -#define CHILD_STATE_DUPERR 5 -#define CHILD_STATE_DUPIN 6 -#define CHILD_STATE_CLOSEFD 7 -#define CHILD_STATE_EXEC 8 -#define CHILD_STATE_FAILEXEC 9 -/** @} */ -/** - * Boolean. If true, then Tor may call execve or CreateProcess via - * tor_spawn_background. - **/ -static int may_spawn_background_process = 1; -/** - * Turn off may_spawn_background_process, so that all future calls to - * tor_spawn_background are guaranteed to fail. - **/ -void -tor_disable_spawning_background_processes(void) -{ - may_spawn_background_process = 0; -} -/** Start a program in the background. If <b>filename</b> contains a '/', then - * it will be treated as an absolute or relative path. Otherwise, on - * non-Windows systems, the system path will be searched for <b>filename</b>. - * On Windows, only the current directory will be searched. Here, to search the - * system path (as well as the application directory, current working - * directory, and system directories), set filename to NULL. - * - * The strings in <b>argv</b> will be passed as the command line arguments of - * the child program (following convention, argv[0] should normally be the - * filename of the executable, and this must be the case if <b>filename</b> is - * NULL). The last element of argv must be NULL. A handle to the child process - * will be returned in process_handle (which must be non-NULL). Read - * process_handle.status to find out if the process was successfully launched. - * For convenience, process_handle.status is returned by this function. - * - * Some parts of this code are based on the POSIX subprocess module from - * Python, and example code from - * http://msdn.microsoft.com/en-us/library/ms682499%28v=vs.85%29.aspx. - */ -int -tor_spawn_background(const char *const filename, const char **argv, - process_environment_t *env, - process_handle_t **process_handle_out) -{ - if (BUG(may_spawn_background_process == 0)) { - /* We should never reach this point if we're forbidden to spawn - * processes. Instead we should have caught the attempt earlier. */ - return PROCESS_STATUS_ERROR; - } - -#ifdef _WIN32 - HANDLE stdout_pipe_read = NULL; - HANDLE stdout_pipe_write = NULL; - HANDLE stderr_pipe_read = NULL; - HANDLE stderr_pipe_write = NULL; - HANDLE stdin_pipe_read = NULL; - HANDLE stdin_pipe_write = NULL; - process_handle_t *process_handle; - int status; - - STARTUPINFOA siStartInfo; - BOOL retval = FALSE; - - SECURITY_ATTRIBUTES saAttr; - char *joined_argv; - - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - /* TODO: should we set explicit security attributes? (#2046, comment 5) */ - saAttr.lpSecurityDescriptor = NULL; - - /* Assume failure to start process */ - status = PROCESS_STATUS_ERROR; - - /* Set up pipe for stdout */ - if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, &saAttr, 0)) { - log_warn(LD_GENERAL, - "Failed to create pipe for stdout communication with child process: %s", - format_win32_error(GetLastError())); - return status; - } - if (!SetHandleInformation(stdout_pipe_read, HANDLE_FLAG_INHERIT, 0)) { - log_warn(LD_GENERAL, - "Failed to configure pipe for stdout communication with child " - "process: %s", format_win32_error(GetLastError())); - return status; - } - - /* Set up pipe for stderr */ - if (!CreatePipe(&stderr_pipe_read, &stderr_pipe_write, &saAttr, 0)) { - log_warn(LD_GENERAL, - "Failed to create pipe for stderr communication with child process: %s", - format_win32_error(GetLastError())); - return status; - } - if (!SetHandleInformation(stderr_pipe_read, HANDLE_FLAG_INHERIT, 0)) { - log_warn(LD_GENERAL, - "Failed to configure pipe for stderr communication with child " - "process: %s", format_win32_error(GetLastError())); - return status; - } - - /* Set up pipe for stdin */ - if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, &saAttr, 0)) { - log_warn(LD_GENERAL, - "Failed to create pipe for stdin communication with child process: %s", - format_win32_error(GetLastError())); - return status; - } - if (!SetHandleInformation(stdin_pipe_write, HANDLE_FLAG_INHERIT, 0)) { - log_warn(LD_GENERAL, - "Failed to configure pipe for stdin communication with child " - "process: %s", format_win32_error(GetLastError())); - return status; - } - - /* Create the child process */ - - /* Windows expects argv to be a whitespace delimited string, so join argv up - */ - joined_argv = tor_join_win_cmdline(argv); - - process_handle = process_handle_new(); - process_handle->status = status; - - ZeroMemory(&(process_handle->pid), sizeof(PROCESS_INFORMATION)); - ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); - siStartInfo.cb = sizeof(STARTUPINFO); - siStartInfo.hStdError = stderr_pipe_write; - siStartInfo.hStdOutput = stdout_pipe_write; - siStartInfo.hStdInput = stdin_pipe_read; - siStartInfo.dwFlags |= STARTF_USESTDHANDLES; - - /* Create the child process */ - - retval = CreateProcessA(filename, // module name - joined_argv, // command line - /* TODO: should we set explicit security attributes? (#2046, comment 5) */ - NULL, // process security attributes - NULL, // primary thread security attributes - TRUE, // handles are inherited - /*(TODO: set CREATE_NEW CONSOLE/PROCESS_GROUP to make GetExitCodeProcess() - * work?) */ - CREATE_NO_WINDOW, // creation flags - (env==NULL) ? NULL : env->windows_environment_block, - NULL, // use parent's current directory - &siStartInfo, // STARTUPINFO pointer - &(process_handle->pid)); // receives PROCESS_INFORMATION - - tor_free(joined_argv); - - if (!retval) { - log_warn(LD_GENERAL, - "Failed to create child process %s: %s", filename?filename:argv[0], - format_win32_error(GetLastError())); - tor_free(process_handle); - } else { - /* TODO: Close hProcess and hThread in process_handle->pid? */ - process_handle->stdout_pipe = stdout_pipe_read; - process_handle->stderr_pipe = stderr_pipe_read; - process_handle->stdin_pipe = stdin_pipe_write; - status = process_handle->status = PROCESS_STATUS_RUNNING; - } - - /* TODO: Close pipes on exit */ - *process_handle_out = process_handle; - return status; -#else /* !(defined(_WIN32)) */ - pid_t pid; - int stdout_pipe[2]; - int stderr_pipe[2]; - int stdin_pipe[2]; - int fd, retval; - process_handle_t *process_handle; - int status; - - const char *error_message = SPAWN_ERROR_MESSAGE; - size_t error_message_length; - - /* Represents where in the process of spawning the program is; - this is used for printing out the error message */ - unsigned char child_state = CHILD_STATE_INIT; - - char hex_errno[HEX_ERRNO_SIZE + 2]; /* + 1 should be sufficient actually */ - - static int max_fd = -1; - - status = PROCESS_STATUS_ERROR; - - /* We do the strlen here because strlen() is not signal handler safe, - and we are not allowed to use unsafe functions between fork and exec */ - error_message_length = strlen(error_message); - - // child_state = CHILD_STATE_PIPE; - - /* Set up pipe for redirecting stdout, stderr, and stdin of child */ - retval = pipe(stdout_pipe); - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to set up pipe for stdout communication with child process: %s", - strerror(errno)); - return status; - } - - retval = pipe(stderr_pipe); - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to set up pipe for stderr communication with child process: %s", - strerror(errno)); - - close(stdout_pipe[0]); - close(stdout_pipe[1]); - - return status; - } - - retval = pipe(stdin_pipe); - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to set up pipe for stdin communication with child process: %s", - strerror(errno)); - - close(stdout_pipe[0]); - close(stdout_pipe[1]); - close(stderr_pipe[0]); - close(stderr_pipe[1]); - - return status; - } - - // child_state = CHILD_STATE_MAXFD; - -#ifdef _SC_OPEN_MAX - if (-1 == max_fd) { - max_fd = (int) sysconf(_SC_OPEN_MAX); - if (max_fd == -1) { - max_fd = DEFAULT_MAX_FD; - log_warn(LD_GENERAL, - "Cannot find maximum file descriptor, assuming %d", max_fd); - } - } -#else /* !(defined(_SC_OPEN_MAX)) */ - max_fd = DEFAULT_MAX_FD; -#endif /* defined(_SC_OPEN_MAX) */ - - // child_state = CHILD_STATE_FORK; - - pid = fork(); - if (0 == pid) { - /* In child */ - -#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) - /* Attempt to have the kernel issue a SIGTERM if the parent - * goes away. Certain attributes of the binary being execve()ed - * will clear this during the execve() call, but it's better - * than nothing. - */ - prctl(PR_SET_PDEATHSIG, SIGTERM); -#endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) */ - - child_state = CHILD_STATE_DUPOUT; - - /* Link child stdout to the write end of the pipe */ - retval = dup2(stdout_pipe[1], STDOUT_FILENO); - if (-1 == retval) - goto error; - - child_state = CHILD_STATE_DUPERR; - - /* Link child stderr to the write end of the pipe */ - retval = dup2(stderr_pipe[1], STDERR_FILENO); - if (-1 == retval) - goto error; - - child_state = CHILD_STATE_DUPIN; - - /* Link child stdin to the read end of the pipe */ - retval = dup2(stdin_pipe[0], STDIN_FILENO); - if (-1 == retval) - goto error; - - // child_state = CHILD_STATE_CLOSEFD; - - close(stderr_pipe[0]); - close(stderr_pipe[1]); - close(stdout_pipe[0]); - close(stdout_pipe[1]); - close(stdin_pipe[0]); - close(stdin_pipe[1]); - - /* Close all other fds, including the read end of the pipe */ - /* XXX: We should now be doing enough FD_CLOEXEC setting to make - * this needless. */ - for (fd = STDERR_FILENO + 1; fd < max_fd; fd++) { - close(fd); - } - - // child_state = CHILD_STATE_EXEC; - - /* Call the requested program. We need the cast because - execvp doesn't define argv as const, even though it - does not modify the arguments */ - if (env) - execve(filename, (char *const *) argv, env->unixoid_environment_block); - else { - static char *new_env[] = { NULL }; - execve(filename, (char *const *) argv, new_env); - } - - /* If we got here, the exec or open(/dev/null) failed */ - - child_state = CHILD_STATE_FAILEXEC; - - error: - { - /* XXX: are we leaking fds from the pipe? */ - int n, err=0; - ssize_t nbytes; - - n = format_helper_exit_status(child_state, errno, hex_errno); - - if (n >= 0) { - /* Write the error message. GCC requires that we check the return - value, but there is nothing we can do if it fails */ - /* TODO: Don't use STDOUT, use a pipe set up just for this purpose */ - nbytes = write(STDOUT_FILENO, error_message, error_message_length); - err = (nbytes < 0); - nbytes = write(STDOUT_FILENO, hex_errno, n); - err += (nbytes < 0); - } - - _exit(err?254:255); // exit ok: in child. - } - - /* Never reached, but avoids compiler warning */ - return status; // LCOV_EXCL_LINE - } - - /* In parent */ - - if (-1 == pid) { - log_warn(LD_GENERAL, "Failed to fork child process: %s", strerror(errno)); - close(stdin_pipe[0]); - close(stdin_pipe[1]); - close(stdout_pipe[0]); - close(stdout_pipe[1]); - close(stderr_pipe[0]); - close(stderr_pipe[1]); - return status; - } - - process_handle = process_handle_new(); - process_handle->status = status; - process_handle->pid = pid; - - /* TODO: If the child process forked but failed to exec, waitpid it */ - - /* Return read end of the pipes to caller, and close write end */ - process_handle->stdout_pipe = stdout_pipe[0]; - retval = close(stdout_pipe[1]); - - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to close write end of stdout pipe in parent process: %s", - strerror(errno)); - } - - process_handle->waitpid_cb = set_waitpid_callback(pid, - process_handle_waitpid_cb, - process_handle); - - process_handle->stderr_pipe = stderr_pipe[0]; - retval = close(stderr_pipe[1]); - - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to close write end of stderr pipe in parent process: %s", - strerror(errno)); - } - - /* Return write end of the stdin pipe to caller, and close the read end */ - process_handle->stdin_pipe = stdin_pipe[1]; - retval = close(stdin_pipe[0]); - - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to close read end of stdin pipe in parent process: %s", - strerror(errno)); - } - - status = process_handle->status = PROCESS_STATUS_RUNNING; - /* Set stdin/stdout/stderr pipes to be non-blocking */ - if (fcntl(process_handle->stdout_pipe, F_SETFL, O_NONBLOCK) < 0 || - fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK) < 0 || - fcntl(process_handle->stdin_pipe, F_SETFL, O_NONBLOCK) < 0) { - log_warn(LD_GENERAL, "Failed to set stderror/stdout/stdin pipes " - "nonblocking in parent process: %s", strerror(errno)); - } - - *process_handle_out = process_handle; - return status; -#endif /* defined(_WIN32) */ -} - -/** Destroy all resources allocated by the process handle in - * <b>process_handle</b>. - * If <b>also_terminate_process</b> is true, also terminate the - * process of the process handle. */ -MOCK_IMPL(void, -tor_process_handle_destroy,(process_handle_t *process_handle, - int also_terminate_process)) -{ - if (!process_handle) - return; - - if (also_terminate_process) { - if (tor_terminate_process(process_handle) < 0) { - const char *errstr = -#ifdef _WIN32 - format_win32_error(GetLastError()); -#else - strerror(errno); -#endif - log_notice(LD_GENERAL, "Failed to terminate process with " - "PID '%d' ('%s').", tor_process_get_pid(process_handle), - errstr); - } else { - log_info(LD_GENERAL, "Terminated process with PID '%d'.", - tor_process_get_pid(process_handle)); - } - } - - process_handle->status = PROCESS_STATUS_NOTRUNNING; - -#ifdef _WIN32 - if (process_handle->stdout_pipe) - CloseHandle(process_handle->stdout_pipe); - - if (process_handle->stderr_pipe) - CloseHandle(process_handle->stderr_pipe); - - if (process_handle->stdin_pipe) - CloseHandle(process_handle->stdin_pipe); -#else /* !(defined(_WIN32)) */ - close(process_handle->stdout_pipe); - close(process_handle->stderr_pipe); - close(process_handle->stdin_pipe); - - clear_waitpid_callback(process_handle->waitpid_cb); -#endif /* defined(_WIN32) */ - - memset(process_handle, 0x0f, sizeof(process_handle_t)); - tor_free(process_handle); -} - -/** Get the exit code of a process specified by <b>process_handle</b> and store - * it in <b>exit_code</b>, if set to a non-NULL value. If <b>block</b> is set - * to true, the call will block until the process has exited. Otherwise if - * the process is still running, the function will return - * PROCESS_EXIT_RUNNING, and exit_code will be left unchanged. Returns - * PROCESS_EXIT_EXITED if the process did exit. If there is a failure, - * PROCESS_EXIT_ERROR will be returned and the contents of exit_code (if - * non-NULL) will be undefined. N.B. Under *nix operating systems, this will - * probably not work in Tor, because waitpid() is called in main.c to reap any - * terminated child processes.*/ -int -tor_get_exit_code(process_handle_t *process_handle, - int block, int *exit_code) -{ -#ifdef _WIN32 - DWORD retval; - BOOL success; - - if (block) { - /* Wait for the process to exit */ - retval = WaitForSingleObject(process_handle->pid.hProcess, INFINITE); - if (retval != WAIT_OBJECT_0) { - log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s", - (int)retval, format_win32_error(GetLastError())); - return PROCESS_EXIT_ERROR; - } - } else { - retval = WaitForSingleObject(process_handle->pid.hProcess, 0); - if (WAIT_TIMEOUT == retval) { - /* Process has not exited */ - return PROCESS_EXIT_RUNNING; - } else if (retval != WAIT_OBJECT_0) { - log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s", - (int)retval, format_win32_error(GetLastError())); - return PROCESS_EXIT_ERROR; - } - } - - if (exit_code != NULL) { - success = GetExitCodeProcess(process_handle->pid.hProcess, - (PDWORD)exit_code); - if (!success) { - log_warn(LD_GENERAL, "GetExitCodeProcess() failed: %s", - format_win32_error(GetLastError())); - return PROCESS_EXIT_ERROR; - } - } -#else /* !(defined(_WIN32)) */ - int stat_loc; - int retval; - - if (process_handle->waitpid_cb) { - /* We haven't processed a SIGCHLD yet. */ - retval = waitpid(process_handle->pid, &stat_loc, block?0:WNOHANG); - if (retval == process_handle->pid) { - clear_waitpid_callback(process_handle->waitpid_cb); - process_handle->waitpid_cb = NULL; - process_handle->waitpid_exit_status = stat_loc; - } - } else { - /* We already got a SIGCHLD for this process, and handled it. */ - retval = process_handle->pid; - stat_loc = process_handle->waitpid_exit_status; - } - - if (!block && 0 == retval) { - /* Process has not exited */ - return PROCESS_EXIT_RUNNING; - } else if (retval != process_handle->pid) { - log_warn(LD_GENERAL, "waitpid() failed for PID %d: %s", - (int)process_handle->pid, strerror(errno)); - return PROCESS_EXIT_ERROR; - } - - if (!WIFEXITED(stat_loc)) { - log_warn(LD_GENERAL, "Process %d did not exit normally", - (int)process_handle->pid); - return PROCESS_EXIT_ERROR; - } - - if (exit_code != NULL) - *exit_code = WEXITSTATUS(stat_loc); -#endif /* defined(_WIN32) */ - - return PROCESS_EXIT_EXITED; -} - -/** Helper: return the number of characters in <b>s</b> preceding the first - * occurrence of <b>ch</b>. If <b>ch</b> does not occur in <b>s</b>, return - * the length of <b>s</b>. Should be equivalent to strspn(s, "ch"). */ -static inline size_t -str_num_before(const char *s, char ch) -{ - const char *cp = strchr(s, ch); - if (cp) - return cp - s; - else - return strlen(s); -} - -/** Return non-zero iff getenv would consider <b>s1</b> and <b>s2</b> - * to have the same name as strings in a process's environment. */ -int -environment_variable_names_equal(const char *s1, const char *s2) -{ - size_t s1_name_len = str_num_before(s1, '='); - size_t s2_name_len = str_num_before(s2, '='); - - return (s1_name_len == s2_name_len && - tor_memeq(s1, s2, s1_name_len)); -} - -/** Free <b>env</b> (assuming it was produced by - * process_environment_make). */ -void -process_environment_free_(process_environment_t *env) -{ - if (env == NULL) return; - - /* As both an optimization hack to reduce consing on Unixoid systems - * and a nice way to ensure that some otherwise-Windows-specific - * code will always get tested before changes to it get merged, the - * strings which env->unixoid_environment_block points to are packed - * into env->windows_environment_block. */ - tor_free(env->unixoid_environment_block); - tor_free(env->windows_environment_block); - - tor_free(env); -} - -/** Make a process_environment_t containing the environment variables - * specified in <b>env_vars</b> (as C strings of the form - * "NAME=VALUE"). */ -process_environment_t * -process_environment_make(struct smartlist_t *env_vars) -{ - process_environment_t *env = tor_malloc_zero(sizeof(process_environment_t)); - int n_env_vars = smartlist_len(env_vars); - int i; - size_t total_env_length; - smartlist_t *env_vars_sorted; - - tor_assert(n_env_vars + 1 != 0); - env->unixoid_environment_block = tor_calloc(n_env_vars + 1, sizeof(char *)); - /* env->unixoid_environment_block is already NULL-terminated, - * because we assume that NULL == 0 (and check that during compilation). */ - - total_env_length = 1; /* terminating NUL of terminating empty string */ - for (i = 0; i < n_env_vars; ++i) { - const char *s = smartlist_get(env_vars, i); - size_t slen = strlen(s); - - tor_assert(slen + 1 != 0); - tor_assert(slen + 1 < SIZE_MAX - total_env_length); - total_env_length += slen + 1; - } - - env->windows_environment_block = tor_malloc_zero(total_env_length); - /* env->windows_environment_block is already - * (NUL-terminated-empty-string)-terminated. */ - - /* Some versions of Windows supposedly require that environment - * blocks be sorted. Or maybe some Windows programs (or their - * runtime libraries) fail to look up strings in non-sorted - * environment blocks. - * - * Also, sorting strings makes it easy to find duplicate environment - * variables and environment-variable strings without an '=' on all - * OSes, and they can cause badness. Let's complain about those. */ - env_vars_sorted = smartlist_new(); - smartlist_add_all(env_vars_sorted, env_vars); - smartlist_sort_strings(env_vars_sorted); - - /* Now copy the strings into the environment blocks. */ - { - char *cp = env->windows_environment_block; - const char *prev_env_var = NULL; - - for (i = 0; i < n_env_vars; ++i) { - const char *s = smartlist_get(env_vars_sorted, i); - size_t slen = strlen(s); - size_t s_name_len = str_num_before(s, '='); - - if (s_name_len == slen) { - log_warn(LD_GENERAL, - "Preparing an environment containing a variable " - "without a value: %s", - s); - } - if (prev_env_var != NULL && - environment_variable_names_equal(s, prev_env_var)) { - log_warn(LD_GENERAL, - "Preparing an environment containing two variables " - "with the same name: %s and %s", - prev_env_var, s); - } - - prev_env_var = s; - - /* Actually copy the string into the environment. */ - memcpy(cp, s, slen+1); - env->unixoid_environment_block[i] = cp; - cp += slen+1; - } - - tor_assert(cp == env->windows_environment_block + total_env_length - 1); - } - - smartlist_free(env_vars_sorted); - - return env; -} - -/** Return a newly allocated smartlist containing every variable in - * this process's environment, as a NUL-terminated string of the form - * "NAME=VALUE". Note that on some/many/most/all OSes, the parent - * process can put strings not of that form in our environment; - * callers should try to not get crashed by that. - * - * The returned strings are heap-allocated, and must be freed by the - * caller. */ -struct smartlist_t * -get_current_process_environment_variables(void) -{ - smartlist_t *sl = smartlist_new(); - - char **environ_tmp; /* Not const char ** ? Really? */ - for (environ_tmp = get_environment(); *environ_tmp; ++environ_tmp) { - smartlist_add_strdup(sl, *environ_tmp); - } - - return sl; -} - -/** For each string s in <b>env_vars</b> such that - * environment_variable_names_equal(s, <b>new_var</b>), remove it; if - * <b>free_p</b> is non-zero, call <b>free_old</b>(s). If - * <b>new_var</b> contains '=', insert it into <b>env_vars</b>. */ -void -set_environment_variable_in_smartlist(struct smartlist_t *env_vars, - const char *new_var, - void (*free_old)(void*), - int free_p) -{ - SMARTLIST_FOREACH_BEGIN(env_vars, const char *, s) { - if (environment_variable_names_equal(s, new_var)) { - SMARTLIST_DEL_CURRENT(env_vars, s); - if (free_p) { - free_old((void *)s); - } - } - } SMARTLIST_FOREACH_END(s); - - if (strchr(new_var, '=') != NULL) { - smartlist_add(env_vars, (void *)new_var); - } -} - -#ifdef _WIN32 -/** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes. If - * <b>hProcess</b> is NULL, the function will return immediately if there is - * nothing more to read. Otherwise <b>hProcess</b> should be set to the handle - * to the process owning the <b>h</b>. In this case, the function will exit - * only once the process has exited, or <b>count</b> bytes are read. Returns - * the number of bytes read, or -1 on error. */ -ssize_t -tor_read_all_handle(HANDLE h, char *buf, size_t count, - const process_handle_t *process) -{ - size_t numread = 0; - BOOL retval; - DWORD byte_count; - BOOL process_exited = FALSE; - - if (count > SIZE_T_CEILING || count > SSIZE_MAX) - return -1; - - while (numread < count) { - /* Check if there is anything to read */ - retval = PeekNamedPipe(h, NULL, 0, NULL, &byte_count, NULL); - if (!retval) { - log_warn(LD_GENERAL, - "Failed to peek from handle: %s", - format_win32_error(GetLastError())); - return -1; - } else if (0 == byte_count) { - /* Nothing available: process exited or it is busy */ - - /* Exit if we don't know whether the process is running */ - if (NULL == process) - break; - - /* The process exited and there's nothing left to read from it */ - if (process_exited) - break; - - /* If process is not running, check for output one more time in case - it wrote something after the peek was performed. Otherwise keep on - waiting for output */ - tor_assert(process != NULL); - byte_count = WaitForSingleObject(process->pid.hProcess, 0); - if (WAIT_TIMEOUT != byte_count) - process_exited = TRUE; - - continue; - } - - /* There is data to read; read it */ - retval = ReadFile(h, buf+numread, count-numread, &byte_count, NULL); - tor_assert(byte_count + numread <= count); - if (!retval) { - log_warn(LD_GENERAL, "Failed to read from handle: %s", - format_win32_error(GetLastError())); - return -1; - } else if (0 == byte_count) { - /* End of file */ - break; - } - numread += byte_count; - } - return (ssize_t)numread; -} -#else /* !(defined(_WIN32)) */ -/** Read from a handle <b>fd</b> into <b>buf</b>, up to <b>count</b> bytes. If - * <b>process</b> is NULL, the function will return immediately if there is - * nothing more to read. Otherwise data will be read until end of file, or - * <b>count</b> bytes are read. Returns the number of bytes read, or -1 on - * error. Sets <b>eof</b> to true if <b>eof</b> is not NULL and the end of the - * file has been reached. */ -ssize_t -tor_read_all_handle(int fd, char *buf, size_t count, - const process_handle_t *process, - int *eof) -{ - size_t numread = 0; - ssize_t result; - - if (eof) - *eof = 0; - - if (count > SIZE_T_CEILING || count > SSIZE_MAX) - return -1; - - while (numread < count) { - result = read(fd, buf+numread, count-numread); - - if (result == 0) { - log_debug(LD_GENERAL, "read() reached end of file"); - if (eof) - *eof = 1; - break; - } else if (result < 0 && errno == EAGAIN) { - if (process) - continue; - else - break; - } else if (result < 0) { - log_warn(LD_GENERAL, "read() failed: %s", strerror(errno)); - return -1; - } - - numread += result; - } - - log_debug(LD_GENERAL, "read() read %d bytes from handle", (int)numread); - return (ssize_t)numread; -} -#endif /* defined(_WIN32) */ - -/** Read from stdout of a process until the process exits. */ -ssize_t -tor_read_all_from_process_stdout(const process_handle_t *process_handle, - char *buf, size_t count) -{ -#ifdef _WIN32 - return tor_read_all_handle(process_handle->stdout_pipe, buf, count, - process_handle); -#else - return tor_read_all_handle(process_handle->stdout_pipe, buf, count, - process_handle, NULL); -#endif /* defined(_WIN32) */ -} - -/** Read from stdout of a process until the process exits. */ -ssize_t -tor_read_all_from_process_stderr(const process_handle_t *process_handle, - char *buf, size_t count) -{ -#ifdef _WIN32 - return tor_read_all_handle(process_handle->stderr_pipe, buf, count, - process_handle); -#else - return tor_read_all_handle(process_handle->stderr_pipe, buf, count, - process_handle, NULL); -#endif /* defined(_WIN32) */ -} - -/** Split buf into lines, and add to smartlist. The buffer <b>buf</b> will be - * modified. The resulting smartlist will consist of pointers to buf, so there - * is no need to free the contents of sl. <b>buf</b> must be a NUL-terminated - * string. <b>len</b> should be set to the length of the buffer excluding the - * NUL. Non-printable characters (including NUL) will be replaced with "." */ -int -tor_split_lines(smartlist_t *sl, char *buf, int len) -{ - /* Index in buf of the start of the current line */ - int start = 0; - /* Index in buf of the current character being processed */ - int cur = 0; - /* Are we currently in a line */ - char in_line = 0; - - /* Loop over string */ - while (cur < len) { - /* Loop until end of line or end of string */ - for (; cur < len; cur++) { - if (in_line) { - if ('\r' == buf[cur] || '\n' == buf[cur]) { - /* End of line */ - buf[cur] = '\0'; - /* Point cur to the next line */ - cur++; - /* Line starts at start and ends with a nul */ - break; - } else { - if (!TOR_ISPRINT(buf[cur])) - buf[cur] = '.'; - } - } else { - if ('\r' == buf[cur] || '\n' == buf[cur]) { - /* Skip leading vertical space */ - ; - } else { - in_line = 1; - start = cur; - if (!TOR_ISPRINT(buf[cur])) - buf[cur] = '.'; - } - } - } - /* We are at the end of the line or end of string. If in_line is true there - * is a line which starts at buf+start and ends at a NUL. cur points to - * the character after the NUL. */ - if (in_line) - smartlist_add(sl, (void *)(buf+start)); - in_line = 0; - } - return smartlist_len(sl); -} - -/** Return a string corresponding to <b>stream_status</b>. */ -const char * -stream_status_to_string(enum stream_status stream_status) -{ - switch (stream_status) { - case IO_STREAM_OKAY: - return "okay"; - case IO_STREAM_EAGAIN: - return "temporarily unavailable"; - case IO_STREAM_TERM: - return "terminated"; - case IO_STREAM_CLOSED: - return "closed"; - default: - tor_fragile_assert(); - return "unknown"; - } -} - -#ifdef _WIN32 - -/** Return a smartlist containing lines outputted from - * <b>handle</b>. Return NULL on error, and set - * <b>stream_status_out</b> appropriately. */ -MOCK_IMPL(smartlist_t *, -tor_get_lines_from_handle, (HANDLE *handle, - enum stream_status *stream_status_out)) -{ - int pos; - char stdout_buf[600] = {0}; - smartlist_t *lines = NULL; - - tor_assert(stream_status_out); - - *stream_status_out = IO_STREAM_TERM; - - pos = tor_read_all_handle(handle, stdout_buf, sizeof(stdout_buf) - 1, NULL); - if (pos < 0) { - *stream_status_out = IO_STREAM_TERM; - return NULL; - } - if (pos == 0) { - *stream_status_out = IO_STREAM_EAGAIN; - return NULL; - } - - /* End with a null even if there isn't a \r\n at the end */ - /* TODO: What if this is a partial line? */ - stdout_buf[pos] = '\0'; - - /* Split up the buffer */ - lines = smartlist_new(); - tor_split_lines(lines, stdout_buf, pos); - - /* Currently 'lines' is populated with strings residing on the - stack. Replace them with their exact copies on the heap: */ - SMARTLIST_FOREACH(lines, char *, line, - SMARTLIST_REPLACE_CURRENT(lines, line, tor_strdup(line))); - - *stream_status_out = IO_STREAM_OKAY; - - return lines; -} - -#else /* !(defined(_WIN32)) */ - -/** Return a smartlist containing lines outputted from - * <b>fd</b>. Return NULL on error, and set - * <b>stream_status_out</b> appropriately. */ -MOCK_IMPL(smartlist_t *, -tor_get_lines_from_handle, (int fd, enum stream_status *stream_status_out)) -{ - enum stream_status stream_status; - char stdout_buf[400]; - smartlist_t *lines = NULL; - - while (1) { - memset(stdout_buf, 0, sizeof(stdout_buf)); - - stream_status = get_string_from_pipe(fd, - stdout_buf, sizeof(stdout_buf) - 1); - if (stream_status != IO_STREAM_OKAY) - goto done; - - if (!lines) lines = smartlist_new(); - smartlist_split_string(lines, stdout_buf, "\n", 0, 0); - } - - done: - *stream_status_out = stream_status; - return lines; -} - -#endif /* defined(_WIN32) */ - -/** Reads from <b>fd</b> and stores input in <b>buf_out</b> making - * sure it's below <b>count</b> bytes. - * If the string has a trailing newline, we strip it off. - * - * This function is specifically created to handle input from managed - * proxies, according to the pluggable transports spec. Make sure it - * fits your needs before using it. - * - * Returns: - * IO_STREAM_CLOSED: If the stream is closed. - * IO_STREAM_EAGAIN: If there is nothing to read and we should check back - * later. - * IO_STREAM_TERM: If something is wrong with the stream. - * IO_STREAM_OKAY: If everything went okay and we got a string - * in <b>buf_out</b>. */ -enum stream_status -get_string_from_pipe(int fd, char *buf_out, size_t count) -{ - ssize_t ret; - - tor_assert(count <= INT_MAX); - - ret = read(fd, buf_out, count); - - if (ret == 0) - return IO_STREAM_CLOSED; - else if (ret < 0 && errno == EAGAIN) - return IO_STREAM_EAGAIN; - else if (ret < 0) - return IO_STREAM_TERM; - - if (buf_out[ret - 1] == '\n') { - /* Remove the trailing newline */ - buf_out[ret - 1] = '\0'; - } else - buf_out[ret] = '\0'; - - return IO_STREAM_OKAY; -} - -/** Initialize the insecure RNG <b>rng</b> from a seed value <b>seed</b>. */ -void -tor_init_weak_random(tor_weak_rng_t *rng, unsigned seed) -{ - rng->state = (uint32_t)(seed & 0x7fffffff); -} - -/** Return a randomly chosen value in the range 0..TOR_WEAK_RANDOM_MAX based - * on the RNG state of <b>rng</b>. This entropy will not be cryptographically - * strong; do not rely on it for anything an adversary should not be able to - * predict. */ -int32_t -tor_weak_random(tor_weak_rng_t *rng) -{ - /* Here's a linear congruential generator. OpenBSD and glibc use these - * parameters; they aren't too bad, and should have maximal period over the - * range 0..INT32_MAX. We don't want to use the platform rand() or random(), - * since some platforms have bad weak RNGs that only return values in the - * range 0..INT16_MAX, which just isn't enough. */ - rng->state = (rng->state * 1103515245 + 12345) & 0x7fffffff; - return (int32_t) rng->state; -} - -/** Return a random number in the range [0 , <b>top</b>). {That is, the range - * of integers i such that 0 <= i < top.} Chooses uniformly. Requires that - * top is greater than 0. This randomness is not cryptographically strong; do - * not rely on it for anything an adversary should not be able to predict. */ -int32_t -tor_weak_random_range(tor_weak_rng_t *rng, int32_t top) -{ - /* We don't want to just do tor_weak_random() % top, since random() is often - * implemented with an LCG whose modulus is a power of 2, and those are - * cyclic in their low-order bits. */ - int divisor, result; - tor_assert(top > 0); - divisor = TOR_WEAK_RANDOM_MAX / top; - do { - result = (int32_t)(tor_weak_random(rng) / divisor); - } while (result >= top); - return result; -} - -/** Cast a given double value to a int64_t. Return 0 if number is NaN. - * Returns either INT64_MIN or INT64_MAX if number is outside of the int64_t - * range. */ -int64_t -clamp_double_to_int64(double number) -{ - int exponent; - -#if defined(MINGW_ANY) && GCC_VERSION >= 409 -/* - Mingw's math.h uses gcc's __builtin_choose_expr() facility to declare - isnan, isfinite, and signbit. But as implemented in at least some - versions of gcc, __builtin_choose_expr() can generate type warnings - even from branches that are not taken. So, suppress those warnings. -*/ -#define PROBLEMATIC_FLOAT_CONVERSION_WARNING -DISABLE_GCC_WARNING(float-conversion) -#endif /* defined(MINGW_ANY) && GCC_VERSION >= 409 */ - -/* - With clang 4.0 we apparently run into "double promotion" warnings here, - since clang thinks we're promoting a double to a long double. - */ -#if defined(__clang__) -#if __has_warning("-Wdouble-promotion") -#define PROBLEMATIC_DOUBLE_PROMOTION_WARNING -DISABLE_GCC_WARNING(double-promotion) -#endif -#endif /* defined(__clang__) */ - - /* NaN is a special case that can't be used with the logic below. */ - if (isnan(number)) { - return 0; - } - - /* Time to validate if result can overflows a int64_t value. Fun with - * float! Find that exponent exp such that - * number == x * 2^exp - * for some x with abs(x) in [0.5, 1.0). Note that this implies that the - * magnitude of number is strictly less than 2^exp. - * - * If number is infinite, the call to frexp is legal but the contents of - * are exponent unspecified. */ - frexp(number, &exponent); - - /* If the magnitude of number is strictly less than 2^63, the truncated - * version of number is guaranteed to be representable. The only - * representable integer for which this is not the case is INT64_MIN, but - * it is covered by the logic below. */ - if (isfinite(number) && exponent <= 63) { - return (int64_t)number; - } - - /* Handle infinities and finite numbers with magnitude >= 2^63. */ - return signbit(number) ? INT64_MIN : INT64_MAX; - -#ifdef PROBLEMATIC_DOUBLE_PROMOTION_WARNING -ENABLE_GCC_WARNING(double-promotion) -#endif -#ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING -ENABLE_GCC_WARNING(float-conversion) -#endif -} - -/** Return a uint64_t value from <b>a</b> in network byte order. */ -uint64_t -tor_htonll(uint64_t a) -{ -#ifdef WORDS_BIGENDIAN - /* Big endian. */ - return a; -#else /* WORDS_BIGENDIAN */ - /* Little endian. The worst... */ - return htonl((uint32_t)(a>>32)) | - (((uint64_t)htonl((uint32_t)a))<<32); -#endif /* defined(WORDS_BIGENDIAN) */ -} - -/** Return a uint64_t value from <b>a</b> in host byte order. */ -uint64_t -tor_ntohll(uint64_t a) -{ - return tor_htonll(a); -} - diff --git a/src/common/util.h b/src/common/util.h index 7172b7da08..55eec2b8c9 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,561 +12,41 @@ #define TOR_UTIL_H #include "orconfig.h" -#include "torint.h" -#include "compat.h" -#include "di_ops.h" -#include "testsupport.h" -#include <stdio.h> -#include <stdlib.h> -#ifdef _WIN32 -/* for the correct alias to struct stat */ -#include <sys/stat.h> -#endif -#include "util_bug.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif -#ifndef O_TEXT -#define O_TEXT 0 -#endif -#ifndef O_NOFOLLOW -#define O_NOFOLLOW 0 -#endif - -/* If we're building with dmalloc, we want all of our memory allocation - * functions to take an extra file/line pair of arguments. If not, not. - * We define DMALLOC_PARAMS to the extra parameters to insert in the - * function prototypes, and DMALLOC_ARGS to the extra arguments to add - * to calls. */ -#ifdef USE_DMALLOC -#define DMALLOC_PARAMS , const char *file, const int line -#define DMALLOC_ARGS , SHORT_FILE__, __LINE__ -#else -#define DMALLOC_PARAMS -#define DMALLOC_ARGS -#endif /* defined(USE_DMALLOC) */ - -/* Memory management */ -void *tor_malloc_(size_t size DMALLOC_PARAMS) ATTR_MALLOC; -void *tor_malloc_zero_(size_t size DMALLOC_PARAMS) ATTR_MALLOC; -void *tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS) ATTR_MALLOC; -void *tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS); -void *tor_reallocarray_(void *ptr, size_t size1, size_t size2 DMALLOC_PARAMS); -char *tor_strdup_(const char *s DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1)); -char *tor_strndup_(const char *s, size_t n DMALLOC_PARAMS) - ATTR_MALLOC ATTR_NONNULL((1)); -void *tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS) - ATTR_MALLOC ATTR_NONNULL((1)); -void *tor_memdup_nulterm_(const void *mem, size_t len DMALLOC_PARAMS) - ATTR_MALLOC ATTR_NONNULL((1)); -void tor_free_(void *mem); -uint64_t tor_htonll(uint64_t a); -uint64_t tor_ntohll(uint64_t a); -#ifdef USE_DMALLOC -extern int dmalloc_free(const char *file, const int line, void *pnt, - const int func_id); -#define tor_free(p) STMT_BEGIN \ - if (PREDICT_LIKELY((p)!=NULL)) { \ - dmalloc_free(SHORT_FILE__, __LINE__, (p), 0); \ - (p)=NULL; \ - } \ - STMT_END -#else /* !(defined(USE_DMALLOC)) */ -/** Release memory allocated by tor_malloc, tor_realloc, tor_strdup, - * etc. Unlike the free() function, the tor_free() macro sets the - * pointer value to NULL after freeing it. - * - * This is a macro. If you need a function pointer to release memory from - * tor_malloc(), use tor_free_(). - * - * Note that this macro takes the address of the pointer it is going to - * free and clear. If that pointer is stored with a nonstandard - * alignment (eg because of a "packed" pragma) it is not correct to use - * tor_free(). - */ -#ifdef __GNUC__ -#define tor_free(p) STMT_BEGIN \ - typeof(&(p)) tor_free__tmpvar = &(p); \ - raw_free(*tor_free__tmpvar); \ - *tor_free__tmpvar=NULL; \ - STMT_END -#else -#define tor_free(p) STMT_BEGIN \ - raw_free(p); \ - (p)=NULL; \ - STMT_END -#endif -#endif /* defined(USE_DMALLOC) */ - -#define tor_malloc(size) tor_malloc_(size DMALLOC_ARGS) -#define tor_malloc_zero(size) tor_malloc_zero_(size DMALLOC_ARGS) -#define tor_calloc(nmemb,size) tor_calloc_(nmemb, size DMALLOC_ARGS) -#define tor_realloc(ptr, size) tor_realloc_(ptr, size DMALLOC_ARGS) -#define tor_reallocarray(ptr, sz1, sz2) \ - tor_reallocarray_((ptr), (sz1), (sz2) DMALLOC_ARGS) -#define tor_strdup(s) tor_strdup_(s DMALLOC_ARGS) -#define tor_strndup(s, n) tor_strndup_(s, n DMALLOC_ARGS) -#define tor_memdup(s, n) tor_memdup_(s, n DMALLOC_ARGS) -#define tor_memdup_nulterm(s, n) tor_memdup_nulterm_(s, n DMALLOC_ARGS) - -/* Aliases for the underlying system malloc/realloc/free. Only use - * them to indicate "I really want the underlying system function, I know - * what I'm doing." */ -#define raw_malloc malloc -#define raw_realloc realloc -#define raw_free free -#define raw_strdup strdup - -void tor_log_mallinfo(int severity); - -/* Helper macro: free a variable of type 'typename' using freefn, and - * set the variable to NULL. - */ -#define FREE_AND_NULL(typename, freefn, var) \ - do { \ - /* only evaluate (var) once. */ \ - typename **tmp__free__ptr ## freefn = &(var); \ - freefn(*tmp__free__ptr ## freefn); \ - (*tmp__free__ptr ## freefn) = NULL; \ - } while (0) - -/** Macro: yield a pointer to the field at position <b>off</b> within the - * structure <b>st</b>. Example: - * <pre> - * struct a { int foo; int bar; } x; - * off_t bar_offset = offsetof(struct a, bar); - * int *bar_p = STRUCT_VAR_P(&x, bar_offset); - * *bar_p = 3; - * </pre> - */ -#define STRUCT_VAR_P(st, off) ((void*) ( ((char*)(st)) + (off) ) ) - -/** Macro: yield a pointer to an enclosing structure given a pointer to - * a substructure at offset <b>off</b>. Example: - * <pre> - * struct base { ... }; - * struct subtype { int x; struct base b; } x; - * struct base *bp = &x.base; - * struct *sp = SUBTYPE_P(bp, struct subtype, b); - * </pre> - */ -#define SUBTYPE_P(p, subtype, basemember) \ - ((void*) ( ((char*)(p)) - offsetof(subtype, basemember) )) - -/* Logic */ -/** Macro: true if two values have the same boolean value. */ -#define bool_eq(a,b) (!(a)==!(b)) -/** Macro: true if two values have different boolean values. */ -#define bool_neq(a,b) (!(a)!=!(b)) - -/* Math functions */ -double tor_mathlog(double d) ATTR_CONST; -long tor_lround(double d) ATTR_CONST; -int64_t tor_llround(double d) ATTR_CONST; -int tor_log2(uint64_t u64) ATTR_CONST; -uint64_t round_to_power_of_2(uint64_t u64); -unsigned round_to_next_multiple_of(unsigned number, unsigned divisor); -uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor); -uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor); -int64_t sample_laplace_distribution(double mu, double b, double p); -int64_t add_laplace_noise(int64_t signal, double random, double delta_f, - double epsilon); -int n_bits_set_u8(uint8_t v); -int64_t clamp_double_to_int64(double number); -void simplify_fraction64(uint64_t *numer, uint64_t *denom); - -uint32_t tor_add_u32_nowrap(uint32_t a, uint32_t b); - -/* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b> - * and positive <b>b</b>. Works on integer types only. Not defined if a+(b-1) - * can overflow. */ -#define CEIL_DIV(a,b) (((a)+((b)-1))/(b)) - -/* Return <b>v</b> if it's between <b>min</b> and <b>max</b>. Otherwise - * return <b>min</b> if <b>v</b> is smaller than <b>min</b>, or <b>max</b> if - * <b>b</b> is larger than <b>max</b>. - * - * Requires that <b>min</b> is no more than <b>max</b>. May evaluate any of - * its arguments more than once! */ -#define CLAMP(min,v,max) \ - ( ((v) < (min)) ? (min) : \ - ((v) > (max)) ? (max) : \ - (v) ) - -/* String manipulation */ - -/** Allowable characters in a hexadecimal string. */ -#define HEX_CHARACTERS "0123456789ABCDEFabcdef" -void tor_strlower(char *s) ATTR_NONNULL((1)); -void tor_strupper(char *s) ATTR_NONNULL((1)); -int tor_strisprint(const char *s) ATTR_NONNULL((1)); -int tor_strisnonupper(const char *s) ATTR_NONNULL((1)); -int tor_strisspace(const char *s); -int strcmp_opt(const char *s1, const char *s2); -int strcmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2)); -int strcmp_len(const char *s1, const char *s2, size_t len) ATTR_NONNULL((1,2)); -int strcasecmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2)); -int strcmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2)); -int strcasecmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2)); -int fast_memcmpstart(const void *mem, size_t memlen, const char *prefix); - -void tor_strstrip(char *s, const char *strip) ATTR_NONNULL((1,2)); -long tor_parse_long(const char *s, int base, long min, - long max, int *ok, char **next); -unsigned long tor_parse_ulong(const char *s, int base, unsigned long min, - unsigned long max, int *ok, char **next); -double tor_parse_double(const char *s, double min, double max, int *ok, - char **next); -uint64_t tor_parse_uint64(const char *s, int base, uint64_t min, - uint64_t max, int *ok, char **next); -const char *hex_str(const char *from, size_t fromlen) ATTR_NONNULL((1)); -const char *eat_whitespace(const char *s); -const char *eat_whitespace_eos(const char *s, const char *eos); -const char *eat_whitespace_no_nl(const char *s); -const char *eat_whitespace_eos_no_nl(const char *s, const char *eos); -const char *find_whitespace(const char *s); -const char *find_whitespace_eos(const char *s, const char *eos); -const char *find_str_at_start_of_line(const char *haystack, - const char *needle); -int string_is_C_identifier(const char *string); -int string_is_key_value(int severity, const char *string); -int string_is_valid_dest(const char *string); -int string_is_valid_nonrfc_hostname(const char *string); -int string_is_valid_ipv4_address(const char *string); -int string_is_valid_ipv6_address(const char *string); - -int tor_mem_is_zero(const char *mem, size_t len); -int tor_digest_is_zero(const char *digest); -int tor_digest256_is_zero(const char *digest); -char *esc_for_log(const char *string) ATTR_MALLOC; -char *esc_for_log_len(const char *chars, size_t n) ATTR_MALLOC; -const char *escaped(const char *string); - -char *tor_escape_str_for_pt_args(const char *string, - const char *chars_to_escape); - -struct smartlist_t; -int tor_vsscanf(const char *buf, const char *pattern, va_list ap) \ - CHECK_SCANF(2, 0); -int tor_sscanf(const char *buf, const char *pattern, ...) - CHECK_SCANF(2, 3); - -void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...) - CHECK_PRINTF(2, 3); -void smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern, - va_list args) - CHECK_PRINTF(2, 0); -void smartlist_add_strdup(struct smartlist_t *sl, const char *string); - -/* Time helpers */ -long tv_udiff(const struct timeval *start, const struct timeval *end); -long tv_mdiff(const struct timeval *start, const struct timeval *end); -int64_t tv_to_msec(const struct timeval *tv); -int tor_timegm(const struct tm *tm, time_t *time_out); -#define RFC1123_TIME_LEN 29 -void format_rfc1123_time(char *buf, time_t t); -int parse_rfc1123_time(const char *buf, time_t *t); -#define ISO_TIME_LEN 19 -#define ISO_TIME_USEC_LEN (ISO_TIME_LEN+7) -void format_local_iso_time(char *buf, time_t t); -void format_iso_time(char *buf, time_t t); -void format_local_iso_time_nospace(char *buf, time_t t); -void format_iso_time_nospace(char *buf, time_t t); -void format_iso_time_nospace_usec(char *buf, const struct timeval *tv); -int parse_iso_time_(const char *cp, time_t *t, int strict, int nospace); -int parse_iso_time(const char *buf, time_t *t); -int parse_iso_time_nospace(const char *cp, time_t *t); -int parse_http_time(const char *buf, struct tm *tm); -int format_time_interval(char *out, size_t out_len, long interval); - -/* Cached time */ -#ifdef TIME_IS_FAST -#define approx_time() time(NULL) -#define update_approx_time(t) STMT_NIL -#else -time_t approx_time(void); -void update_approx_time(time_t now); -#endif /* defined(TIME_IS_FAST) */ - -/* Rate-limiter */ - -/** A ratelim_t remembers how often an event is occurring, and how often - * it's allowed to occur. Typical usage is something like: - * - <pre> - if (possibly_very_frequent_event()) { - const int INTERVAL = 300; - static ratelim_t warning_limit = RATELIM_INIT(INTERVAL); - char *m; - if ((m = rate_limit_log(&warning_limit, approx_time()))) { - log_warn(LD_GENERAL, "The event occurred!%s", m); - tor_free(m); - } - } - </pre> - - As a convenience wrapper for logging, you can replace the above with: - <pre> - if (possibly_very_frequent_event()) { - static ratelim_t warning_limit = RATELIM_INIT(300); - log_fn_ratelim(&warning_limit, LOG_WARN, LD_GENERAL, - "The event occurred!"); - } - </pre> - */ -typedef struct ratelim_t { - int rate; - time_t last_allowed; - int n_calls_since_last_time; -} ratelim_t; - -#define RATELIM_INIT(r) { (r), 0, 0 } -#define RATELIM_TOOMANY (16*1000*1000) - -char *rate_limit_log(ratelim_t *lim, time_t now); - -/* File helpers */ -ssize_t write_all(tor_socket_t fd, const char *buf, size_t count,int isSocket); -ssize_t read_all(tor_socket_t fd, char *buf, size_t count, int isSocket); - -/** Status of an I/O stream. */ -enum stream_status { - IO_STREAM_OKAY, - IO_STREAM_EAGAIN, - IO_STREAM_TERM, - IO_STREAM_CLOSED -}; - -const char *stream_status_to_string(enum stream_status stream_status); - -enum stream_status get_string_from_pipe(int fd, char *buf, size_t count); - -MOCK_DECL(int,tor_unlink,(const char *pathname)); - -/** Return values from file_status(); see that function's documentation - * for details. */ -typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR, FN_EMPTY } file_status_t; -file_status_t file_status(const char *filename); - -/** Possible behaviors for check_private_dir() on encountering a nonexistent - * directory; see that function's documentation for details. */ -typedef unsigned int cpd_check_t; -#define CPD_NONE 0 -#define CPD_CREATE (1u << 0) -#define CPD_CHECK (1u << 1) -#define CPD_GROUP_OK (1u << 2) -#define CPD_GROUP_READ (1u << 3) -#define CPD_CHECK_MODE_ONLY (1u << 4) -#define CPD_RELAX_DIRMODE_CHECK (1u << 5) -MOCK_DECL(int, check_private_dir, - (const char *dirname, cpd_check_t check, - const char *effective_user)); - -#define OPEN_FLAGS_REPLACE (O_WRONLY|O_CREAT|O_TRUNC) -#define OPEN_FLAGS_APPEND (O_WRONLY|O_CREAT|O_APPEND) -#define OPEN_FLAGS_DONT_REPLACE (O_CREAT|O_EXCL|O_APPEND|O_WRONLY) -typedef struct open_file_t open_file_t; -int start_writing_to_file(const char *fname, int open_flags, int mode, - open_file_t **data_out); -FILE *start_writing_to_stdio_file(const char *fname, int open_flags, int mode, - open_file_t **data_out); -FILE *fdopen_file(open_file_t *file_data); -int finish_writing_to_file(open_file_t *file_data); -int abort_writing_to_file(open_file_t *file_data); -MOCK_DECL(int, -write_str_to_file,(const char *fname, const char *str, int bin)); -MOCK_DECL(int, -write_bytes_to_file,(const char *fname, const char *str, size_t len, - int bin)); -/** An ad-hoc type to hold a string of characters and a count; used by - * write_chunks_to_file. */ -typedef struct sized_chunk_t { - const char *bytes; - size_t len; -} sized_chunk_t; -int write_chunks_to_file(const char *fname, const struct smartlist_t *chunks, - int bin, int no_tempfile); -int append_bytes_to_file(const char *fname, const char *str, size_t len, - int bin); -int write_bytes_to_new_file(const char *fname, const char *str, size_t len, - int bin); - -/** Flag for read_file_to_str: open the file in binary mode. */ -#define RFTS_BIN 1 -/** Flag for read_file_to_str: it's okay if the file doesn't exist. */ -#define RFTS_IGNORE_MISSING 2 - -#ifndef _WIN32 -struct stat; -#endif -MOCK_DECL_ATTR(char *, read_file_to_str, - (const char *filename, int flags, struct stat *stat_out), - ATTR_MALLOC); -char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, - size_t *sz_out) - ATTR_MALLOC; -const char *unescape_string(const char *s, char **result, size_t *size_out); -char *get_unquoted_path(const char *path); -char *expand_filename(const char *filename); -MOCK_DECL(struct smartlist_t *, tor_listdir, (const char *dirname)); -int path_is_relative(const char *filename); - -/* Process helpers */ -void start_daemon(void); -void finish_daemon(const char *desired_cwd); -int write_pidfile(const char *filename); - -void tor_disable_spawning_background_processes(void); - -typedef struct process_handle_t process_handle_t; -typedef struct process_environment_t process_environment_t; -int tor_spawn_background(const char *const filename, const char **argv, - process_environment_t *env, - process_handle_t **process_handle_out); - -#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code " - -#ifdef _WIN32 -HANDLE load_windows_system_library(const TCHAR *library_name); -#endif - -int environment_variable_names_equal(const char *s1, const char *s2); - -/* DOCDOC process_environment_t */ -struct process_environment_t { - /** A pointer to a sorted empty-string-terminated sequence of - * NUL-terminated strings of the form "NAME=VALUE". */ - char *windows_environment_block; - /** A pointer to a NULL-terminated array of pointers to - * NUL-terminated strings of the form "NAME=VALUE". */ - char **unixoid_environment_block; -}; - -process_environment_t *process_environment_make(struct smartlist_t *env_vars); -void process_environment_free_(process_environment_t *env); -#define process_environment_free(env) \ - FREE_AND_NULL(process_environment_t, process_environment_free_, (env)) - -struct smartlist_t *get_current_process_environment_variables(void); - -void set_environment_variable_in_smartlist(struct smartlist_t *env_vars, - const char *new_var, - void (*free_old)(void*), - int free_p); - -/* Values of process_handle_t.status. */ -#define PROCESS_STATUS_NOTRUNNING 0 -#define PROCESS_STATUS_RUNNING 1 -#define PROCESS_STATUS_ERROR -1 - -#ifdef UTIL_PRIVATE -struct waitpid_callback_t; -/** Structure to represent the state of a process with which Tor is - * communicating. The contents of this structure are private to util.c */ -struct process_handle_t { - /** One of the PROCESS_STATUS_* values */ - int status; -#ifdef _WIN32 - HANDLE stdin_pipe; - HANDLE stdout_pipe; - HANDLE stderr_pipe; - PROCESS_INFORMATION pid; -#else /* !(defined(_WIN32)) */ - int stdin_pipe; - int stdout_pipe; - int stderr_pipe; - pid_t pid; - /** If the process has not given us a SIGCHLD yet, this has the - * waitpid_callback_t that gets invoked once it has. Otherwise this - * contains NULL. */ - struct waitpid_callback_t *waitpid_cb; - /** The exit status reported by waitpid. */ - int waitpid_exit_status; -#endif /* defined(_WIN32) */ -}; -#endif /* defined(UTIL_PRIVATE) */ - -/* Return values of tor_get_exit_code() */ -#define PROCESS_EXIT_RUNNING 1 -#define PROCESS_EXIT_EXITED 0 -#define PROCESS_EXIT_ERROR -1 -int tor_get_exit_code(process_handle_t *process_handle, - int block, int *exit_code); -int tor_split_lines(struct smartlist_t *sl, char *buf, int len); -#ifdef _WIN32 -ssize_t tor_read_all_handle(HANDLE h, char *buf, size_t count, - const process_handle_t *process); -#else -ssize_t tor_read_all_handle(int fd, char *buf, size_t count, - const process_handle_t *process, - int *eof); -#endif /* defined(_WIN32) */ -ssize_t tor_read_all_from_process_stdout( - const process_handle_t *process_handle, char *buf, size_t count); -ssize_t tor_read_all_from_process_stderr( - const process_handle_t *process_handle, char *buf, size_t count); -char *tor_join_win_cmdline(const char *argv[]); - -int tor_process_get_pid(process_handle_t *process_handle); -#ifdef _WIN32 -HANDLE tor_process_get_stdout_pipe(process_handle_t *process_handle); -#else -int tor_process_get_stdout_pipe(process_handle_t *process_handle); -#endif - -#ifdef _WIN32 -MOCK_DECL(struct smartlist_t *, -tor_get_lines_from_handle,(HANDLE *handle, - enum stream_status *stream_status)); -#else -MOCK_DECL(struct smartlist_t *, -tor_get_lines_from_handle,(int fd, - enum stream_status *stream_status)); -#endif /* defined(_WIN32) */ - -int -tor_terminate_process(process_handle_t *process_handle); - -MOCK_DECL(void, -tor_process_handle_destroy,(process_handle_t *process_handle, - int also_terminate_process)); - -/* ===== Insecure rng */ -typedef struct tor_weak_rng_t { - uint32_t state; -} tor_weak_rng_t; - -#define TOR_WEAK_RNG_INIT {383745623} -#define TOR_WEAK_RANDOM_MAX (INT_MAX) -void tor_init_weak_random(tor_weak_rng_t *weak_rng, unsigned seed); -int32_t tor_weak_random(tor_weak_rng_t *weak_rng); -int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top); -/** Randomly return true according to <b>rng</b> with probability 1 in - * <b>n</b> */ -#define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n))) - -int format_hex_number_sigsafe(unsigned long x, char *buf, int max_len); -int format_dec_number_sigsafe(unsigned long x, char *buf, int max_len); - -#ifdef UTIL_PRIVATE -/* Prototypes for private functions only used by util.c (and unit tests) */ - -#ifndef _WIN32 -STATIC int format_helper_exit_status(unsigned char child_state, - int saved_errno, char *hex_errno); - -/* Space for hex values of child state, a slash, saved_errno (with - leading minus) and newline (no null) */ -#define HEX_ERRNO_SIZE (sizeof(char) * 2 + 1 + \ - 1 + sizeof(int) * 2 + 1) -#endif /* !defined(_WIN32) */ - -#endif /* defined(UTIL_PRIVATE) */ - -int size_mul_check(const size_t x, const size_t y); - -#define ARRAY_LENGTH(x) ((sizeof(x)) / sizeof(x[0])) +#include "lib/arch/bytes.h" +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" +#include "lib/ctime/di_ops.h" +#include "lib/encoding/cstring.h" +#include "lib/encoding/time_fmt.h" +#include "lib/err/torerr.h" +#include "lib/fs/dir.h" +#include "lib/fs/files.h" +#include "lib/fs/mmap.h" +#include "lib/fs/path.h" +#include "lib/fs/userdb.h" +#include "lib/intmath/addsub.h" +#include "lib/intmath/bits.h" +#include "lib/intmath/cmp.h" +#include "lib/intmath/logic.h" +#include "lib/intmath/muldiv.h" +#include "lib/log/escape.h" +#include "lib/log/ratelim.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/net/ipv4.h" +#include "lib/net/ipv6.h" +#include "lib/net/resolve.h" +#include "lib/net/socket.h" +#include "lib/string/compat_ctype.h" +#include "lib/string/compat_string.h" +#include "lib/string/parse_int.h" +#include "lib/string/printf.h" +#include "lib/string/scanf.h" +#include "lib/string/util_string.h" +#include "lib/testsupport/testsupport.h" +#include "lib/thread/threads.h" +#include "lib/time/compat_time.h" +#include "lib/wallclock/approx_time.h" +#include "lib/wallclock/timeval.h" #endif /* !defined(TOR_UTIL_H) */ - diff --git a/src/common/workqueue.c b/src/common/workqueue.c index 563a98af96..e5254396f9 100644 --- a/src/common/workqueue.c +++ b/src/common/workqueue.c @@ -24,16 +24,21 @@ */ #include "orconfig.h" -#include "compat.h" -#include "compat_libevent.h" -#include "compat_threads.h" -#include "crypto_rand.h" -#include "util.h" -#include "workqueue.h" -#include "tor_queue.h" -#include "torlog.h" +#include "common/compat_libevent.h" +#include "common/workqueue.h" + +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/intmath/weakrng.h" +#include "lib/log/ratelim.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/net/alertsock.h" +#include "lib/net/socket.h" +#include "lib/thread/threads.h" +#include "tor_queue.h" #include <event2/event.h> +#include <string.h> #define WORKQUEUE_PRIORITY_FIRST WQ_PRI_HIGH #define WORKQUEUE_PRIORITY_LAST WQ_PRI_LOW @@ -675,4 +680,3 @@ replyqueue_process(replyqueue_t *queue) tor_mutex_release(&queue->lock); } - diff --git a/src/common/workqueue.h b/src/common/workqueue.h index e1fe612e2b..4e5c424be6 100644 --- a/src/common/workqueue.h +++ b/src/common/workqueue.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_WORKQUEUE_H #define TOR_WORKQUEUE_H -#include "compat.h" +#include "lib/cc/torint.h" /** A replyqueue is used to tell the main thread about the outcome of * work that we queued for the workers. */ @@ -63,4 +63,3 @@ int threadpool_register_reply_event(threadpool_t *tp, void (*cb)(threadpool_t *tp)); #endif /* !defined(TOR_WORKQUEUE_H) */ - diff --git a/src/ext/OpenBSD_malloc_Linux.c b/src/ext/OpenBSD_malloc_Linux.c index 855c912310..9c30570c41 100644 --- a/src/ext/OpenBSD_malloc_Linux.c +++ b/src/ext/OpenBSD_malloc_Linux.c @@ -59,7 +59,7 @@ #include <errno.h> #include <err.h> /* For SIZE_MAX */ -#include "torint.h" +#include "lib/cc/torint.h" //#include "thread_private.h" diff --git a/src/ext/csiphash.c b/src/ext/csiphash.c index 0427c87950..a6a9846db4 100644 --- a/src/ext/csiphash.c +++ b/src/ext/csiphash.c @@ -29,12 +29,12 @@ Jean-Philippe Aumasson (https://131002.net/siphash/siphash24.c) */ -#include "torint.h" +#include "lib/cc/torint.h" +#include "lib/log/util_bug.h" + #include "siphash.h" -/* for tor_assert */ -#include "util.h" -/* for memcpy */ #include <string.h> +#include <stdlib.h> #include "byteorder.h" #define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) ) diff --git a/src/ext/curve25519_donna/curve25519-donna-c64.c b/src/ext/curve25519_donna/curve25519-donna-c64.c index b68ff3695a..45da7bf1e6 100644 --- a/src/ext/curve25519_donna/curve25519-donna-c64.c +++ b/src/ext/curve25519_donna/curve25519-donna-c64.c @@ -25,7 +25,7 @@ #include "orconfig.h" #include <string.h> -#include "torint.h" +#include "lib/cc/torint.h" typedef uint8_t u8; typedef uint64_t limb; diff --git a/src/ext/curve25519_donna/curve25519-donna.c b/src/ext/curve25519_donna/curve25519-donna.c index 1c5a27ab8a..d64b95c113 100644 --- a/src/ext/curve25519_donna/curve25519-donna.c +++ b/src/ext/curve25519_donna/curve25519-donna.c @@ -48,7 +48,7 @@ #include "orconfig.h" #include <string.h> -#include "torint.h" +#include "lib/cc/torint.h" typedef uint8_t u8; typedef int32_t s32; diff --git a/src/ext/ed25519/donna/ed25519-hash-custom.h b/src/ext/ed25519/donna/ed25519-hash-custom.h index cdeab3e45b..ff8bbde3da 100644 --- a/src/ext/ed25519/donna/ed25519-hash-custom.h +++ b/src/ext/ed25519/donna/ed25519-hash-custom.h @@ -9,7 +9,7 @@ void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); */ -#include "crypto_digest.h" +#include "lib/crypt_ops/crypto_digest.h" typedef struct ed25519_hash_context { crypto_digest_t *ctx; diff --git a/src/ext/ed25519/donna/ed25519-randombytes-custom.h b/src/ext/ed25519/donna/ed25519-randombytes-custom.h index 27eade4f95..d92a51d1d3 100644 --- a/src/ext/ed25519/donna/ed25519-randombytes-custom.h +++ b/src/ext/ed25519/donna/ed25519-randombytes-custom.h @@ -8,7 +8,7 @@ */ /* Tor: Instead of calling OpenSSL's CSPRNG directly, call the wrapper. */ -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_rand.h" static void ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len) diff --git a/src/ext/ed25519/donna/ed25519_donna_tor.h b/src/ext/ed25519/donna/ed25519_donna_tor.h index 7d7b8c0625..20e9b5e99c 100644 --- a/src/ext/ed25519/donna/ed25519_donna_tor.h +++ b/src/ext/ed25519/donna/ed25519_donna_tor.h @@ -1,7 +1,7 @@ /* Added for Tor. */ #ifndef SRC_EXT_ED25519_DONNA_H_INCLUDED_ #define SRC_EXT_ED25519_DONNA_H_INCLUDED_ -#include <torint.h> +#include "lib/cc/torint.h" typedef unsigned char curved25519_key[32]; diff --git a/src/ext/ed25519/donna/ed25519_tor.c b/src/ext/ed25519/donna/ed25519_tor.c index 43de9faaea..7f5ab398d8 100644 --- a/src/ext/ed25519/donna/ed25519_tor.c +++ b/src/ext/ed25519/donna/ed25519_tor.c @@ -40,7 +40,7 @@ #include "ed25519-randombytes.h" #include "ed25519-hash.h" -#include "crypto_util.h" +#include "lib/crypt_ops/crypto_util.h" typedef unsigned char ed25519_signature[64]; typedef unsigned char ed25519_public_key[32]; diff --git a/src/ext/ed25519/ref10/blinding.c b/src/ext/ed25519/ref10/blinding.c index 88e84cac20..8485524e5d 100644 --- a/src/ext/ed25519/ref10/blinding.c +++ b/src/ext/ed25519/ref10/blinding.c @@ -7,7 +7,7 @@ #include "ed25519_ref10.h" #include <string.h> -#include "crypto_util.h" +#include "lib/crypt_ops/crypto_util.h" static void ed25519_ref10_gettweak(unsigned char *out, const unsigned char *param) diff --git a/src/ext/ed25519/ref10/crypto_hash_sha512.h b/src/ext/ed25519/ref10/crypto_hash_sha512.h index 7faddb1597..25e6a90cec 100644 --- a/src/ext/ed25519/ref10/crypto_hash_sha512.h +++ b/src/ext/ed25519/ref10/crypto_hash_sha512.h @@ -1,5 +1,5 @@ /* Added for Tor. */ -#include "crypto_digest.h" +#include "lib/crypt_ops/crypto_digest.h" /* Set 'out' to the 512-bit SHA512 hash of the 'len'-byte string in 'inp' */ #define crypto_hash_sha512(out, inp, len) \ diff --git a/src/ext/ed25519/ref10/crypto_int32.h b/src/ext/ed25519/ref10/crypto_int32.h index dd13c91bd0..26271e917b 100644 --- a/src/ext/ed25519/ref10/crypto_int32.h +++ b/src/ext/ed25519/ref10/crypto_int32.h @@ -3,7 +3,7 @@ #ifndef CRYPTO_INT32_H #define CRYPTO_INT32_H -#include "torint.h" +#include "lib/cc/torint.h" #define crypto_int32 int32_t #define crypto_uint32 uint32_t diff --git a/src/ext/ed25519/ref10/crypto_int64.h b/src/ext/ed25519/ref10/crypto_int64.h index 46e8852ed0..3b066a9c0c 100644 --- a/src/ext/ed25519/ref10/crypto_int64.h +++ b/src/ext/ed25519/ref10/crypto_int64.h @@ -3,7 +3,7 @@ #ifndef CRYPTO_INT64_H #define CRYPTO_INT64_H -#include "torint.h" +#include "lib/cc/torint.h" #define crypto_int64 int64_t #define crypto_uint64 uint64_t diff --git a/src/ext/ed25519/ref10/crypto_uint32.h b/src/ext/ed25519/ref10/crypto_uint32.h index 62655a5b66..a7a77723bd 100644 --- a/src/ext/ed25519/ref10/crypto_uint32.h +++ b/src/ext/ed25519/ref10/crypto_uint32.h @@ -1,3 +1,3 @@ /* Added for Tor. */ -#include "torint.h" +#include "lib/cc/torint.h" #define crypto_uint32 uint32_t diff --git a/src/ext/ed25519/ref10/crypto_uint64.h b/src/ext/ed25519/ref10/crypto_uint64.h index cbda882a6a..adaaa08042 100644 --- a/src/ext/ed25519/ref10/crypto_uint64.h +++ b/src/ext/ed25519/ref10/crypto_uint64.h @@ -1,3 +1,3 @@ /* Added for Tor. */ -#include "torint.h" +#include "lib/cc/torint.h" #define crypto_uint64 uint64_t diff --git a/src/ext/ed25519/ref10/crypto_verify_32.h b/src/ext/ed25519/ref10/crypto_verify_32.h index 0f63efc7a3..5299928754 100644 --- a/src/ext/ed25519/ref10/crypto_verify_32.h +++ b/src/ext/ed25519/ref10/crypto_verify_32.h @@ -1,5 +1,4 @@ /* Added for Tor. */ -#include "di_ops.h" +#include "lib/ctime/di_ops.h" #define crypto_verify_32(a,b) \ (! tor_memeq((a), (b), 32)) - diff --git a/src/ext/ed25519/ref10/ed25519_ref10.h b/src/ext/ed25519/ref10/ed25519_ref10.h index 5965694977..bb72af6c0b 100644 --- a/src/ext/ed25519/ref10/ed25519_ref10.h +++ b/src/ext/ed25519/ref10/ed25519_ref10.h @@ -1,7 +1,7 @@ /* Added for Tor */ #ifndef SRC_EXT_ED25519_REF10_H_INCLUDED_ #define SRC_EXT_ED25519_REF10_H_INCLUDED_ -#include <torint.h> +#include "lib/cc/torint.h" int ed25519_ref10_seckey(unsigned char *sk); int ed25519_ref10_seckey_expand(unsigned char *sk, const unsigned char *sk_seed); diff --git a/src/ext/ed25519/ref10/keypair.c b/src/ext/ed25519/ref10/keypair.c index c437f0a4f2..a6e2d4c781 100644 --- a/src/ext/ed25519/ref10/keypair.c +++ b/src/ext/ed25519/ref10/keypair.c @@ -6,8 +6,8 @@ #include "crypto_hash_sha512.h" #include "ge.h" -#include "crypto_rand.h" -#include "crypto_util.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" int crypto_sign_seckey(unsigned char *sk) @@ -52,4 +52,3 @@ int crypto_sign_keypair(unsigned char *pk,unsigned char *sk) return 0; } - diff --git a/src/ext/ed25519/ref10/randombytes.h b/src/ext/ed25519/ref10/randombytes.h index a21dde8540..c2cef10ceb 100644 --- a/src/ext/ed25519/ref10/randombytes.h +++ b/src/ext/ed25519/ref10/randombytes.h @@ -1,4 +1,4 @@ /* Added for Tor. */ -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_rand.h" #define randombytes(b, n) \ (crypto_strongest_rand((b), (n)), 0) diff --git a/src/ext/ht.h b/src/ext/ht.h index 99da773faf..df9f60ba1d 100644 --- a/src/ext/ht.h +++ b/src/ext/ht.h @@ -1,6 +1,6 @@ /* Copyright (c) 2002, Christopher Clark. * Copyright (c) 2005-2006, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See license at end. */ /* Based on ideas by Christopher Clark and interfaces from Niels Provos. */ diff --git a/src/ext/keccak-tiny/keccak-tiny-unrolled.c b/src/ext/keccak-tiny/keccak-tiny-unrolled.c index 07e8c95bcf..05cf0ec3f0 100644 --- a/src/ext/keccak-tiny/keccak-tiny-unrolled.c +++ b/src/ext/keccak-tiny/keccak-tiny-unrolled.c @@ -9,7 +9,7 @@ #include "keccak-tiny.h" #include <string.h> -#include "crypto_util.h" +#include "lib/crypt_ops/crypto_util.h" #include "byteorder.h" /******** Endianness conversion helpers ********/ diff --git a/src/ext/keccak-tiny/keccak-tiny.h b/src/ext/keccak-tiny/keccak-tiny.h index 7efea2319e..a9c8ed6420 100644 --- a/src/ext/keccak-tiny/keccak-tiny.h +++ b/src/ext/keccak-tiny/keccak-tiny.h @@ -2,7 +2,7 @@ #define KECCAK_FIPS202_H #include <stddef.h> -#include "torint.h" +#include "lib/cc/torint.h" #define KECCAK_MAX_RATE 200 diff --git a/src/ext/mulodi/mulodi4.c b/src/ext/mulodi/mulodi4.c index 9891bbf1af..accce1ce01 100644 --- a/src/ext/mulodi/mulodi4.c +++ b/src/ext/mulodi/mulodi4.c @@ -18,7 +18,7 @@ #define COMPILER_RT_ABI #define di_int int64_t #define di_uint uint64_t -#include "torint.h" +#include "lib/cc/torint.h" di_int __mulodi4(di_int a, di_int b, int* overflow); #endif diff --git a/src/include.am b/src/include.am index 90ecf90d45..1ed07425a6 100644 --- a/src/include.am +++ b/src/include.am @@ -1,6 +1,38 @@ include src/ext/include.am -include src/trunnel/include.am +include src/lib/arch/include.am +include src/lib/err/include.am +include src/lib/cc/include.am +include src/lib/ctime/include.am +include src/lib/compress/include.am +include src/lib/container/include.am +include src/lib/crypt_ops/include.am +include src/lib/defs/include.am +include src/lib/encoding/include.am +include src/lib/fdio/include.am +include src/lib/fs/include.am +include src/lib/include.libdonna.am +include src/lib/intmath/include.am +include src/lib/lock/include.am +include src/lib/log/include.am +include src/lib/math/include.am +include src/lib/memarea/include.am +include src/lib/meminfo/include.am +include src/lib/malloc/include.am +include src/lib/net/include.am +include src/lib/osinfo/include.am +include src/lib/process/include.am +include src/lib/sandbox/include.am +include src/lib/string/include.am +include src/lib/smartlist_core/include.am +include src/lib/term/include.am +include src/lib/testsupport/include.am +include src/lib/thread/include.am +include src/lib/time/include.am +include src/lib/tls/include.am +include src/lib/trace/include.am +include src/lib/wallclock/include.am include src/common/include.am +include src/trunnel/include.am include src/or/include.am include src/rust/include.am include src/test/include.am @@ -8,4 +40,3 @@ include src/tools/include.am include src/win32/include.am include src/config/include.am include src/test/fuzz/include.am -include src/trace/include.am diff --git a/src/lib/arch/.may_include b/src/lib/arch/.may_include new file mode 100644 index 0000000000..4285c3dcb8 --- /dev/null +++ b/src/lib/arch/.may_include @@ -0,0 +1,2 @@ +orconfig.h +lib/cc/*.h diff --git a/src/lib/arch/bytes.h b/src/lib/arch/bytes.h new file mode 100644 index 0000000000..4359b0f723 --- /dev/null +++ b/src/lib/arch/bytes.h @@ -0,0 +1,175 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_BYTES_H +#define TOR_BYTES_H + +#include <string.h> +#include "lib/cc/torint.h" + +/* The uint8 variants are defined to make the code more uniform. */ +static inline uint8_t +get_uint8(const void *cp) +{ + return *(const uint8_t*)(cp); +} +static inline void +set_uint8(void *cp, uint8_t v) +{ + *(uint8_t*)cp = v; +} + +/** + * Read a 16-bit value beginning at <b>cp</b>. Equivalent to + * *(uint16_t*)(cp), but will not cause segfaults on platforms that forbid + * unaligned memory access. + */ +static inline uint16_t +get_uint16(const void *cp) +{ + uint16_t v; + memcpy(&v,cp,2); + return v; +} +/** + * Read a 32-bit value beginning at <b>cp</b>. Equivalent to + * *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid + * unaligned memory access. + */ +static inline uint32_t +get_uint32(const void *cp) +{ + uint32_t v; + memcpy(&v,cp,4); + return v; +} +/** + * Read a 64-bit value beginning at <b>cp</b>. Equivalent to + * *(uint64_t*)(cp), but will not cause segfaults on platforms that forbid + * unaligned memory access. + */ +static inline uint64_t +get_uint64(const void *cp) +{ + uint64_t v; + memcpy(&v,cp,8); + return v; +} + +/** + * Set a 16-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to + * *(uint16_t*)(cp) = v, but will not cause segfaults on platforms that forbid + * unaligned memory access. */ +static inline void +set_uint16(void *cp, uint16_t v) +{ + memcpy(cp,&v,2); +} +/** + * Set a 32-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to + * *(uint32_t*)(cp) = v, but will not cause segfaults on platforms that forbid + * unaligned memory access. */ +static inline void +set_uint32(void *cp, uint32_t v) +{ + memcpy(cp,&v,4); +} +/** + * Set a 64-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to + * *(uint64_t*)(cp) = v, but will not cause segfaults on platforms that forbid + * unaligned memory access. */ +static inline void +set_uint64(void *cp, uint64_t v) +{ + memcpy(cp,&v,8); +} + +#ifdef WORDS_BIGENDIAN +static inline uint16_t +tor_htons(uint32_t a) +{ + return a; +} + +static inline uint16_t +tor_ntohs(uint64_t a) +{ + return a; +} + +static inline uint32_t +tor_htonl(uint32_t a) +{ + return a; +} + +static inline uint32_t +tor_ntohl(uint64_t a) +{ + return a; +} + +static inline uint64_t +tor_htonll(uint64_t a) +{ + return a; +} + +static inline uint64_t +tor_ntohll(uint64_t a) +{ + return a; +} +#else +static inline uint16_t +tor_htons(uint16_t a) +{ + /* Our compilers will indeed recognize this as bswap. */ + return + ((a & 0x00ff) << 8) | + ((a & 0xff00) >> 8); +} + +static inline uint16_t +tor_ntohs(uint16_t a) +{ + return tor_htons(a); +} + +static inline uint32_t +tor_htonl(uint32_t a) +{ + /* Our compilers will indeed recognize this as bswap. */ + return + ((a & 0x000000ff) <<24) | + ((a & 0x0000ff00) << 8) | + ((a & 0x00ff0000) >> 8) | + ((a & 0xff000000) >>24); +} + +static inline uint32_t +tor_ntohl(uint32_t a) +{ + return tor_htonl(a); +} + +/** Return a uint64_t value from <b>a</b> in network byte order. */ +static inline uint64_t +tor_htonll(uint64_t a) +{ + /* Little endian. The worst... */ + return tor_htonl((uint32_t)(a>>32)) | + (((uint64_t)tor_htonl((uint32_t)a))<<32); +} + +/** Return a uint64_t value from <b>a</b> in host byte order. */ +static inline uint64_t +tor_ntohll(uint64_t a) +{ + return tor_htonll(a); +} +#endif + +#endif diff --git a/src/lib/arch/include.am b/src/lib/arch/include.am new file mode 100644 index 0000000000..f92ee9222f --- /dev/null +++ b/src/lib/arch/include.am @@ -0,0 +1,3 @@ + +noinst_HEADERS += \ + src/lib/arch/bytes.h diff --git a/src/lib/cc/.may_include b/src/lib/cc/.may_include new file mode 100644 index 0000000000..2b06e8519c --- /dev/null +++ b/src/lib/cc/.may_include @@ -0,0 +1 @@ +orconfig.h diff --git a/src/lib/cc/compat_compiler.h b/src/lib/cc/compat_compiler.h new file mode 100644 index 0000000000..c631a7e821 --- /dev/null +++ b/src/lib/cc/compat_compiler.h @@ -0,0 +1,271 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_COMPAT_COMPILER_H +#define TOR_COMPAT_COMPILER_H + +#include "orconfig.h" + +#if defined(__has_feature) +# if __has_feature(address_sanitizer) +/* Some of the fancy glibc strcmp() macros include references to memory that + * clang rejects because it is off the end of a less-than-3. Clang hates this, + * even though those references never actually happen. */ +# undef strcmp +#endif /* __has_feature(address_sanitizer) */ +#endif /* defined(__has_feature) */ + +#ifndef NULL_REP_IS_ZERO_BYTES +#error "It seems your platform does not represent NULL as zero. We can't cope." +#endif + +#ifndef DOUBLE_0_REP_IS_ZERO_BYTES +#error "It seems your platform does not represent 0.0 as zeros. We can't cope." +#endif + +#if 'a'!=97 || 'z'!=122 || 'A'!=65 || ' '!=32 +#error "It seems that you encode characters in something other than ASCII." +#endif + +/* GCC can check printf and scanf types on arbitrary functions. */ +#ifdef __GNUC__ +#define CHECK_PRINTF(formatIdx, firstArg) \ + __attribute__ ((format(printf, formatIdx, firstArg))) +#else +#define CHECK_PRINTF(formatIdx, firstArg) +#endif /* defined(__GNUC__) */ +#ifdef __GNUC__ +#define CHECK_SCANF(formatIdx, firstArg) \ + __attribute__ ((format(scanf, formatIdx, firstArg))) +#else +#define CHECK_SCANF(formatIdx, firstArg) +#endif /* defined(__GNUC__) */ + +/* What GCC do we have? */ +#ifdef __GNUC__ +#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#else +#define GCC_VERSION 0 +#endif + +/* Temporarily enable and disable warnings. */ +#ifdef __GNUC__ +# define PRAGMA_STRINGIFY_(s) #s +# define PRAGMA_JOIN_STRINGIFY_(a,b) PRAGMA_STRINGIFY_(a ## b) +/* Support for macro-generated pragmas (c99) */ +# define PRAGMA_(x) _Pragma (#x) +# ifdef __clang__ +# define PRAGMA_DIAGNOSTIC_(x) PRAGMA_(clang diagnostic x) +# else +# define PRAGMA_DIAGNOSTIC_(x) PRAGMA_(GCC diagnostic x) +# endif +# if defined(__clang__) || GCC_VERSION >= 406 +/* we have push/pop support */ +# define DISABLE_GCC_WARNING(warningopt) \ + PRAGMA_DIAGNOSTIC_(push) \ + PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) +# define ENABLE_GCC_WARNING(warningopt) \ + PRAGMA_DIAGNOSTIC_(pop) +#else /* !(defined(__clang__) || GCC_VERSION >= 406) */ +/* older version of gcc: no push/pop support. */ +# define DISABLE_GCC_WARNING(warningopt) \ + PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) +# define ENABLE_GCC_WARNING(warningopt) \ + PRAGMA_DIAGNOSTIC_(warning PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) +#endif /* defined(__clang__) || GCC_VERSION >= 406 */ +#else /* !(defined(__GNUC__)) */ +/* not gcc at all */ +# define DISABLE_GCC_WARNING(warning) +# define ENABLE_GCC_WARNING(warning) +#endif /* defined(__GNUC__) */ + +/* inline is __inline on windows. */ +#ifdef _WIN32 +#define inline __inline +#endif + +/* Try to get a reasonable __func__ substitute in place. */ +#if defined(_MSC_VER) + +#define __func__ __FUNCTION__ + +#else +/* For platforms where autoconf works, make sure __func__ is defined + * sanely. */ +#ifndef HAVE_MACRO__func__ +#ifdef HAVE_MACRO__FUNCTION__ +#define __func__ __FUNCTION__ +#elif HAVE_MACRO__FUNC__ +#define __func__ __FUNC__ +#else +#define __func__ "???" +#endif /* defined(HAVE_MACRO__FUNCTION__) || ... */ +#endif /* !defined(HAVE_MACRO__func__) */ +#endif /* defined(_MSC_VER) */ + +#define U64_TO_DBL(x) ((double) (x)) +#define DBL_TO_U64(x) ((uint64_t) (x)) + +#ifdef ENUM_VALS_ARE_SIGNED +#define ENUM_BF(t) unsigned +#else +/** Wrapper for having a bitfield of an enumerated type. Where possible, we + * just use the enumerated type (so the compiler can help us and notice + * problems), but if enumerated types are unsigned, we must use unsigned, + * so that the loss of precision doesn't make large values negative. */ +#define ENUM_BF(t) t +#endif /* defined(ENUM_VALS_ARE_SIGNED) */ + +/* GCC has several useful attributes. */ +#if defined(__GNUC__) && __GNUC__ >= 3 +#define ATTR_NORETURN __attribute__((noreturn)) +#define ATTR_CONST __attribute__((const)) +#define ATTR_MALLOC __attribute__((malloc)) +#define ATTR_NORETURN __attribute__((noreturn)) +#define ATTR_WUR __attribute__((warn_unused_result)) +/* Alas, nonnull is not at present a good idea for us. We'd like to get + * warnings when we pass NULL where we shouldn't (which nonnull does, albeit + * spottily), but we don't want to tell the compiler to make optimizations + * with the assumption that the argument can't be NULL (since this would make + * many of our checks go away, and make our code less robust against + * programming errors). Unfortunately, nonnull currently does both of these + * things, and there's no good way to split them up. + * + * #define ATTR_NONNULL(x) __attribute__((nonnull x)) */ +#define ATTR_NONNULL(x) +#define ATTR_UNUSED __attribute__ ((unused)) + +/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value + * of <b>exp</b> will probably be true. + * + * In other words, "if (PREDICT_LIKELY(foo))" is the same as "if (foo)", + * except that it tells the compiler that the branch will be taken most of the + * time. This can generate slightly better code with some CPUs. + */ +#define PREDICT_LIKELY(exp) __builtin_expect(!!(exp), 1) +/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value + * of <b>exp</b> will probably be false. + * + * In other words, "if (PREDICT_UNLIKELY(foo))" is the same as "if (foo)", + * except that it tells the compiler that the branch will usually not be + * taken. This can generate slightly better code with some CPUs. + */ +#define PREDICT_UNLIKELY(exp) __builtin_expect(!!(exp), 0) +#else /* !(defined(__GNUC__) && __GNUC__ >= 3) */ +#define ATTR_NORETURN +#define ATTR_CONST +#define ATTR_MALLOC +#define ATTR_NORETURN +#define ATTR_NONNULL(x) +#define ATTR_UNUSED +#define ATTR_WUR +#define PREDICT_LIKELY(exp) (exp) +#define PREDICT_UNLIKELY(exp) (exp) +#endif /* defined(__GNUC__) && __GNUC__ >= 3 */ + +/** Expands to a syntactically valid empty statement. */ +#define STMT_NIL (void)0 + +/** Expands to a syntactically valid empty statement, explicitly (void)ing its + * argument. */ +#define STMT_VOID(a) while (0) { (void)(a); } + +#ifdef __GNUC__ +/** STMT_BEGIN and STMT_END are used to wrap blocks inside macros so that + * the macro can be used as if it were a single C statement. */ +#define STMT_BEGIN (void) ({ +#define STMT_END }) +#elif defined(sun) || defined(__sun__) +#define STMT_BEGIN if (1) { +#define STMT_END } else STMT_NIL +#else +#define STMT_BEGIN do { +#define STMT_END } while (0) +#endif /* defined(__GNUC__) || ... */ + +/* Some tools (like coccinelle) don't like to see operators as macro + * arguments. */ +#define OP_LT < +#define OP_GT > +#define OP_GE >= +#define OP_LE <= +#define OP_EQ == +#define OP_NE != + +#ifdef _MSC_VER +/** Casts the uint64_t value in <b>a</b> to the right type for an argument + * to printf. */ +#define U64_PRINTF_ARG(a) (a) +/** Casts the uint64_t* value in <b>a</b> to the right type for an argument + * to scanf. */ +#define U64_SCANF_ARG(a) (a) +/** Expands to a literal uint64_t-typed constant for the value <b>n</b>. */ +#define U64_LITERAL(n) (n ## ui64) +#define I64_PRINTF_ARG(a) (a) +#define I64_SCANF_ARG(a) (a) +#define I64_LITERAL(n) (n ## i64) +#else /* !(defined(_MSC_VER)) */ +#define U64_PRINTF_ARG(a) ((long long unsigned int)(a)) +#define U64_SCANF_ARG(a) ((long long unsigned int*)(a)) +#define U64_LITERAL(n) (n ## llu) +#define I64_PRINTF_ARG(a) ((long long signed int)(a)) +#define I64_SCANF_ARG(a) ((long long signed int*)(a)) +#define I64_LITERAL(n) (n ## ll) +#endif /* defined(_MSC_VER) */ + +#if defined(__MINGW32__) || defined(__MINGW64__) +#define MINGW_ANY +#endif + +#if defined(_MSC_VER) || defined(MINGW_ANY) +/** The formatting string used to put a uint64_t value in a printf() or + * scanf() function. See also U64_PRINTF_ARG and U64_SCANF_ARG. */ +#define U64_FORMAT "%I64u" +#define I64_FORMAT "%I64d" +#else /* !(defined(_MSC_VER) || defined(MINGW_ANY)) */ +#define U64_FORMAT "%llu" +#define I64_FORMAT "%lld" +#endif /* defined(_MSC_VER) || defined(MINGW_ANY) */ + +#if (SIZEOF_INTPTR_T == SIZEOF_INT) +#define INTPTR_T_FORMAT "%d" +#define INTPTR_PRINTF_ARG(x) ((int)(x)) +#elif (SIZEOF_INTPTR_T == SIZEOF_LONG) +#define INTPTR_T_FORMAT "%ld" +#define INTPTR_PRINTF_ARG(x) ((long)(x)) +#elif (SIZEOF_INTPTR_T == 8) +#define INTPTR_T_FORMAT I64_FORMAT +#define INTPTR_PRINTF_ARG(x) I64_PRINTF_ARG(x) +#else +#error Unknown: SIZEOF_INTPTR_T +#endif /* (SIZEOF_INTPTR_T == SIZEOF_INT) || ... */ + +/** Macro: yield a pointer to the field at position <b>off</b> within the + * structure <b>st</b>. Example: + * <pre> + * struct a { int foo; int bar; } x; + * off_t bar_offset = offsetof(struct a, bar); + * int *bar_p = STRUCT_VAR_P(&x, bar_offset); + * *bar_p = 3; + * </pre> + */ +#define STRUCT_VAR_P(st, off) ((void*) ( ((char*)(st)) + (off) ) ) + +/** Macro: yield a pointer to an enclosing structure given a pointer to + * a substructure at offset <b>off</b>. Example: + * <pre> + * struct base { ... }; + * struct subtype { int x; struct base b; } x; + * struct base *bp = &x.base; + * struct *sp = SUBTYPE_P(bp, struct subtype, b); + * </pre> + */ +#define SUBTYPE_P(p, subtype, basemember) \ + ((void*) ( ((char*)(p)) - offsetof(subtype, basemember) )) + +/** Macro: Yields the number of elements in array x. */ +#define ARRAY_LENGTH(x) ((sizeof(x)) / sizeof(x[0])) + +#endif /* !defined(TOR_COMPAT_H) */ diff --git a/src/lib/cc/include.am b/src/lib/cc/include.am new file mode 100644 index 0000000000..2ae90f97dd --- /dev/null +++ b/src/lib/cc/include.am @@ -0,0 +1,4 @@ + +noinst_HEADERS += \ + src/lib/cc/compat_compiler.h \ + src/lib/cc/torint.h diff --git a/src/common/torint.h b/src/lib/cc/torint.h index fc7818fe2c..55b15402f2 100644 --- a/src/common/torint.h +++ b/src/lib/cc/torint.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/.may_include b/src/lib/compress/.may_include new file mode 100644 index 0000000000..68fe9f1c54 --- /dev/null +++ b/src/lib/compress/.may_include @@ -0,0 +1,12 @@ +orconfig.h +lib/arch/*.h +lib/cc/*.h +lib/compress/*.h +lib/container/*.h +lib/ctime/*.h +lib/intmath/*.h +lib/log/*.h +lib/malloc/*.h +lib/string/*.h +lib/testsupport/*.h +lib/thread/*.h diff --git a/src/common/compress.c b/src/lib/compress/compress.c index cb1549f1aa..2cb5dbaec2 100644 --- a/src/common/compress.c +++ b/src/lib/compress/compress.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,21 +12,25 @@ #include <stdlib.h> #include <stdio.h> -#include <assert.h> #include <string.h> -#include "torint.h" +#include "lib/cc/torint.h" #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_lzma.h" -#include "compress_none.h" -#include "compress_zlib.h" -#include "compress_zstd.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/arch/bytes.h" +#include "lib/ctime/di_ops.h" +#include "lib/compress/compress.h" +#include "lib/compress/compress_lzma.h" +#include "lib/compress/compress_none.h" +#include "lib/compress/compress_zlib.h" +#include "lib/compress/compress_zstd.h" +#include "lib/intmath/cmp.h" +#include "lib/malloc/util_malloc.h" +#include "lib/thread/threads.h" /** Total number of bytes allocated for compression state overhead. */ static atomic_counter_t total_compress_allocation; @@ -277,7 +281,7 @@ detect_compression_method(const char *in, size_t in_len) if (in_len > 2 && fast_memeq(in, "\x1f\x8b", 2)) { return GZIP_METHOD; } else if (in_len > 2 && (in[0] & 0x0f) == 8 && - (ntohs(get_uint16(in)) % 31) == 0) { + (tor_ntohs(get_uint16(in)) % 31) == 0) { return ZLIB_METHOD; } else if (in_len > 2 && fast_memeq(in, "\x5d\x00\x00", 3)) { @@ -672,4 +676,3 @@ tor_compress_log_init_warnings(void) { tor_zstd_warn_if_version_mismatched(); } - diff --git a/src/common/compress.h b/src/lib/compress/compress.h index 65d63a4386..ae98e1aaef 100644 --- a/src/common/compress.h +++ b/src/lib/compress/compress.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,6 +11,9 @@ #ifndef TOR_COMPRESS_H #define TOR_COMPRESS_H +#include <stddef.h> +#include "lib/testsupport/testsupport.h" + /** Enumeration of what kind of compression to use. Only ZLIB_METHOD and * GZIP_METHOD is guaranteed to be supported by the compress/uncompress * functions here. Call tor_compress_supports_method() to check if a given @@ -89,5 +92,8 @@ size_t tor_compress_state_size(const tor_compress_state_t *state); void tor_compress_init(void); void tor_compress_log_init_warnings(void); -#endif /* !defined(TOR_COMPRESS_H) */ +struct buf_t; +int buf_add_compress(struct buf_t *buf, struct tor_compress_state_t *state, + const char *data, size_t data_len, int done); +#endif /* !defined(TOR_COMPRESS_H) */ diff --git a/src/lib/compress/compress_buf.c b/src/lib/compress/compress_buf.c new file mode 100644 index 0000000000..4b88772382 --- /dev/null +++ b/src/lib/compress/compress_buf.c @@ -0,0 +1,77 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define BUFFERS_PRIVATE +#include "lib/cc/compat_compiler.h" +#include "lib/container/buffers.h" +#include "lib/compress/compress.h" +#include "lib/log/util_bug.h" + +#ifdef PARANOIA +/** Helper: If PARANOIA is defined, assert that the buffer in local variable + * <b>buf</b> is well-formed. */ +#define check() STMT_BEGIN buf_assert_ok(buf); STMT_END +#else +#define check() STMT_NIL +#endif /* defined(PARANOIA) */ + +/** Compress or uncompress the <b>data_len</b> bytes in <b>data</b> using the + * compression state <b>state</b>, appending the result to <b>buf</b>. If + * <b>done</b> is true, flush the data in the state and finish the + * compression/uncompression. Return -1 on failure, 0 on success. */ +int +buf_add_compress(buf_t *buf, tor_compress_state_t *state, + const char *data, size_t data_len, + const int done) +{ + char *next; + size_t old_avail, avail; + int over = 0; + + do { + int need_new_chunk = 0; + if (!buf->tail || ! CHUNK_REMAINING_CAPACITY(buf->tail)) { + size_t cap = data_len / 4; + buf_add_chunk_with_capacity(buf, cap, 1); + } + next = CHUNK_WRITE_PTR(buf->tail); + avail = old_avail = CHUNK_REMAINING_CAPACITY(buf->tail); + switch (tor_compress_process(state, &next, &avail, + &data, &data_len, done)) { + case TOR_COMPRESS_DONE: + over = 1; + break; + case TOR_COMPRESS_ERROR: + return -1; + case TOR_COMPRESS_OK: + if (data_len == 0) { + tor_assert_nonfatal(!done); + over = 1; + } + break; + case TOR_COMPRESS_BUFFER_FULL: + if (avail) { + /* The compression module says we need more room + * (TOR_COMPRESS_BUFFER_FULL). Start a new chunk automatically, + * whether were going to or not. */ + need_new_chunk = 1; + } + if (data_len == 0 && !done) { + /* We've consumed all the input data, though, so there's no + * point in forging ahead right now. */ + over = 1; + } + break; + } + buf->datalen += old_avail - avail; + buf->tail->datalen += old_avail - avail; + if (need_new_chunk) { + buf_add_chunk_with_capacity(buf, data_len/4, 1); + } + + } while (!over); + check(); + return 0; +} diff --git a/src/common/compress_lzma.c b/src/lib/compress/compress_lzma.c index 051c59ba2d..3b6f91b84b 100644 --- a/src/common/compress_lzma.c +++ b/src/lib/compress/compress_lzma.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,10 +13,12 @@ #include "orconfig.h" -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_lzma.h" +#include "lib/compress/compress.h" +#include "lib/compress/compress_lzma.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/thread/threads.h" #ifdef HAVE_LZMA #include <lzma.h> @@ -358,4 +360,3 @@ tor_lzma_init(void) { atomic_counter_init(&total_lzma_allocation); } - diff --git a/src/common/compress_lzma.h b/src/lib/compress/compress_lzma.h index 38a447c1f3..9ef3382a25 100644 --- a/src/common/compress_lzma.h +++ b/src/lib/compress/compress_lzma.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/common/compress_none.c b/src/lib/compress/compress_none.c index 34314e4af7..9574c47a7e 100644 --- a/src/common/compress_none.c +++ b/src/lib/compress/compress_none.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -16,10 +16,12 @@ #include "orconfig.h" -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_none.h" +#include "lib/log/torlog.h" +#include "lib/compress/compress.h" +#include "lib/compress/compress_none.h" +#include "lib/intmath/cmp.h" + +#include <string.h> /** Transfer some bytes using the identity transformation. Read up to * *<b>in_len</b> bytes from *<b>in</b>, and write up to *<b>out_len</b> bytes @@ -50,4 +52,3 @@ tor_cnone_compress_process(char **out, size_t *out_len, return TOR_COMPRESS_BUFFER_FULL; } } - diff --git a/src/common/compress_none.h b/src/lib/compress/compress_none.h index 77c3cef47b..5c395bbb30 100644 --- a/src/common/compress_none.h +++ b/src/lib/compress/compress_none.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/common/compress_zlib.c b/src/lib/compress/compress_zlib.c index 23d71d27be..12e6727dee 100644 --- a/src/common/compress_zlib.c +++ b/src/lib/compress/compress_zlib.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,10 +13,11 @@ #include "orconfig.h" -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_zlib.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/compress/compress.h" +#include "lib/compress/compress_zlib.h" +#include "lib/thread/threads.h" /* zlib 1.2.4 and 1.2.5 do some "clever" things with macros. Instead of saying "(defined(FOO) ? FOO : 0)" they like to say "FOO-0", on the theory @@ -301,4 +302,3 @@ tor_zlib_init(void) { atomic_counter_init(&total_zlib_allocation); } - diff --git a/src/common/compress_zlib.h b/src/lib/compress/compress_zlib.h index e3c1a2b339..7af68044de 100644 --- a/src/common/compress_zlib.h +++ b/src/lib/compress/compress_zlib.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/common/compress_zstd.c b/src/lib/compress/compress_zstd.c index 316a3fb417..0a553db55c 100644 --- a/src/common/compress_zstd.c +++ b/src/lib/compress/compress_zstd.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,10 +13,12 @@ #include "orconfig.h" -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_zstd.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/compress/compress.h" +#include "lib/compress/compress_zstd.h" +#include "lib/string/printf.h" +#include "lib/thread/threads.h" #ifdef ENABLE_ZSTD_ADVANCED_APIS /* This is a lie, but we make sure it doesn't get us in trouble by wrapping @@ -533,4 +535,3 @@ tor_zstd_set_static_apis_disabled_for_testing(int disabled) static_apis_disable_for_testing = disabled; } #endif - diff --git a/src/common/compress_zstd.h b/src/lib/compress/compress_zstd.h index bd42cf65ce..1177537a9e 100644 --- a/src/common/compress_zstd.h +++ b/src/lib/compress/compress_zstd.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/include.am b/src/lib/compress/include.am new file mode 100644 index 0000000000..75c9032bd2 --- /dev/null +++ b/src/lib/compress/include.am @@ -0,0 +1,26 @@ + +noinst_LIBRARIES += src/lib/libtor-compress.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-compress-testing.a +endif + +src_lib_libtor_compress_a_SOURCES = \ + src/lib/compress/compress.c \ + src/lib/compress/compress_buf.c \ + src/lib/compress/compress_lzma.c \ + src/lib/compress/compress_none.c \ + src/lib/compress/compress_zlib.c \ + src/lib/compress/compress_zstd.c + +src_lib_libtor_compress_testing_a_SOURCES = \ + $(src_lib_libtor_compress_a_SOURCES) +src_lib_libtor_compress_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_compress_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/compress/compress.h \ + src/lib/compress/compress_lzma.h \ + src/lib/compress/compress_none.h \ + src/lib/compress/compress_zlib.h \ + src/lib/compress/compress_zstd.h diff --git a/src/lib/container/.may_include b/src/lib/container/.may_include new file mode 100644 index 0000000000..90de5eda40 --- /dev/null +++ b/src/lib/container/.may_include @@ -0,0 +1,18 @@ +orconfig.h +lib/cc/*.h +lib/container/*.h +lib/ctime/*.h +lib/defs/*.h +lib/malloc/*.h +lib/err/*.h +lib/smartlist_core/*.h +lib/string/*.h +lib/testsupport/testsupport.h +lib/intmath/*.h +lib/log/*.h + +# XXXX I am unsure about this one. It's only here for buffers.c +lib/time/*.h + +ht.h +siphash.h diff --git a/src/lib/container/bitarray.h b/src/lib/container/bitarray.h new file mode 100644 index 0000000000..2cea433fb0 --- /dev/null +++ b/src/lib/container/bitarray.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_BITARRAY_H +#define TOR_BITARRAY_H + +#include "orconfig.h" +#include <string.h> +#include "lib/cc/torint.h" +#include "lib/malloc/util_malloc.h" + +#if SIZEOF_INT == 4 +#define BITARRAY_SHIFT 5 +#elif SIZEOF_INT == 8 +#define BITARRAY_SHIFT 6 +#else +#error "int is neither 4 nor 8 bytes. I can't deal with that." +#endif /* SIZEOF_INT == 4 || ... */ +#define BITARRAY_MASK ((1u<<BITARRAY_SHIFT)-1) + +/** A random-access array of one-bit-wide elements. */ +typedef unsigned int bitarray_t; +/** Create a new bit array that can hold <b>n_bits</b> bits. */ +static inline bitarray_t * +bitarray_init_zero(unsigned int n_bits) +{ + /* round up to the next int. */ + size_t sz = (n_bits+BITARRAY_MASK) >> BITARRAY_SHIFT; + return tor_calloc(sz, sizeof(unsigned int)); +} +/** Expand <b>ba</b> from holding <b>n_bits_old</b> to <b>n_bits_new</b>, + * clearing all new bits. Returns a possibly changed pointer to the + * bitarray. */ +static inline bitarray_t * +bitarray_expand(bitarray_t *ba, + unsigned int n_bits_old, unsigned int n_bits_new) +{ + size_t sz_old = (n_bits_old+BITARRAY_MASK) >> BITARRAY_SHIFT; + size_t sz_new = (n_bits_new+BITARRAY_MASK) >> BITARRAY_SHIFT; + char *ptr; + if (sz_new <= sz_old) + return ba; + ptr = tor_reallocarray(ba, sz_new, sizeof(unsigned int)); + /* This memset does nothing to the older excess bytes. But they were + * already set to 0 by bitarry_init_zero. */ + memset(ptr+sz_old*sizeof(unsigned int), 0, + (sz_new-sz_old)*sizeof(unsigned int)); + return (bitarray_t*) ptr; +} +/** Free the bit array <b>ba</b>. */ +static inline void +bitarray_free_(bitarray_t *ba) +{ + tor_free(ba); +} +#define bitarray_free(ba) FREE_AND_NULL(bitarray_t, bitarray_free_, (ba)) + +/** Set the <b>bit</b>th bit in <b>b</b> to 1. */ +static inline void +bitarray_set(bitarray_t *b, int bit) +{ + b[bit >> BITARRAY_SHIFT] |= (1u << (bit & BITARRAY_MASK)); +} +/** Set the <b>bit</b>th bit in <b>b</b> to 0. */ +static inline void +bitarray_clear(bitarray_t *b, int bit) +{ + b[bit >> BITARRAY_SHIFT] &= ~ (1u << (bit & BITARRAY_MASK)); +} +/** Return true iff <b>bit</b>th bit in <b>b</b> is nonzero. NOTE: does + * not necessarily return 1 on true. */ +static inline unsigned int +bitarray_is_set(bitarray_t *b, int bit) +{ + return b[bit >> BITARRAY_SHIFT] & (1u << (bit & BITARRAY_MASK)); +} + +#endif /* !defined(TOR_CONTAINER_H) */ diff --git a/src/lib/container/bloomfilt.c b/src/lib/container/bloomfilt.c new file mode 100644 index 0000000000..1cab817e18 --- /dev/null +++ b/src/lib/container/bloomfilt.c @@ -0,0 +1,113 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file bloomfilt.c + * \brief Uses bitarray_t to implement a bloom filter. + **/ + +#include <stdlib.h> + +#include "lib/malloc/util_malloc.h" +#include "lib/container/bloomfilt.h" +#include "lib/intmath/bits.h" +#include "lib/log/util_bug.h" +#include "siphash.h" + +/** How many bloom-filter bits we set per address. This is twice the + * BLOOMFILT_N_HASHES value, since we split the siphash output into two 32-bit + * values. */ +#define N_BITS_PER_ITEM (BLOOMFILT_N_HASHES * 2) + +struct bloomfilt_t { + /** siphash keys to make BLOOMFILT_N_HASHES independent hashes for each + * items. */ + struct sipkey key[BLOOMFILT_N_HASHES]; + bloomfilt_hash_fn hashfn; /**< Function used to generate hashes */ + uint32_t mask; /**< One less than the number of bits in <b>ba</b>; always + * one less than a power of two. */ + bitarray_t *ba; /**< A bit array to implement the Bloom filter. */ +}; + +#define BIT(set, n) ((n) & (set)->mask) + +/** Add the element <b>item</b> to <b>set</b>. */ +void +bloomfilt_add(bloomfilt_t *set, + const void *item) +{ + int i; + for (i = 0; i < BLOOMFILT_N_HASHES; ++i) { + uint64_t h = set->hashfn(&set->key[i], item); + uint32_t high_bits = (uint32_t)(h >> 32); + uint32_t low_bits = (uint32_t)(h); + bitarray_set(set->ba, BIT(set, high_bits)); + bitarray_set(set->ba, BIT(set, low_bits)); + } +} + +/** If <b>item</b> is in <b>set</b>, return nonzero. Otherwise, + * <em>probably</em> return zero. */ +int +bloomfilt_probably_contains(const bloomfilt_t *set, + const void *item) +{ + int i, matches = 0; + for (i = 0; i < BLOOMFILT_N_HASHES; ++i) { + uint64_t h = set->hashfn(&set->key[i], item); + uint32_t high_bits = (uint32_t)(h >> 32); + uint32_t low_bits = (uint32_t)(h); + // Note that !! is necessary here, since bitarray_is_set does not + // necessarily return 1 on true. + matches += !! bitarray_is_set(set->ba, BIT(set, high_bits)); + matches += !! bitarray_is_set(set->ba, BIT(set, low_bits)); + } + return matches == N_BITS_PER_ITEM; +} + +/** Return a newly allocated bloomfilt_t, optimized to hold a total of + * <b>max_elements</b> elements with a reasonably low false positive weight. + * + * Uses the siphash-based function <b>hashfn</b> to compute hard-to-collide + * functions of the items, and the key material <b>random_key</b> to + * key the hash. There must be BLOOMFILT_KEY_LEN bytes in the supplied key. + **/ +bloomfilt_t * +bloomfilt_new(int max_elements, + bloomfilt_hash_fn hashfn, + const uint8_t *random_key) +{ + /* The probability of false positives is about P=(1 - exp(-kn/m))^k, where k + * is the number of hash functions per entry, m is the bits in the array, + * and n is the number of elements inserted. For us, k==4, n<=max_elements, + * and m==n_bits= approximately max_elements*32. This gives + * P<(1-exp(-4*n/(32*n)))^4 == (1-exp(1/-8))^4 == .00019 + * + * It would be more optimal in space vs false positives to get this false + * positive rate by going for k==13, and m==18.5n, but we also want to + * conserve CPU, and k==13 is pretty big. + */ + int n_bits = 1u << (tor_log2(max_elements)+5); + bloomfilt_t *r = tor_malloc(sizeof(bloomfilt_t)); + r->mask = n_bits - 1; + r->ba = bitarray_init_zero(n_bits); + + tor_assert(sizeof(r->key) == BLOOMFILT_KEY_LEN); + memcpy(r->key, random_key, sizeof(r->key)); + + r->hashfn = hashfn; + + return r; +} + +/** Free all storage held in <b>set</b>. */ +void +bloomfilt_free_(bloomfilt_t *set) +{ + if (!set) + return; + bitarray_free(set->ba); + tor_free(set); +} diff --git a/src/lib/container/bloomfilt.h b/src/lib/container/bloomfilt.h new file mode 100644 index 0000000000..577acf5e48 --- /dev/null +++ b/src/lib/container/bloomfilt.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_BLOOMFILT_H +#define TOR_BLOOMFILT_H + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/container/bitarray.h" + +/** A set of elements, implemented as a Bloom filter. */ +typedef struct bloomfilt_t bloomfilt_t; + +/** How many 64-bit siphash values to extract per item. */ +#define BLOOMFILT_N_HASHES 2 + +/** How much key material do we need to randomize hashes? */ +#define BLOOMFILT_KEY_LEN (BLOOMFILT_N_HASHES * 16) + +struct sipkey; +typedef uint64_t (*bloomfilt_hash_fn)(const struct sipkey *key, + const void *item); + +void bloomfilt_add(bloomfilt_t *set, const void *item); +int bloomfilt_probably_contains(const bloomfilt_t *set, const void *item); + +bloomfilt_t *bloomfilt_new(int max_elements, + bloomfilt_hash_fn hashfn, + const uint8_t *random_key); +void bloomfilt_free_(bloomfilt_t* set); +#define bloomfilt_free(set) FREE_AND_NULL(bloomfilt_t, bloomfilt_free_, (set)) + +#endif /* !defined(TOR_BLOOMFILT_H) */ diff --git a/src/common/buffers.c b/src/lib/container/buffers.c index a01add9bef..0e98033bfd 100644 --- a/src/common/buffers.c +++ b/src/lib/container/buffers.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,16 +21,22 @@ #define BUFFERS_PRIVATE #include "orconfig.h" #include <stddef.h> -#include "buffers.h" -#include "compat.h" -#include "compress.h" -#include "util.h" -#include "torint.h" -#include "torlog.h" +#include "lib/container/buffers.h" +#include "lib/cc/torint.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/ctime/di_ops.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/printf.h" +#include "lib/time/compat_time.h" + #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#include <stdlib.h> +#include <string.h> + //#define PARANOIA #ifdef PARANOIA @@ -506,177 +512,6 @@ buf_get_total_allocation(void) return total_bytes_allocated_in_chunks; } -/** Read up to <b>at_most</b> bytes from the socket <b>fd</b> into - * <b>chunk</b> (which must be on <b>buf</b>). If we get an EOF, set - * *<b>reached_eof</b> to 1. Return -1 on error, 0 on eof or blocking, - * and the number of bytes read otherwise. */ -static inline int -read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most, - int *reached_eof, int *socket_error) -{ - ssize_t read_result; - if (at_most > CHUNK_REMAINING_CAPACITY(chunk)) - at_most = CHUNK_REMAINING_CAPACITY(chunk); - read_result = tor_socket_recv(fd, CHUNK_WRITE_PTR(chunk), at_most, 0); - - if (read_result < 0) { - int e = tor_socket_errno(fd); - if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ -#ifdef _WIN32 - if (e == WSAENOBUFS) - log_warn(LD_NET,"recv() failed: WSAENOBUFS. Not enough ram?"); -#endif - *socket_error = e; - return -1; - } - return 0; /* would block. */ - } else if (read_result == 0) { - log_debug(LD_NET,"Encountered eof on fd %d", (int)fd); - *reached_eof = 1; - return 0; - } else { /* actually got bytes. */ - buf->datalen += read_result; - chunk->datalen += read_result; - log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result, - (int)buf->datalen); - tor_assert(read_result < INT_MAX); - return (int)read_result; - } -} - -/** Read from socket <b>s</b>, writing onto end of <b>buf</b>. Read at most - * <b>at_most</b> bytes, growing the buffer as necessary. If recv() returns 0 - * (because of EOF), set *<b>reached_eof</b> to 1 and return 0. Return -1 on - * error; else return the number of bytes read. - */ -/* XXXX indicate "read blocked" somehow? */ -int -buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most, - int *reached_eof, - int *socket_error) -{ - /* XXXX It's stupid to overload the return values for these functions: - * "error status" and "number of bytes read" are not mutually exclusive. - */ - int r = 0; - size_t total_read = 0; - - check(); - tor_assert(reached_eof); - tor_assert(SOCKET_OK(s)); - - if (BUG(buf->datalen >= INT_MAX)) - return -1; - if (BUG(buf->datalen >= INT_MAX - at_most)) - return -1; - - while (at_most > total_read) { - size_t readlen = at_most - total_read; - chunk_t *chunk; - if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) { - chunk = buf_add_chunk_with_capacity(buf, at_most, 1); - if (readlen > chunk->memlen) - readlen = chunk->memlen; - } else { - size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail); - chunk = buf->tail; - if (cap < readlen) - readlen = cap; - } - - r = read_to_chunk(buf, chunk, s, readlen, reached_eof, socket_error); - check(); - if (r < 0) - return r; /* Error */ - tor_assert(total_read+r < INT_MAX); - total_read += r; - if ((size_t)r < readlen) { /* eof, block, or no more to read. */ - break; - } - } - return (int)total_read; -} - -/** Helper for buf_flush_to_socket(): try to write <b>sz</b> bytes from chunk - * <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. On success, deduct - * the bytes written from *<b>buf_flushlen</b>. Return the number of bytes - * written on success, 0 on blocking, -1 on failure. - */ -static inline int -flush_chunk(tor_socket_t s, buf_t *buf, chunk_t *chunk, size_t sz, - size_t *buf_flushlen) -{ - ssize_t write_result; - - if (sz > chunk->datalen) - sz = chunk->datalen; - write_result = tor_socket_send(s, chunk->data, sz, 0); - - if (write_result < 0) { - int e = tor_socket_errno(s); - if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ -#ifdef _WIN32 - if (e == WSAENOBUFS) - log_warn(LD_NET,"write() failed: WSAENOBUFS. Not enough ram?"); -#endif - return -1; - } - log_debug(LD_NET,"write() would block, returning."); - return 0; - } else { - *buf_flushlen -= write_result; - buf_drain(buf, write_result); - tor_assert(write_result < INT_MAX); - return (int)write_result; - } -} - -/** Write data from <b>buf</b> to the socket <b>s</b>. Write at most - * <b>sz</b> bytes, decrement *<b>buf_flushlen</b> by - * the number of bytes actually written, and remove the written bytes - * from the buffer. Return the number of bytes written on success, - * -1 on failure. Return 0 if write() would block. - */ -int -buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz, - size_t *buf_flushlen) -{ - /* XXXX It's stupid to overload the return values for these functions: - * "error status" and "number of bytes flushed" are not mutually exclusive. - */ - int r; - size_t flushed = 0; - tor_assert(buf_flushlen); - tor_assert(SOCKET_OK(s)); - if (BUG(*buf_flushlen > buf->datalen)) { - *buf_flushlen = buf->datalen; - } - if (BUG(sz > *buf_flushlen)) { - sz = *buf_flushlen; - } - - check(); - while (sz) { - size_t flushlen0; - tor_assert(buf->head); - if (buf->head->datalen >= sz) - flushlen0 = sz; - else - flushlen0 = buf->head->datalen; - - r = flush_chunk(s, buf, buf->head, flushlen0, buf_flushlen); - check(); - if (r < 0) - return r; - flushed += r; - sz -= r; - if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */ - break; - } - tor_assert(flushed < INT_MAX); - return (int)flushed; -} - /** Append <b>string_len</b> bytes from <b>string</b> to the end of * <b>buf</b>. * @@ -1037,65 +872,6 @@ buf_get_line(buf_t *buf, char *data_out, size_t *data_len) return 1; } -/** Compress or uncompress the <b>data_len</b> bytes in <b>data</b> using the - * compression state <b>state</b>, appending the result to <b>buf</b>. If - * <b>done</b> is true, flush the data in the state and finish the - * compression/uncompression. Return -1 on failure, 0 on success. */ -int -buf_add_compress(buf_t *buf, tor_compress_state_t *state, - const char *data, size_t data_len, - const int done) -{ - char *next; - size_t old_avail, avail; - int over = 0; - - do { - int need_new_chunk = 0; - if (!buf->tail || ! CHUNK_REMAINING_CAPACITY(buf->tail)) { - size_t cap = data_len / 4; - buf_add_chunk_with_capacity(buf, cap, 1); - } - next = CHUNK_WRITE_PTR(buf->tail); - avail = old_avail = CHUNK_REMAINING_CAPACITY(buf->tail); - switch (tor_compress_process(state, &next, &avail, - &data, &data_len, done)) { - case TOR_COMPRESS_DONE: - over = 1; - break; - case TOR_COMPRESS_ERROR: - return -1; - case TOR_COMPRESS_OK: - if (data_len == 0) { - tor_assert_nonfatal(!done); - over = 1; - } - break; - case TOR_COMPRESS_BUFFER_FULL: - if (avail) { - /* The compression module says we need more room - * (TOR_COMPRESS_BUFFER_FULL). Start a new chunk automatically, - * whether were going to or not. */ - need_new_chunk = 1; - } - if (data_len == 0 && !done) { - /* We've consumed all the input data, though, so there's no - * point in forging ahead right now. */ - over = 1; - } - break; - } - buf->datalen += old_avail - avail; - buf->tail->datalen += old_avail - avail; - if (need_new_chunk) { - buf_add_chunk_with_capacity(buf, data_len/4, 1); - } - - } while (!over); - check(); - return 0; -} - /** Set *<b>output</b> to contain a copy of the data in *<b>input</b> */ int buf_set_to_copy(buf_t **output, @@ -1143,4 +919,3 @@ buf_assert_ok(buf_t *buf) tor_assert(buf->datalen == total); } } - diff --git a/src/common/buffers.h b/src/lib/container/buffers.h index 4275152de2..8b16fb298b 100644 --- a/src/common/buffers.h +++ b/src/lib/container/buffers.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,9 +12,11 @@ #ifndef TOR_BUFFERS_H #define TOR_BUFFERS_H -#include "compat.h" -#include "torint.h" -#include "testsupport.h" +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" + +#include <stdarg.h> typedef struct buf_t buf_t; @@ -35,21 +37,12 @@ size_t buf_slack(const buf_t *buf); uint32_t buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now); size_t buf_get_total_allocation(void); -int buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most, - int *reached_eof, - int *socket_error); - -int buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz, - size_t *buf_flushlen); - int buf_add(buf_t *buf, const char *string, size_t string_len); void buf_add_string(buf_t *buf, const char *string); void buf_add_printf(buf_t *buf, const char *format, ...) CHECK_PRINTF(2, 3); void buf_add_vprintf(buf_t *buf, const char *format, va_list args) CHECK_PRINTF(2, 0); -int buf_add_compress(buf_t *buf, struct tor_compress_state_t *state, - const char *data, size_t data_len, int done); int buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen); void buf_move_all(buf_t *buf_out, buf_t *buf_in); void buf_peek(const buf_t *buf, char *string, size_t string_len); @@ -128,4 +121,3 @@ CHUNK_WRITE_PTR(chunk_t *chunk) #endif /* defined(BUFFERS_PRIVATE) */ #endif /* !defined(TOR_BUFFERS_H) */ - diff --git a/src/lib/container/include.am b/src/lib/container/include.am new file mode 100644 index 0000000000..e91ad7d1ca --- /dev/null +++ b/src/lib/container/include.am @@ -0,0 +1,26 @@ + +noinst_LIBRARIES += src/lib/libtor-container.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-container-testing.a +endif + +src_lib_libtor_container_a_SOURCES = \ + src/lib/container/bloomfilt.c \ + src/lib/container/buffers.c \ + src/lib/container/map.c \ + src/lib/container/order.c \ + src/lib/container/smartlist.c + +src_lib_libtor_container_testing_a_SOURCES = \ + $(src_lib_libtor_container_a_SOURCES) +src_lib_libtor_container_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_container_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/container/bitarray.h \ + src/lib/container/bloomfilt.h \ + src/lib/container/buffers.h \ + src/lib/container/map.h \ + src/lib/container/order.h \ + src/lib/container/smartlist.h diff --git a/src/lib/container/map.c b/src/lib/container/map.c new file mode 100644 index 0000000000..3d84356cc8 --- /dev/null +++ b/src/lib/container/map.c @@ -0,0 +1,412 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file container.c + * \brief Hash table implementations of a string-to-void* map, and of + * a digest-to-void* map. + **/ + +#include "lib/container/map.h" +#include "lib/ctime/di_ops.h" +#include "lib/defs/digest_sizes.h" +#include "lib/string/util_string.h" +#include "lib/malloc/util_malloc.h" + +#include "lib/log/util_bug.h" + +#include <stdlib.h> +#include <string.h> + +#include "ht.h" + +/** Helper: Declare an entry type and a map type to implement a mapping using + * ht.h. The map type will be called <b>maptype</b>. The key part of each + * entry is declared using the C declaration <b>keydecl</b>. All functions + * and types associated with the map get prefixed with <b>prefix</b> */ +#define DEFINE_MAP_STRUCTS(maptype, keydecl, prefix) \ + typedef struct prefix ## entry_t { \ + HT_ENTRY(prefix ## entry_t) node; \ + void *val; \ + keydecl; \ + } prefix ## entry_t; \ + struct maptype { \ + HT_HEAD(prefix ## impl, prefix ## entry_t) head; \ + } + +DEFINE_MAP_STRUCTS(strmap_t, char *key, strmap_); +DEFINE_MAP_STRUCTS(digestmap_t, char key[DIGEST_LEN], digestmap_); +DEFINE_MAP_STRUCTS(digest256map_t, uint8_t key[DIGEST256_LEN], digest256map_); + +/** Helper: compare strmap_entry_t objects by key value. */ +static inline int +strmap_entries_eq(const strmap_entry_t *a, const strmap_entry_t *b) +{ + return !strcmp(a->key, b->key); +} + +/** Helper: return a hash value for a strmap_entry_t. */ +static inline unsigned int +strmap_entry_hash(const strmap_entry_t *a) +{ + return (unsigned) siphash24g(a->key, strlen(a->key)); +} + +/** Helper: compare digestmap_entry_t objects by key value. */ +static inline int +digestmap_entries_eq(const digestmap_entry_t *a, const digestmap_entry_t *b) +{ + return tor_memeq(a->key, b->key, DIGEST_LEN); +} + +/** Helper: return a hash value for a digest_map_t. */ +static inline unsigned int +digestmap_entry_hash(const digestmap_entry_t *a) +{ + return (unsigned) siphash24g(a->key, DIGEST_LEN); +} + +/** Helper: compare digestmap_entry_t objects by key value. */ +static inline int +digest256map_entries_eq(const digest256map_entry_t *a, + const digest256map_entry_t *b) +{ + return tor_memeq(a->key, b->key, DIGEST256_LEN); +} + +/** Helper: return a hash value for a digest_map_t. */ +static inline unsigned int +digest256map_entry_hash(const digest256map_entry_t *a) +{ + return (unsigned) siphash24g(a->key, DIGEST256_LEN); +} + +HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash, + strmap_entries_eq) +HT_GENERATE2(strmap_impl, strmap_entry_t, node, strmap_entry_hash, + strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_) + +HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, + digestmap_entries_eq) +HT_GENERATE2(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, + digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_) + +HT_PROTOTYPE(digest256map_impl, digest256map_entry_t, node, + digest256map_entry_hash, + digest256map_entries_eq) +HT_GENERATE2(digest256map_impl, digest256map_entry_t, node, + digest256map_entry_hash, + digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_) + +#define strmap_entry_free(ent) \ + FREE_AND_NULL(strmap_entry_t, strmap_entry_free_, (ent)) +#define digestmap_entry_free(ent) \ + FREE_AND_NULL(digestmap_entry_t, digestmap_entry_free_, (ent)) +#define digest256map_entry_free(ent) \ + FREE_AND_NULL(digest256map_entry_t, digest256map_entry_free_, (ent)) + +static inline void +strmap_entry_free_(strmap_entry_t *ent) +{ + tor_free(ent->key); + tor_free(ent); +} +static inline void +digestmap_entry_free_(digestmap_entry_t *ent) +{ + tor_free(ent); +} +static inline void +digest256map_entry_free_(digest256map_entry_t *ent) +{ + tor_free(ent); +} + +static inline void +strmap_assign_tmp_key(strmap_entry_t *ent, const char *key) +{ + ent->key = (char*)key; +} +static inline void +digestmap_assign_tmp_key(digestmap_entry_t *ent, const char *key) +{ + memcpy(ent->key, key, DIGEST_LEN); +} +static inline void +digest256map_assign_tmp_key(digest256map_entry_t *ent, const uint8_t *key) +{ + memcpy(ent->key, key, DIGEST256_LEN); +} +static inline void +strmap_assign_key(strmap_entry_t *ent, const char *key) +{ + ent->key = tor_strdup(key); +} +static inline void +digestmap_assign_key(digestmap_entry_t *ent, const char *key) +{ + memcpy(ent->key, key, DIGEST_LEN); +} +static inline void +digest256map_assign_key(digest256map_entry_t *ent, const uint8_t *key) +{ + memcpy(ent->key, key, DIGEST256_LEN); +} + +/** + * Macro: implement all the functions for a map that are declared in + * map.h by the DECLARE_MAP_FNS() macro. You must additionally define a + * prefix_entry_free_() function to free entries (and their keys), a + * prefix_assign_tmp_key() function to temporarily set a stack-allocated + * entry to hold a key, and a prefix_assign_key() function to set a + * heap-allocated entry to hold a key. + */ +#define IMPLEMENT_MAP_FNS(maptype, keytype, prefix) \ + /** Create and return a new empty map. */ \ + MOCK_IMPL(maptype *, \ + prefix##_new,(void)) \ + { \ + maptype *result; \ + result = tor_malloc(sizeof(maptype)); \ + HT_INIT(prefix##_impl, &result->head); \ + return result; \ + } \ + \ + /** Return the item from <b>map</b> whose key matches <b>key</b>, or \ + * NULL if no such value exists. */ \ + void * \ + prefix##_get(const maptype *map, const keytype key) \ + { \ + prefix ##_entry_t *resolve; \ + prefix ##_entry_t search; \ + tor_assert(map); \ + tor_assert(key); \ + prefix ##_assign_tmp_key(&search, key); \ + resolve = HT_FIND(prefix ##_impl, &map->head, &search); \ + if (resolve) { \ + return resolve->val; \ + } else { \ + return NULL; \ + } \ + } \ + \ + /** Add an entry to <b>map</b> mapping <b>key</b> to <b>val</b>; \ + * return the previous value, or NULL if no such value existed. */ \ + void * \ + prefix##_set(maptype *map, const keytype key, void *val) \ + { \ + prefix##_entry_t search; \ + void *oldval; \ + tor_assert(map); \ + tor_assert(key); \ + tor_assert(val); \ + prefix##_assign_tmp_key(&search, key); \ + /* We a lot of our time in this function, so the code below is */ \ + /* meant to optimize the check/alloc/set cycle by avoiding the two */\ + /* trips to the hash table that we would do in the unoptimized */ \ + /* version of this code. (Each of HT_INSERT and HT_FIND calls */ \ + /* HT_SET_HASH and HT_FIND_P.) */ \ + HT_FIND_OR_INSERT_(prefix##_impl, node, prefix##_entry_hash, \ + &(map->head), \ + prefix##_entry_t, &search, ptr, \ + { \ + /* we found an entry. */ \ + oldval = (*ptr)->val; \ + (*ptr)->val = val; \ + return oldval; \ + }, \ + { \ + /* We didn't find the entry. */ \ + prefix##_entry_t *newent = \ + tor_malloc_zero(sizeof(prefix##_entry_t)); \ + prefix##_assign_key(newent, key); \ + newent->val = val; \ + HT_FOI_INSERT_(node, &(map->head), \ + &search, newent, ptr); \ + return NULL; \ + }); \ + } \ + \ + /** Remove the value currently associated with <b>key</b> from the map. \ + * Return the value if one was set, or NULL if there was no entry for \ + * <b>key</b>. \ + * \ + * Note: you must free any storage associated with the returned value. \ + */ \ + void * \ + prefix##_remove(maptype *map, const keytype key) \ + { \ + prefix##_entry_t *resolve; \ + prefix##_entry_t search; \ + void *oldval; \ + tor_assert(map); \ + tor_assert(key); \ + prefix##_assign_tmp_key(&search, key); \ + resolve = HT_REMOVE(prefix##_impl, &map->head, &search); \ + if (resolve) { \ + oldval = resolve->val; \ + prefix##_entry_free(resolve); \ + return oldval; \ + } else { \ + return NULL; \ + } \ + } \ + \ + /** Return the number of elements in <b>map</b>. */ \ + int \ + prefix##_size(const maptype *map) \ + { \ + return HT_SIZE(&map->head); \ + } \ + \ + /** Return true iff <b>map</b> has no entries. */ \ + int \ + prefix##_isempty(const maptype *map) \ + { \ + return HT_EMPTY(&map->head); \ + } \ + \ + /** Assert that <b>map</b> is not corrupt. */ \ + void \ + prefix##_assert_ok(const maptype *map) \ + { \ + tor_assert(!prefix##_impl_HT_REP_IS_BAD_(&map->head)); \ + } \ + \ + /** Remove all entries from <b>map</b>, and deallocate storage for \ + * those entries. If free_val is provided, invoked it every value in \ + * <b>map</b>. */ \ + MOCK_IMPL(void, \ + prefix##_free_, (maptype *map, void (*free_val)(void*))) \ + { \ + prefix##_entry_t **ent, **next, *this; \ + if (!map) \ + return; \ + for (ent = HT_START(prefix##_impl, &map->head); ent != NULL; \ + ent = next) { \ + this = *ent; \ + next = HT_NEXT_RMV(prefix##_impl, &map->head, ent); \ + if (free_val) \ + free_val(this->val); \ + prefix##_entry_free(this); \ + } \ + tor_assert(HT_EMPTY(&map->head)); \ + HT_CLEAR(prefix##_impl, &map->head); \ + tor_free(map); \ + } \ + \ + /** return an <b>iterator</b> pointer to the front of a map. \ + * \ + * Iterator example: \ + * \ + * \code \ + * // uppercase values in "map", removing empty values. \ + * \ + * strmap_iter_t *iter; \ + * const char *key; \ + * void *val; \ + * char *cp; \ + * \ + * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) { \ + * strmap_iter_get(iter, &key, &val); \ + * cp = (char*)val; \ + * if (!*cp) { \ + * iter = strmap_iter_next_rmv(map,iter); \ + * free(val); \ + * } else { \ + * for (;*cp;cp++) *cp = TOR_TOUPPER(*cp); \ + */ \ + prefix##_iter_t * \ + prefix##_iter_init(maptype *map) \ + { \ + tor_assert(map); \ + return HT_START(prefix##_impl, &map->head); \ + } \ + \ + /** Advance <b>iter</b> a single step to the next entry, and return \ + * its new value. */ \ + prefix##_iter_t * \ + prefix##_iter_next(maptype *map, prefix##_iter_t *iter) \ + { \ + tor_assert(map); \ + tor_assert(iter); \ + return HT_NEXT(prefix##_impl, &map->head, iter); \ + } \ + /** Advance <b>iter</b> a single step to the next entry, removing the \ + * current entry, and return its new value. */ \ + prefix##_iter_t * \ + prefix##_iter_next_rmv(maptype *map, prefix##_iter_t *iter) \ + { \ + prefix##_entry_t *rmv; \ + tor_assert(map); \ + tor_assert(iter); \ + tor_assert(*iter); \ + rmv = *iter; \ + iter = HT_NEXT_RMV(prefix##_impl, &map->head, iter); \ + prefix##_entry_free(rmv); \ + return iter; \ + } \ + /** Set *<b>keyp</b> and *<b>valp</b> to the current entry pointed \ + * to by iter. */ \ + void \ + prefix##_iter_get(prefix##_iter_t *iter, const keytype *keyp, \ + void **valp) \ + { \ + tor_assert(iter); \ + tor_assert(*iter); \ + tor_assert(keyp); \ + tor_assert(valp); \ + *keyp = (*iter)->key; \ + *valp = (*iter)->val; \ + } \ + /** Return true iff <b>iter</b> has advanced past the last entry of \ + * <b>map</b>. */ \ + int \ + prefix##_iter_done(prefix##_iter_t *iter) \ + { \ + return iter == NULL; \ + } + +IMPLEMENT_MAP_FNS(strmap_t, char *, strmap) +IMPLEMENT_MAP_FNS(digestmap_t, char *, digestmap) +IMPLEMENT_MAP_FNS(digest256map_t, uint8_t *, digest256map) + +/** Same as strmap_set, but first converts <b>key</b> to lowercase. */ +void * +strmap_set_lc(strmap_t *map, const char *key, void *val) +{ + /* We could be a little faster by using strcasecmp instead, and a separate + * type, but I don't think it matters. */ + void *v; + char *lc_key = tor_strdup(key); + tor_strlower(lc_key); + v = strmap_set(map,lc_key,val); + tor_free(lc_key); + return v; +} + +/** Same as strmap_get, but first converts <b>key</b> to lowercase. */ +void * +strmap_get_lc(const strmap_t *map, const char *key) +{ + void *v; + char *lc_key = tor_strdup(key); + tor_strlower(lc_key); + v = strmap_get(map,lc_key); + tor_free(lc_key); + return v; +} + +/** Same as strmap_remove, but first converts <b>key</b> to lowercase */ +void * +strmap_remove_lc(strmap_t *map, const char *key) +{ + void *v; + char *lc_key = tor_strdup(key); + tor_strlower(lc_key); + v = strmap_remove(map,lc_key); + tor_free(lc_key); + return v; +} diff --git a/src/lib/container/map.h b/src/lib/container/map.h new file mode 100644 index 0000000000..ac21c28718 --- /dev/null +++ b/src/lib/container/map.h @@ -0,0 +1,255 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_MAP_H +#define TOR_MAP_H + +#include "lib/testsupport/testsupport.h" +#include "lib/cc/torint.h" + +#include "siphash.h" + +#define DECLARE_MAP_FNS(maptype, keytype, prefix) \ + typedef struct maptype maptype; \ + typedef struct prefix##entry_t *prefix##iter_t; \ + MOCK_DECL(maptype*, prefix##new, (void)); \ + void* prefix##set(maptype *map, keytype key, void *val); \ + void* prefix##get(const maptype *map, keytype key); \ + void* prefix##remove(maptype *map, keytype key); \ + MOCK_DECL(void, prefix##free_, (maptype *map, void (*free_val)(void*))); \ + int prefix##isempty(const maptype *map); \ + int prefix##size(const maptype *map); \ + prefix##iter_t *prefix##iter_init(maptype *map); \ + prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter); \ + prefix##iter_t *prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter); \ + void prefix##iter_get(prefix##iter_t *iter, keytype *keyp, void **valp); \ + int prefix##iter_done(prefix##iter_t *iter); \ + void prefix##assert_ok(const maptype *map) + +/* Map from const char * to void *. Implemented with a hash table. */ +DECLARE_MAP_FNS(strmap_t, const char *, strmap_); +/* Map from const char[DIGEST_LEN] to void *. Implemented with a hash table. */ +DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_); +/* Map from const uint8_t[DIGEST256_LEN] to void *. Implemented with a hash + * table. */ +DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_); + +#define MAP_FREE_AND_NULL(maptype, map, fn) \ + do { \ + maptype ## _free_((map), (fn)); \ + (map) = NULL; \ + } while (0) + +#define strmap_free(map, fn) MAP_FREE_AND_NULL(strmap, (map), (fn)) +#define digestmap_free(map, fn) MAP_FREE_AND_NULL(digestmap, (map), (fn)) +#define digest256map_free(map, fn) MAP_FREE_AND_NULL(digest256map, (map), (fn)) + +#undef DECLARE_MAP_FNS + +/** Iterates over the key-value pairs in a map <b>map</b> in order. + * <b>prefix</b> is as for DECLARE_MAP_FNS (i.e., strmap_ or digestmap_). + * The map's keys and values are of type keytype and valtype respectively; + * each iteration assigns them to keyvar and valvar. + * + * Example use: + * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { + * // use k and r + * } MAP_FOREACH_END. + */ +/* Unpacks to, approximately: + * { + * digestmap_iter_t *k_iter; + * for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter); + * k_iter = digestmap_iter_next(m, k_iter)) { + * const char *k; + * void *r_voidp; + * routerinfo_t *r; + * digestmap_iter_get(k_iter, &k, &r_voidp); + * r = r_voidp; + * // use k and r + * } + * } + */ +#define MAP_FOREACH(prefix, map, keytype, keyvar, valtype, valvar) \ + STMT_BEGIN \ + prefix##iter_t *keyvar##_iter; \ + for (keyvar##_iter = prefix##iter_init(map); \ + !prefix##iter_done(keyvar##_iter); \ + keyvar##_iter = prefix##iter_next(map, keyvar##_iter)) { \ + keytype keyvar; \ + void *valvar##_voidp; \ + valtype valvar; \ + prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ + valvar = valvar##_voidp; + +/** As MAP_FOREACH, except allows members to be removed from the map + * during the iteration via MAP_DEL_CURRENT. Example use: + * + * Example use: + * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { + * if (is_very_old(r)) + * MAP_DEL_CURRENT(k); + * } MAP_FOREACH_END. + **/ +/* Unpacks to, approximately: + * { + * digestmap_iter_t *k_iter; + * int k_del=0; + * for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter); + * k_iter = k_del ? digestmap_iter_next(m, k_iter) + * : digestmap_iter_next_rmv(m, k_iter)) { + * const char *k; + * void *r_voidp; + * routerinfo_t *r; + * k_del=0; + * digestmap_iter_get(k_iter, &k, &r_voidp); + * r = r_voidp; + * if (is_very_old(r)) { + * k_del = 1; + * } + * } + * } + */ +#define MAP_FOREACH_MODIFY(prefix, map, keytype, keyvar, valtype, valvar) \ + STMT_BEGIN \ + prefix##iter_t *keyvar##_iter; \ + int keyvar##_del=0; \ + for (keyvar##_iter = prefix##iter_init(map); \ + !prefix##iter_done(keyvar##_iter); \ + keyvar##_iter = keyvar##_del ? \ + prefix##iter_next_rmv(map, keyvar##_iter) : \ + prefix##iter_next(map, keyvar##_iter)) { \ + keytype keyvar; \ + void *valvar##_voidp; \ + valtype valvar; \ + keyvar##_del=0; \ + prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ + valvar = valvar##_voidp; + +/** Used with MAP_FOREACH_MODIFY to remove the currently-iterated-upon + * member of the map. */ +#define MAP_DEL_CURRENT(keyvar) \ + STMT_BEGIN \ + keyvar##_del = 1; \ + STMT_END + +/** Used to end a MAP_FOREACH() block. */ +#define MAP_FOREACH_END } STMT_END ; + +/** As MAP_FOREACH, but does not require declaration of prefix or keytype. + * Example use: + * DIGESTMAP_FOREACH(m, k, routerinfo_t *, r) { + * // use k and r + * } DIGESTMAP_FOREACH_END. + */ +#define DIGESTMAP_FOREACH(map, keyvar, valtype, valvar) \ + MAP_FOREACH(digestmap_, map, const char *, keyvar, valtype, valvar) + +/** As MAP_FOREACH_MODIFY, but does not require declaration of prefix or + * keytype. + * Example use: + * DIGESTMAP_FOREACH_MODIFY(m, k, routerinfo_t *, r) { + * if (is_very_old(r)) + * MAP_DEL_CURRENT(k); + * } DIGESTMAP_FOREACH_END. + */ +#define DIGESTMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ + MAP_FOREACH_MODIFY(digestmap_, map, const char *, keyvar, valtype, valvar) +/** Used to end a DIGESTMAP_FOREACH() block. */ +#define DIGESTMAP_FOREACH_END MAP_FOREACH_END + +#define DIGEST256MAP_FOREACH(map, keyvar, valtype, valvar) \ + MAP_FOREACH(digest256map_, map, const uint8_t *, keyvar, valtype, valvar) +#define DIGEST256MAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ + MAP_FOREACH_MODIFY(digest256map_, map, const uint8_t *, \ + keyvar, valtype, valvar) +#define DIGEST256MAP_FOREACH_END MAP_FOREACH_END + +#define STRMAP_FOREACH(map, keyvar, valtype, valvar) \ + MAP_FOREACH(strmap_, map, const char *, keyvar, valtype, valvar) +#define STRMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ + MAP_FOREACH_MODIFY(strmap_, map, const char *, keyvar, valtype, valvar) +#define STRMAP_FOREACH_END MAP_FOREACH_END + +void* strmap_set_lc(strmap_t *map, const char *key, void *val); +void* strmap_get_lc(const strmap_t *map, const char *key); +void* strmap_remove_lc(strmap_t *map, const char *key); + +#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, maptype, valtype) \ + typedef struct maptype maptype; \ + typedef struct prefix##iter_t *prefix##iter_t; \ + ATTR_UNUSED static inline maptype* \ + prefix##new(void) \ + { \ + return (maptype*)digestmap_new(); \ + } \ + ATTR_UNUSED static inline digestmap_t* \ + prefix##to_digestmap(maptype *map) \ + { \ + return (digestmap_t*)map; \ + } \ + ATTR_UNUSED static inline valtype* \ + prefix##get(maptype *map, const char *key) \ + { \ + return (valtype*)digestmap_get((digestmap_t*)map, key); \ + } \ + ATTR_UNUSED static inline valtype* \ + prefix##set(maptype *map, const char *key, valtype *val) \ + { \ + return (valtype*)digestmap_set((digestmap_t*)map, key, val); \ + } \ + ATTR_UNUSED static inline valtype* \ + prefix##remove(maptype *map, const char *key) \ + { \ + return (valtype*)digestmap_remove((digestmap_t*)map, key); \ + } \ + ATTR_UNUSED static inline void \ + prefix##f##ree_(maptype *map, void (*free_val)(void*)) \ + { \ + digestmap_free_((digestmap_t*)map, free_val); \ + } \ + ATTR_UNUSED static inline int \ + prefix##isempty(maptype *map) \ + { \ + return digestmap_isempty((digestmap_t*)map); \ + } \ + ATTR_UNUSED static inline int \ + prefix##size(maptype *map) \ + { \ + return digestmap_size((digestmap_t*)map); \ + } \ + ATTR_UNUSED static inline \ + prefix##iter_t *prefix##iter_init(maptype *map) \ + { \ + return (prefix##iter_t*) digestmap_iter_init((digestmap_t*)map); \ + } \ + ATTR_UNUSED static inline \ + prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter) \ + { \ + return (prefix##iter_t*) digestmap_iter_next( \ + (digestmap_t*)map, (digestmap_iter_t*)iter); \ + } \ + ATTR_UNUSED static inline prefix##iter_t* \ + prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter) \ + { \ + return (prefix##iter_t*) digestmap_iter_next_rmv( \ + (digestmap_t*)map, (digestmap_iter_t*)iter); \ + } \ + ATTR_UNUSED static inline void \ + prefix##iter_get(prefix##iter_t *iter, \ + const char **keyp, \ + valtype **valp) \ + { \ + void *v; \ + digestmap_iter_get((digestmap_iter_t*) iter, keyp, &v); \ + *valp = v; \ + } \ + ATTR_UNUSED static inline int \ + prefix##iter_done(prefix##iter_t *iter) \ + { \ + return digestmap_iter_done((digestmap_iter_t*)iter); \ + } + +#endif /* !defined(TOR_CONTAINER_H) */ diff --git a/src/lib/container/order.c b/src/lib/container/order.c new file mode 100644 index 0000000000..1efef2c734 --- /dev/null +++ b/src/lib/container/order.c @@ -0,0 +1,48 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file order.c + * \brief Functions for finding the n'th element of an array. + **/ + +#include <stdlib.h> + +#include "lib/container/order.h" +#include "lib/log/util_bug.h" + +/** Declare a function called <b>funcname</b> that acts as a find_nth_FOO + * function for an array of type <b>elt_t</b>*. + * + * NOTE: The implementation kind of sucks: It's O(n log n), whereas finding + * the kth element of an n-element list can be done in O(n). Then again, this + * implementation is not in critical path, and it is obviously correct. */ +#define IMPLEMENT_ORDER_FUNC(funcname, elt_t) \ + static int \ + _cmp_ ## elt_t(const void *_a, const void *_b) \ + { \ + const elt_t *a = _a, *b = _b; \ + if (*a<*b) \ + return -1; \ + else if (*a>*b) \ + return 1; \ + else \ + return 0; \ + } \ + elt_t \ + funcname(elt_t *array, int n_elements, int nth) \ + { \ + tor_assert(nth >= 0); \ + tor_assert(nth < n_elements); \ + qsort(array, n_elements, sizeof(elt_t), _cmp_ ##elt_t); \ + return array[nth]; \ + } + +IMPLEMENT_ORDER_FUNC(find_nth_int, int) +IMPLEMENT_ORDER_FUNC(find_nth_time, time_t) +IMPLEMENT_ORDER_FUNC(find_nth_double, double) +IMPLEMENT_ORDER_FUNC(find_nth_uint32, uint32_t) +IMPLEMENT_ORDER_FUNC(find_nth_int32, int32_t) +IMPLEMENT_ORDER_FUNC(find_nth_long, long) diff --git a/src/lib/container/order.h b/src/lib/container/order.h new file mode 100644 index 0000000000..bd23750d54 --- /dev/null +++ b/src/lib/container/order.h @@ -0,0 +1,54 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_ORDER_H +#define TOR_ORDER_H + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" + +/* These functions, given an <b>array</b> of <b>n_elements</b>, return the + * <b>nth</b> lowest element. <b>nth</b>=0 gives the lowest element; + * <b>n_elements</b>-1 gives the highest; and (<b>n_elements</b>-1) / 2 gives + * the median. As a side effect, the elements of <b>array</b> are sorted. */ +int find_nth_int(int *array, int n_elements, int nth); +time_t find_nth_time(time_t *array, int n_elements, int nth); +double find_nth_double(double *array, int n_elements, int nth); +int32_t find_nth_int32(int32_t *array, int n_elements, int nth); +uint32_t find_nth_uint32(uint32_t *array, int n_elements, int nth); +long find_nth_long(long *array, int n_elements, int nth); +static inline int +median_int(int *array, int n_elements) +{ + return find_nth_int(array, n_elements, (n_elements-1)/2); +} +static inline time_t +median_time(time_t *array, int n_elements) +{ + return find_nth_time(array, n_elements, (n_elements-1)/2); +} +static inline double +median_double(double *array, int n_elements) +{ + return find_nth_double(array, n_elements, (n_elements-1)/2); +} +static inline uint32_t +median_uint32(uint32_t *array, int n_elements) +{ + return find_nth_uint32(array, n_elements, (n_elements-1)/2); +} +static inline int32_t +median_int32(int32_t *array, int n_elements) +{ + return find_nth_int32(array, n_elements, (n_elements-1)/2); +} + +static inline uint32_t +third_quartile_uint32(uint32_t *array, int n_elements) +{ + return find_nth_uint32(array, n_elements, (n_elements*3)/4); +} + +#endif /* !defined(TOR_CONTAINER_H) */ diff --git a/src/lib/container/smartlist.c b/src/lib/container/smartlist.c new file mode 100644 index 0000000000..9025cab9f6 --- /dev/null +++ b/src/lib/container/smartlist.c @@ -0,0 +1,832 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file container.c + * \brief Implements a smartlist (a resizable array) along + * with helper functions to use smartlists. + **/ + +#include "lib/container/smartlist.h" +#include "lib/err/torerr.h" +#include "lib/malloc/util_malloc.h" +#include "lib/defs/digest_sizes.h" +#include "lib/ctime/di_ops.h" +#include "lib/string/compat_ctype.h" +#include "lib/string/util_string.h" +#include "lib/string/printf.h" + +#include "lib/log/util_bug.h" + +#include <stdlib.h> +#include <string.h> + +/** Append the string produced by tor_asprintf(<b>pattern</b>, <b>...</b>) + * to <b>sl</b>. */ +void +smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...) +{ + va_list ap; + va_start(ap, pattern); + smartlist_add_vasprintf(sl, pattern, ap); + va_end(ap); +} + +/** va_list-based backend of smartlist_add_asprintf. */ +void +smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern, + va_list args) +{ + char *str = NULL; + + tor_vasprintf(&str, pattern, args); + tor_assert(str != NULL); + + smartlist_add(sl, str); +} + +/** Reverse the order of the items in <b>sl</b>. */ +void +smartlist_reverse(smartlist_t *sl) +{ + int i, j; + void *tmp; + tor_assert(sl); + for (i = 0, j = sl->num_used-1; i < j; ++i, --j) { + tmp = sl->list[i]; + sl->list[i] = sl->list[j]; + sl->list[j] = tmp; + } +} + +/** If there are any strings in sl equal to element, remove and free them. + * Does not preserve order. */ +void +smartlist_string_remove(smartlist_t *sl, const char *element) +{ + int i; + tor_assert(sl); + tor_assert(element); + for (i = 0; i < sl->num_used; ++i) { + if (!strcmp(element, sl->list[i])) { + tor_free(sl->list[i]); + sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ + i--; /* so we process the new i'th element */ + sl->list[sl->num_used] = NULL; + } + } +} + +/** Return true iff <b>sl</b> has some element E such that + * !strcmp(E,<b>element</b>) + */ +int +smartlist_contains_string(const smartlist_t *sl, const char *element) +{ + int i; + if (!sl) return 0; + for (i=0; i < sl->num_used; i++) + if (strcmp((const char*)sl->list[i],element)==0) + return 1; + return 0; +} + +/** If <b>element</b> is equal to an element of <b>sl</b>, return that + * element's index. Otherwise, return -1. */ +int +smartlist_string_pos(const smartlist_t *sl, const char *element) +{ + int i; + if (!sl) return -1; + for (i=0; i < sl->num_used; i++) + if (strcmp((const char*)sl->list[i],element)==0) + return i; + return -1; +} + +/** If <b>element</b> is the same pointer as an element of <b>sl</b>, return + * that element's index. Otherwise, return -1. */ +int +smartlist_pos(const smartlist_t *sl, const void *element) +{ + int i; + if (!sl) return -1; + for (i=0; i < sl->num_used; i++) + if (element == sl->list[i]) + return i; + return -1; +} + +/** Return true iff <b>sl</b> has some element E such that + * !strcasecmp(E,<b>element</b>) + */ +int +smartlist_contains_string_case(const smartlist_t *sl, const char *element) +{ + int i; + if (!sl) return 0; + for (i=0; i < sl->num_used; i++) + if (strcasecmp((const char*)sl->list[i],element)==0) + return 1; + return 0; +} + +/** Return true iff <b>sl</b> has some element E such that E is equal + * to the decimal encoding of <b>num</b>. + */ +int +smartlist_contains_int_as_string(const smartlist_t *sl, int num) +{ + char buf[32]; /* long enough for 64-bit int, and then some. */ + tor_snprintf(buf,sizeof(buf),"%d", num); + return smartlist_contains_string(sl, buf); +} + +/** Return true iff the two lists contain the same strings in the same + * order, or if they are both NULL. */ +int +smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2) +{ + if (sl1 == NULL) + return sl2 == NULL; + if (sl2 == NULL) + return 0; + if (smartlist_len(sl1) != smartlist_len(sl2)) + return 0; + SMARTLIST_FOREACH(sl1, const char *, cp1, { + const char *cp2 = smartlist_get(sl2, cp1_sl_idx); + if (strcmp(cp1, cp2)) + return 0; + }); + return 1; +} + +/** Return true iff the two lists contain the same int pointer values in + * the same order, or if they are both NULL. */ +int +smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2) +{ + if (sl1 == NULL) + return sl2 == NULL; + if (sl2 == NULL) + return 0; + if (smartlist_len(sl1) != smartlist_len(sl2)) + return 0; + SMARTLIST_FOREACH(sl1, int *, cp1, { + int *cp2 = smartlist_get(sl2, cp1_sl_idx); + if (*cp1 != *cp2) + return 0; + }); + return 1; +} + +/** Return true iff <b>sl</b> has some element E such that + * tor_memeq(E,<b>element</b>,DIGEST_LEN) + */ +int +smartlist_contains_digest(const smartlist_t *sl, const char *element) +{ + int i; + if (!sl) return 0; + for (i=0; i < sl->num_used; i++) + if (tor_memeq((const char*)sl->list[i],element,DIGEST_LEN)) + return 1; + return 0; +} + +/** Return true iff some element E of sl2 has smartlist_contains(sl1,E). + */ +int +smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2) +{ + int i; + for (i=0; i < sl2->num_used; i++) + if (smartlist_contains(sl1, sl2->list[i])) + return 1; + return 0; +} + +/** Remove every element E of sl1 such that !smartlist_contains(sl2,E). + * Does not preserve the order of sl1. + */ +void +smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2) +{ + int i; + for (i=0; i < sl1->num_used; i++) + if (!smartlist_contains(sl2, sl1->list[i])) { + sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */ + i--; /* so we process the new i'th element */ + sl1->list[sl1->num_used] = NULL; + } +} + +/** Remove every element E of sl1 such that smartlist_contains(sl2,E). + * Does not preserve the order of sl1. + */ +void +smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2) +{ + int i; + for (i=0; i < sl2->num_used; i++) + smartlist_remove(sl1, sl2->list[i]); +} + +/** Allocate and return a new string containing the concatenation of + * the elements of <b>sl</b>, in order, separated by <b>join</b>. If + * <b>terminate</b> is true, also terminate the string with <b>join</b>. + * If <b>len_out</b> is not NULL, set <b>len_out</b> to the length of + * the returned string. Requires that every element of <b>sl</b> is + * NUL-terminated string. + */ +char * +smartlist_join_strings(smartlist_t *sl, const char *join, + int terminate, size_t *len_out) +{ + return smartlist_join_strings2(sl,join,strlen(join),terminate,len_out); +} + +/** As smartlist_join_strings, but instead of separating/terminated with a + * NUL-terminated string <b>join</b>, uses the <b>join_len</b>-byte sequence + * at <b>join</b>. (Useful for generating a sequence of NUL-terminated + * strings.) + */ +char * +smartlist_join_strings2(smartlist_t *sl, const char *join, + size_t join_len, int terminate, size_t *len_out) +{ + int i; + size_t n = 0; + char *r = NULL, *dst, *src; + + tor_assert(sl); + tor_assert(join); + + if (terminate) + n = join_len; + + for (i = 0; i < sl->num_used; ++i) { + n += strlen(sl->list[i]); + if (i+1 < sl->num_used) /* avoid double-counting the last one */ + n += join_len; + } + dst = r = tor_malloc(n+1); + for (i = 0; i < sl->num_used; ) { + for (src = sl->list[i]; *src; ) + *dst++ = *src++; + if (++i < sl->num_used) { + memcpy(dst, join, join_len); + dst += join_len; + } + } + if (terminate) { + memcpy(dst, join, join_len); + dst += join_len; + } + *dst = '\0'; + + if (len_out) + *len_out = dst-r; + return r; +} + +/** Sort the members of <b>sl</b> into an order defined by + * the ordering function <b>compare</b>, which returns less then 0 if a + * precedes b, greater than 0 if b precedes a, and 0 if a 'equals' b. + */ +void +smartlist_sort(smartlist_t *sl, int (*compare)(const void **a, const void **b)) +{ + if (!sl->num_used) + return; + qsort(sl->list, sl->num_used, sizeof(void*), + (int (*)(const void *,const void*))compare); +} + +/** Given a smartlist <b>sl</b> sorted with the function <b>compare</b>, + * return the most frequent member in the list. Break ties in favor of + * later elements. If the list is empty, return NULL. If count_out is + * non-null, set it to the count of the most frequent member. + */ +void * +smartlist_get_most_frequent_(const smartlist_t *sl, + int (*compare)(const void **a, const void **b), + int *count_out) +{ + const void *most_frequent = NULL; + int most_frequent_count = 0; + + const void *cur = NULL; + int i, count=0; + + if (!sl->num_used) { + if (count_out) + *count_out = 0; + return NULL; + } + for (i = 0; i < sl->num_used; ++i) { + const void *item = sl->list[i]; + if (cur && 0 == compare(&cur, &item)) { + ++count; + } else { + if (cur && count >= most_frequent_count) { + most_frequent = cur; + most_frequent_count = count; + } + cur = item; + count = 1; + } + } + if (cur && count >= most_frequent_count) { + most_frequent = cur; + most_frequent_count = count; + } + if (count_out) + *count_out = most_frequent_count; + return (void*)most_frequent; +} + +/** Given a sorted smartlist <b>sl</b> and the comparison function used to + * sort it, remove all duplicate members. If free_fn is provided, calls + * free_fn on each duplicate. Otherwise, just removes them. Preserves order. + */ +void +smartlist_uniq(smartlist_t *sl, + int (*compare)(const void **a, const void **b), + void (*free_fn)(void *a)) +{ + int i; + for (i=1; i < sl->num_used; ++i) { + if (compare((const void **)&(sl->list[i-1]), + (const void **)&(sl->list[i])) == 0) { + if (free_fn) + free_fn(sl->list[i]); + smartlist_del_keeporder(sl, i--); + } + } +} + +/** Assuming the members of <b>sl</b> are in order, return a pointer to the + * member that matches <b>key</b>. Ordering and matching are defined by a + * <b>compare</b> function that returns 0 on a match; less than 0 if key is + * less than member, and greater than 0 if key is greater then member. + */ +void * +smartlist_bsearch(smartlist_t *sl, const void *key, + int (*compare)(const void *key, const void **member)) +{ + int found, idx; + idx = smartlist_bsearch_idx(sl, key, compare, &found); + return found ? smartlist_get(sl, idx) : NULL; +} + +/** Assuming the members of <b>sl</b> are in order, return the index of the + * member that matches <b>key</b>. If no member matches, return the index of + * the first member greater than <b>key</b>, or smartlist_len(sl) if no member + * is greater than <b>key</b>. Set <b>found_out</b> to true on a match, to + * false otherwise. Ordering and matching are defined by a <b>compare</b> + * function that returns 0 on a match; less than 0 if key is less than member, + * and greater than 0 if key is greater then member. + */ +int +smartlist_bsearch_idx(const smartlist_t *sl, const void *key, + int (*compare)(const void *key, const void **member), + int *found_out) +{ + int hi, lo, cmp, mid, len, diff; + + tor_assert(sl); + tor_assert(compare); + tor_assert(found_out); + + len = smartlist_len(sl); + + /* Check for the trivial case of a zero-length list */ + if (len == 0) { + *found_out = 0; + /* We already know smartlist_len(sl) is 0 in this case */ + return 0; + } + + /* Okay, we have a real search to do */ + tor_assert(len > 0); + lo = 0; + hi = len - 1; + + /* + * These invariants are always true: + * + * For all i such that 0 <= i < lo, sl[i] < key + * For all i such that hi < i <= len, sl[i] > key + */ + + while (lo <= hi) { + diff = hi - lo; + /* + * We want mid = (lo + hi) / 2, but that could lead to overflow, so + * instead diff = hi - lo (non-negative because of loop condition), and + * then hi = lo + diff, mid = (lo + lo + diff) / 2 = lo + (diff / 2). + */ + mid = lo + (diff / 2); + cmp = compare(key, (const void**) &(sl->list[mid])); + if (cmp == 0) { + /* sl[mid] == key; we found it */ + *found_out = 1; + return mid; + } else if (cmp > 0) { + /* + * key > sl[mid] and an index i such that sl[i] == key must + * have i > mid if it exists. + */ + + /* + * Since lo <= mid <= hi, hi can only decrease on each iteration (by + * being set to mid - 1) and hi is initially len - 1, mid < len should + * always hold, and this is not symmetric with the left end of list + * mid > 0 test below. A key greater than the right end of the list + * should eventually lead to lo == hi == mid == len - 1, and then + * we set lo to len below and fall out to the same exit we hit for + * a key in the middle of the list but not matching. Thus, we just + * assert for consistency here rather than handle a mid == len case. + */ + tor_assert(mid < len); + /* Move lo to the element immediately after sl[mid] */ + lo = mid + 1; + } else { + /* This should always be true in this case */ + tor_assert(cmp < 0); + + /* + * key < sl[mid] and an index i such that sl[i] == key must + * have i < mid if it exists. + */ + + if (mid > 0) { + /* Normal case, move hi to the element immediately before sl[mid] */ + hi = mid - 1; + } else { + /* These should always be true in this case */ + tor_assert(mid == lo); + tor_assert(mid == 0); + /* + * We were at the beginning of the list and concluded that every + * element e compares e > key. + */ + *found_out = 0; + return 0; + } + } + } + + /* + * lo > hi; we have no element matching key but we have elements falling + * on both sides of it. The lo index points to the first element > key. + */ + tor_assert(lo == hi + 1); /* All other cases should have been handled */ + tor_assert(lo >= 0); + tor_assert(lo <= len); + tor_assert(hi >= 0); + tor_assert(hi <= len); + + if (lo < len) { + cmp = compare(key, (const void **) &(sl->list[lo])); + tor_assert(cmp < 0); + } else { + cmp = compare(key, (const void **) &(sl->list[len-1])); + tor_assert(cmp > 0); + } + + *found_out = 0; + return lo; +} + +/** Helper: compare two const char **s. */ +static int +compare_string_ptrs_(const void **_a, const void **_b) +{ + return strcmp((const char*)*_a, (const char*)*_b); +} + +/** Sort a smartlist <b>sl</b> containing strings into lexically ascending + * order. */ +void +smartlist_sort_strings(smartlist_t *sl) +{ + smartlist_sort(sl, compare_string_ptrs_); +} + +/** Return the most frequent string in the sorted list <b>sl</b> */ +const char * +smartlist_get_most_frequent_string(smartlist_t *sl) +{ + return smartlist_get_most_frequent(sl, compare_string_ptrs_); +} + +/** Return the most frequent string in the sorted list <b>sl</b>. + * If <b>count_out</b> is provided, set <b>count_out</b> to the + * number of times that string appears. + */ +const char * +smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out) +{ + return smartlist_get_most_frequent_(sl, compare_string_ptrs_, count_out); +} + +/** Remove duplicate strings from a sorted list, and free them with tor_free(). + */ +void +smartlist_uniq_strings(smartlist_t *sl) +{ + smartlist_uniq(sl, compare_string_ptrs_, tor_free_); +} + +/** Helper: compare two pointers. */ +static int +compare_ptrs_(const void **_a, const void **_b) +{ + const void *a = *_a, *b = *_b; + if (a<b) + return -1; + else if (a==b) + return 0; + else + return 1; +} + +/** Sort <b>sl</b> in ascending order of the pointers it contains. */ +void +smartlist_sort_pointers(smartlist_t *sl) +{ + smartlist_sort(sl, compare_ptrs_); +} + +/* Heap-based priority queue implementation for O(lg N) insert and remove. + * Recall that the heap property is that, for every index I, h[I] < + * H[LEFT_CHILD[I]] and h[I] < H[RIGHT_CHILD[I]]. + * + * For us to remove items other than the topmost item, each item must store + * its own index within the heap. When calling the pqueue functions, tell + * them about the offset of the field that stores the index within the item. + * + * Example: + * + * typedef struct timer_t { + * struct timeval tv; + * int heap_index; + * } timer_t; + * + * static int compare(const void *p1, const void *p2) { + * const timer_t *t1 = p1, *t2 = p2; + * if (t1->tv.tv_sec < t2->tv.tv_sec) { + * return -1; + * } else if (t1->tv.tv_sec > t2->tv.tv_sec) { + * return 1; + * } else { + * return t1->tv.tv_usec - t2->tv_usec; + * } + * } + * + * void timer_heap_insert(smartlist_t *heap, timer_t *timer) { + * smartlist_pqueue_add(heap, compare, offsetof(timer_t, heap_index), + * timer); + * } + * + * void timer_heap_pop(smartlist_t *heap) { + * return smartlist_pqueue_pop(heap, compare, + * offsetof(timer_t, heap_index)); + * } + */ + +/** @{ */ +/** Functions to manipulate heap indices to find a node's parent and children. + * + * For a 1-indexed array, we would use LEFT_CHILD[x] = 2*x and RIGHT_CHILD[x] + * = 2*x + 1. But this is C, so we have to adjust a little. */ + +/* MAX_PARENT_IDX is the largest IDX in the smartlist which might have + * children whose indices fit inside an int. + * LEFT_CHILD(MAX_PARENT_IDX) == INT_MAX-2; + * RIGHT_CHILD(MAX_PARENT_IDX) == INT_MAX-1; + * LEFT_CHILD(MAX_PARENT_IDX + 1) == INT_MAX // impossible, see max list size. + */ +#define MAX_PARENT_IDX ((INT_MAX - 2) / 2) +/* If this is true, then i is small enough to potentially have children + * in the smartlist, and it is save to use LEFT_CHILD/RIGHT_CHILD on it. */ +#define IDX_MAY_HAVE_CHILDREN(i) ((i) <= MAX_PARENT_IDX) +#define LEFT_CHILD(i) ( 2*(i) + 1 ) +#define RIGHT_CHILD(i) ( 2*(i) + 2 ) +#define PARENT(i) ( ((i)-1) / 2 ) +/** }@ */ + +/** @{ */ +/** Helper macros for heaps: Given a local variable <b>idx_field_offset</b> + * set to the offset of an integer index within the heap element structure, + * IDX_OF_ITEM(p) gives you the index of p, and IDXP(p) gives you a pointer to + * where p's index is stored. Given additionally a local smartlist <b>sl</b>, + * UPDATE_IDX(i) sets the index of the element at <b>i</b> to the correct + * value (that is, to <b>i</b>). + */ +#define IDXP(p) ((int*)STRUCT_VAR_P(p, idx_field_offset)) + +#define UPDATE_IDX(i) do { \ + void *updated = sl->list[i]; \ + *IDXP(updated) = i; \ + } while (0) + +#define IDX_OF_ITEM(p) (*IDXP(p)) +/** @} */ + +/** Helper. <b>sl</b> may have at most one violation of the heap property: + * the item at <b>idx</b> may be greater than one or both of its children. + * Restore the heap property. */ +static inline void +smartlist_heapify(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + int idx) +{ + while (1) { + if (! IDX_MAY_HAVE_CHILDREN(idx)) { + /* idx is so large that it cannot have any children, since doing so + * would mean the smartlist was over-capacity. Therefore it cannot + * violate the heap property by being greater than a child (since it + * doesn't have any). */ + return; + } + + int left_idx = LEFT_CHILD(idx); + int best_idx; + + if (left_idx >= sl->num_used) + return; + if (compare(sl->list[idx],sl->list[left_idx]) < 0) + best_idx = idx; + else + best_idx = left_idx; + if (left_idx+1 < sl->num_used && + compare(sl->list[left_idx+1],sl->list[best_idx]) < 0) + best_idx = left_idx + 1; + + if (best_idx == idx) { + return; + } else { + void *tmp = sl->list[idx]; + sl->list[idx] = sl->list[best_idx]; + sl->list[best_idx] = tmp; + UPDATE_IDX(idx); + UPDATE_IDX(best_idx); + + idx = best_idx; + } + } +} + +/** Insert <b>item</b> into the heap stored in <b>sl</b>, where order is + * determined by <b>compare</b> and the offset of the item in the heap is + * stored in an int-typed field at position <b>idx_field_offset</b> within + * item. + */ +void +smartlist_pqueue_add(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + void *item) +{ + int idx; + smartlist_add(sl,item); + UPDATE_IDX(sl->num_used-1); + + for (idx = sl->num_used - 1; idx; ) { + int parent = PARENT(idx); + if (compare(sl->list[idx], sl->list[parent]) < 0) { + void *tmp = sl->list[parent]; + sl->list[parent] = sl->list[idx]; + sl->list[idx] = tmp; + UPDATE_IDX(parent); + UPDATE_IDX(idx); + idx = parent; + } else { + return; + } + } +} + +/** Remove and return the top-priority item from the heap stored in <b>sl</b>, + * where order is determined by <b>compare</b> and the item's position is + * stored at position <b>idx_field_offset</b> within the item. <b>sl</b> must + * not be empty. */ +void * +smartlist_pqueue_pop(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset) +{ + void *top; + tor_assert(sl->num_used); + + top = sl->list[0]; + *IDXP(top)=-1; + if (--sl->num_used) { + sl->list[0] = sl->list[sl->num_used]; + sl->list[sl->num_used] = NULL; + UPDATE_IDX(0); + smartlist_heapify(sl, compare, idx_field_offset, 0); + } + sl->list[sl->num_used] = NULL; + return top; +} + +/** Remove the item <b>item</b> from the heap stored in <b>sl</b>, + * where order is determined by <b>compare</b> and the item's position is + * stored at position <b>idx_field_offset</b> within the item. <b>sl</b> must + * not be empty. */ +void +smartlist_pqueue_remove(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + void *item) +{ + int idx = IDX_OF_ITEM(item); + tor_assert(idx >= 0); + tor_assert(sl->list[idx] == item); + --sl->num_used; + *IDXP(item) = -1; + if (idx == sl->num_used) { + sl->list[sl->num_used] = NULL; + return; + } else { + sl->list[idx] = sl->list[sl->num_used]; + sl->list[sl->num_used] = NULL; + UPDATE_IDX(idx); + smartlist_heapify(sl, compare, idx_field_offset, idx); + } +} + +/** Assert that the heap property is correctly maintained by the heap stored + * in <b>sl</b>, where order is determined by <b>compare</b>. */ +void +smartlist_pqueue_assert_ok(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset) +{ + int i; + for (i = sl->num_used - 1; i >= 0; --i) { + if (i>0) + tor_assert(compare(sl->list[PARENT(i)], sl->list[i]) <= 0); + tor_assert(IDX_OF_ITEM(sl->list[i]) == i); + } +} + +/** Helper: compare two DIGEST_LEN digests. */ +static int +compare_digests_(const void **_a, const void **_b) +{ + return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST_LEN); +} + +/** Sort the list of DIGEST_LEN-byte digests into ascending order. */ +void +smartlist_sort_digests(smartlist_t *sl) +{ + smartlist_sort(sl, compare_digests_); +} + +/** Remove duplicate digests from a sorted list, and free them with tor_free(). + */ +void +smartlist_uniq_digests(smartlist_t *sl) +{ + smartlist_uniq(sl, compare_digests_, tor_free_); +} + +/** Helper: compare two DIGEST256_LEN digests. */ +static int +compare_digests256_(const void **_a, const void **_b) +{ + return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST256_LEN); +} + +/** Sort the list of DIGEST256_LEN-byte digests into ascending order. */ +void +smartlist_sort_digests256(smartlist_t *sl) +{ + smartlist_sort(sl, compare_digests256_); +} + +/** Return the most frequent member of the sorted list of DIGEST256_LEN + * digests in <b>sl</b> */ +const uint8_t * +smartlist_get_most_frequent_digest256(smartlist_t *sl) +{ + return smartlist_get_most_frequent(sl, compare_digests256_); +} + +/** Remove duplicate 256-bit digests from a sorted list, and free them with + * tor_free(). + */ +void +smartlist_uniq_digests256(smartlist_t *sl) +{ + smartlist_uniq(sl, compare_digests256_, tor_free_); +} diff --git a/src/lib/container/smartlist.h b/src/lib/container/smartlist.h new file mode 100644 index 0000000000..76ecbda0a2 --- /dev/null +++ b/src/lib/container/smartlist.h @@ -0,0 +1,159 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SMARTLIST_H +#define TOR_SMARTLIST_H + +#include <stdarg.h> + +#include "lib/smartlist_core/smartlist_core.h" +#include "lib/smartlist_core/smartlist_foreach.h" +#include "lib/smartlist_core/smartlist_split.h" + +void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...) + CHECK_PRINTF(2, 3); +void smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern, + va_list args) + CHECK_PRINTF(2, 0); +void smartlist_reverse(smartlist_t *sl); +void smartlist_string_remove(smartlist_t *sl, const char *element); +int smartlist_contains_string(const smartlist_t *sl, const char *element); +int smartlist_pos(const smartlist_t *sl, const void *element); +int smartlist_string_pos(const smartlist_t *, const char *elt); +int smartlist_contains_string_case(const smartlist_t *sl, const char *element); +int smartlist_contains_int_as_string(const smartlist_t *sl, int num); +int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2); +int smartlist_contains_digest(const smartlist_t *sl, const char *element); +int smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2); +int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2); +void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2); +void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2); + +void smartlist_sort(smartlist_t *sl, + int (*compare)(const void **a, const void **b)); +void *smartlist_get_most_frequent_(const smartlist_t *sl, + int (*compare)(const void **a, const void **b), + int *count_out); +#define smartlist_get_most_frequent(sl, compare) \ + smartlist_get_most_frequent_((sl), (compare), NULL) +void smartlist_uniq(smartlist_t *sl, + int (*compare)(const void **a, const void **b), + void (*free_fn)(void *elt)); + +void smartlist_sort_strings(smartlist_t *sl); +void smartlist_sort_digests(smartlist_t *sl); +void smartlist_sort_digests256(smartlist_t *sl); +void smartlist_sort_pointers(smartlist_t *sl); + +const char *smartlist_get_most_frequent_string(smartlist_t *sl); +const char *smartlist_get_most_frequent_string_(smartlist_t *sl, + int *count_out); +const uint8_t *smartlist_get_most_frequent_digest256(smartlist_t *sl); + +void smartlist_uniq_strings(smartlist_t *sl); +void smartlist_uniq_digests(smartlist_t *sl); +void smartlist_uniq_digests256(smartlist_t *sl); +void *smartlist_bsearch(smartlist_t *sl, const void *key, + int (*compare)(const void *key, const void **member)); +int smartlist_bsearch_idx(const smartlist_t *sl, const void *key, + int (*compare)(const void *key, const void **member), + int *found_out); + +void smartlist_pqueue_add(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + void *item); +void *smartlist_pqueue_pop(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset); +void smartlist_pqueue_remove(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + void *item); +void smartlist_pqueue_assert_ok(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset); + +char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, + size_t *len_out) ATTR_MALLOC; +char *smartlist_join_strings2(smartlist_t *sl, const char *join, + size_t join_len, int terminate, size_t *len_out) + ATTR_MALLOC; + +/* Helper: Given two lists of items, possibly of different types, such that + * both lists are sorted on some common field (as determined by a comparison + * expression <b>cmpexpr</b>), and such that one list (<b>sl1</b>) has no + * duplicates on the common field, loop through the lists in lockstep, and + * execute <b>unmatched_var2</b> on items in var2 that do not appear in + * var1. + * + * WARNING: It isn't safe to add remove elements from either list while the + * loop is in progress. + * + * Example use: + * SMARTLIST_FOREACH_JOIN(routerstatus_list, routerstatus_t *, rs, + * routerinfo_list, routerinfo_t *, ri, + * tor_memcmp(rs->identity_digest, ri->identity_digest, 20), + * log_info(LD_GENERAL,"No match for %s", ri->nickname)) { + * log_info(LD_GENERAL, "%s matches routerstatus %p", ri->nickname, rs); + * } SMARTLIST_FOREACH_JOIN_END(rs, ri); + **/ +/* The example above unpacks (approximately) to: + * int rs_sl_idx = 0, rs_sl_len = smartlist_len(routerstatus_list); + * int ri_sl_idx, ri_sl_len = smartlist_len(routerinfo_list); + * int rs_ri_cmp; + * routerstatus_t *rs; + * routerinfo_t *ri; + * for (; ri_sl_idx < ri_sl_len; ++ri_sl_idx) { + * ri = smartlist_get(routerinfo_list, ri_sl_idx); + * while (rs_sl_idx < rs_sl_len) { + * rs = smartlist_get(routerstatus_list, rs_sl_idx); + * rs_ri_cmp = tor_memcmp(rs->identity_digest, ri->identity_digest, 20); + * if (rs_ri_cmp > 0) { + * break; + * } else if (rs_ri_cmp == 0) { + * goto matched_ri; + * } else { + * ++rs_sl_idx; + * } + * } + * log_info(LD_GENERAL,"No match for %s", ri->nickname); + * continue; + * matched_ri: { + * log_info(LD_GENERAL,"%s matches with routerstatus %p",ri->nickname,rs); + * } + * } + */ +#define SMARTLIST_FOREACH_JOIN(sl1, type1, var1, sl2, type2, var2, \ + cmpexpr, unmatched_var2) \ + STMT_BEGIN \ + int var1 ## _sl_idx = 0, var1 ## _sl_len=(sl1)->num_used; \ + int var2 ## _sl_idx = 0, var2 ## _sl_len=(sl2)->num_used; \ + int var1 ## _ ## var2 ## _cmp; \ + type1 var1; \ + type2 var2; \ + for (; var2##_sl_idx < var2##_sl_len; ++var2##_sl_idx) { \ + var2 = (sl2)->list[var2##_sl_idx]; \ + while (var1##_sl_idx < var1##_sl_len) { \ + var1 = (sl1)->list[var1##_sl_idx]; \ + var1##_##var2##_cmp = (cmpexpr); \ + if (var1##_##var2##_cmp > 0) { \ + break; \ + } else if (var1##_##var2##_cmp == 0) { \ + goto matched_##var2; \ + } else { \ + ++var1##_sl_idx; \ + } \ + } \ + /* Ran out of v1, or no match for var2. */ \ + unmatched_var2; \ + continue; \ + matched_##var2: ; \ + +#define SMARTLIST_FOREACH_JOIN_END(var1, var2) \ + } \ + STMT_END + +#endif /* !defined(TOR_CONTAINER_H) */ diff --git a/src/lib/crypt_ops/.may_include b/src/lib/crypt_ops/.may_include new file mode 100644 index 0000000000..6ca06f590e --- /dev/null +++ b/src/lib/crypt_ops/.may_include @@ -0,0 +1,25 @@ +orconfig.h +lib/arch/*.h +lib/cc/*.h +lib/container/*.h +lib/crypt_ops/*.h +lib/ctime/*.h +lib/defs/*.h +lib/encoding/*.h +lib/fs/*.h +lib/lock/*.h +lib/malloc/*.h +lib/err/*.h +lib/intmath/*.h +lib/sandbox/*.h +lib/string/*.h +lib/testsupport/testsupport.h +lib/thread/*.h +lib/log/*.h + +trunnel/pwbox.h + +keccak-tiny/*.h +ed25519/*.h + +siphash.h diff --git a/src/common/aes.c b/src/lib/crypt_ops/aes.c index 86f3472bfd..a01b1e16b2 100644 --- a/src/common/aes.c +++ b/src/lib/crypt_ops/aes.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,15 +10,17 @@ **/ #include "orconfig.h" +#include "lib/crypt_ops/aes.h" +#include "lib/log/util_bug.h" #ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/ #include <winsock2.h> #include <ws2tcpip.h> #endif -#include "compat_openssl.h" +#include "lib/crypt_ops/compat_openssl.h" #include <openssl/opensslv.h> -#include "crypto_openssl_mgt.h" +#include "lib/crypt_ops/crypto_openssl_mgt.h" #if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0) #error "We require OpenSSL >= 1.0.0" @@ -26,7 +28,6 @@ DISABLE_GCC_WARNING(redundant-decls) -#include <assert.h> #include <stdlib.h> #include <string.h> #include <openssl/aes.h> @@ -36,11 +37,9 @@ DISABLE_GCC_WARNING(redundant-decls) ENABLE_GCC_WARNING(redundant-decls) -#include "compat.h" -#include "aes.h" -#include "util.h" -#include "torlog.h" -#include "di_ops.h" +#include "lib/crypt_ops/aes.h" +#include "lib/log/torlog.h" +#include "lib/ctime/di_ops.h" #ifdef ANDROID /* Android's OpenSSL seems to have removed all of its Engine support. */ @@ -407,4 +406,3 @@ aes_set_iv(aes_cnt_cipher_t *cipher, const uint8_t *iv) } #endif /* defined(USE_EVP_AES_CTR) */ - diff --git a/src/common/aes.h b/src/lib/crypt_ops/aes.h index 0b17cd55a4..a57654159a 100644 --- a/src/common/aes.h +++ b/src/lib/crypt_ops/aes.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Implements a minimal interface to counter-mode AES. */ @@ -13,6 +13,9 @@ * \brief Headers for aes.c */ +#include "lib/cc/torint.h" +#include "lib/malloc/util_malloc.h" + typedef struct aes_cnt_cipher aes_cnt_cipher_t; aes_cnt_cipher_t* aes_new_cipher(const uint8_t *key, const uint8_t *iv, @@ -26,4 +29,3 @@ int evaluate_evp_for_aes(int force_value); int evaluate_ctr_for_aes(void); #endif /* !defined(TOR_AES_H) */ - diff --git a/src/common/compat_openssl.h b/src/lib/crypt_ops/compat_openssl.h index d1481fb46c..317c01134a 100644 --- a/src/common/compat_openssl.h +++ b/src/lib/crypt_ops/compat_openssl.h @@ -1,14 +1,14 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_COMPAT_OPENSSL_H #define TOR_COMPAT_OPENSSL_H #include <openssl/opensslv.h> -#include "crypto_openssl_mgt.h" +#include "lib/crypt_ops/crypto_openssl_mgt.h" /** * \file compat_openssl.h diff --git a/src/lib/crypt_ops/crypto.c b/src/lib/crypt_ops/crypto.c new file mode 100644 index 0000000000..48574016bf --- /dev/null +++ b/src/lib/crypt_ops/crypto.c @@ -0,0 +1,509 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto.c + * \brief Wrapper functions to present a consistent interface to + * public-key and symmetric cryptography operations from OpenSSL and + * other places. + **/ + +#include "orconfig.h" + +#ifdef _WIN32 +#include <winsock2.h> +#include <windows.h> +#include <wincrypt.h> +/* Windows defines this; so does OpenSSL 0.9.8h and later. We don't actually + * use either definition. */ +#undef OCSP_RESPONSE +#endif /* defined(_WIN32) */ + +#define CRYPTO_PRIVATE +#include "lib/crypt_ops/compat_openssl.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_rsa.h" +#include "lib/crypt_ops/crypto_util.h" + +DISABLE_GCC_WARNING(redundant-decls) + +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/engine.h> +#include <openssl/bn.h> +#include <openssl/dh.h> +#include <openssl/conf.h> +#include <openssl/hmac.h> +#include <openssl/ssl.h> + +ENABLE_GCC_WARNING(redundant-decls) + +#if __GNUC__ && GCC_VERSION >= 402 +#if GCC_VERSION >= 406 +#pragma GCC diagnostic pop +#else +#pragma GCC diagnostic warning "-Wredundant-decls" +#endif +#endif /* __GNUC__ && GCC_VERSION >= 402 */ + +#ifdef HAVE_CTYPE_H +#include <ctype.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/cc/torint.h" +#include "lib/crypt_ops/aes.h" +#include "lib/encoding/binascii.h" + +#include "keccak-tiny/keccak-tiny.h" + +#include "siphash.h" + +#include <string.h> + +/** Boolean: has OpenSSL's crypto been initialized? */ +static int crypto_early_initialized_ = 0; + +/** Boolean: has OpenSSL's crypto been initialized? */ +static int crypto_global_initialized_ = 0; + +#ifndef DISABLE_ENGINES +/** Log any OpenSSL engines we're using at NOTICE. */ +static void +log_engine(const char *fn, ENGINE *e) +{ + if (e) { + const char *name, *id; + name = ENGINE_get_name(e); + id = ENGINE_get_id(e); + log_notice(LD_CRYPTO, "Default OpenSSL engine for %s is %s [%s]", + fn, name?name:"?", id?id:"?"); + } else { + log_info(LD_CRYPTO, "Using default implementation for %s", fn); + } +} +#endif /* !defined(DISABLE_ENGINES) */ + +#ifndef DISABLE_ENGINES +/** Try to load an engine in a shared library via fully qualified path. + */ +static ENGINE * +try_load_engine(const char *path, const char *engine) +{ + ENGINE *e = ENGINE_by_id("dynamic"); + if (e) { + if (!ENGINE_ctrl_cmd_string(e, "ID", engine, 0) || + !ENGINE_ctrl_cmd_string(e, "DIR_LOAD", "2", 0) || + !ENGINE_ctrl_cmd_string(e, "DIR_ADD", path, 0) || + !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { + ENGINE_free(e); + e = NULL; + } + } + return e; +} +#endif /* !defined(DISABLE_ENGINES) */ + +static int have_seeded_siphash = 0; + +/** Set up the siphash key if we haven't already done so. */ +int +crypto_init_siphash_key(void) +{ + struct sipkey key; + if (have_seeded_siphash) + return 0; + + crypto_rand((char*) &key, sizeof(key)); + siphash_set_global_key(&key); + have_seeded_siphash = 1; + return 0; +} + +/** Initialize the crypto library. Return 0 on success, -1 on failure. + */ +int +crypto_early_init(void) +{ + if (!crypto_early_initialized_) { + + crypto_early_initialized_ = 1; + +#ifdef OPENSSL_1_1_API + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | + OPENSSL_INIT_LOAD_CRYPTO_STRINGS | + OPENSSL_INIT_ADD_ALL_CIPHERS | + OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); +#else + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); +#endif + + setup_openssl_threading(); + + unsigned long version_num = OpenSSL_version_num(); + const char *version_str = OpenSSL_version(OPENSSL_VERSION); + if (version_num == OPENSSL_VERSION_NUMBER && + !strcmp(version_str, OPENSSL_VERSION_TEXT)) { + log_info(LD_CRYPTO, "OpenSSL version matches version from headers " + "(%lx: %s).", version_num, version_str); + } else { + log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the " + "version we're running with. If you get weird crashes, that " + "might be why. (Compiled with %lx: %s; running with %lx: %s).", + (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT, + version_num, version_str); + } + + crypto_force_rand_ssleay(); + + if (crypto_seed_rng() < 0) + return -1; + if (crypto_init_siphash_key() < 0) + return -1; + + curve25519_init(); + ed25519_init(); + } + return 0; +} + +/** Initialize the crypto library. Return 0 on success, -1 on failure. + */ +int +crypto_global_init(int useAccel, const char *accelName, const char *accelDir) +{ + if (!crypto_global_initialized_) { + if (crypto_early_init() < 0) + return -1; + + crypto_global_initialized_ = 1; + + if (useAccel > 0) { +#ifdef DISABLE_ENGINES + (void)accelName; + (void)accelDir; + log_warn(LD_CRYPTO, "No OpenSSL hardware acceleration support enabled."); +#else + ENGINE *e = NULL; + + log_info(LD_CRYPTO, "Initializing OpenSSL engine support."); + ENGINE_load_builtin_engines(); + ENGINE_register_all_complete(); + + if (accelName) { + if (accelDir) { + log_info(LD_CRYPTO, "Trying to load dynamic OpenSSL engine \"%s\"" + " via path \"%s\".", accelName, accelDir); + e = try_load_engine(accelName, accelDir); + } else { + log_info(LD_CRYPTO, "Initializing dynamic OpenSSL engine \"%s\"" + " acceleration support.", accelName); + e = ENGINE_by_id(accelName); + } + if (!e) { + log_warn(LD_CRYPTO, "Unable to load dynamic OpenSSL engine \"%s\".", + accelName); + } else { + log_info(LD_CRYPTO, "Loaded dynamic OpenSSL engine \"%s\".", + accelName); + } + } + if (e) { + log_info(LD_CRYPTO, "Loaded OpenSSL hardware acceleration engine," + " setting default ciphers."); + ENGINE_set_default(e, ENGINE_METHOD_ALL); + } + /* Log, if available, the intersection of the set of algorithms + used by Tor and the set of algorithms available in the engine */ + log_engine("RSA", ENGINE_get_default_RSA()); + log_engine("DH", ENGINE_get_default_DH()); +#ifdef OPENSSL_1_1_API + log_engine("EC", ENGINE_get_default_EC()); +#else + log_engine("ECDH", ENGINE_get_default_ECDH()); + log_engine("ECDSA", ENGINE_get_default_ECDSA()); +#endif /* defined(OPENSSL_1_1_API) */ + log_engine("RAND", ENGINE_get_default_RAND()); + log_engine("RAND (which we will not use)", ENGINE_get_default_RAND()); + log_engine("SHA1", ENGINE_get_digest_engine(NID_sha1)); + log_engine("3DES-CBC", ENGINE_get_cipher_engine(NID_des_ede3_cbc)); + log_engine("AES-128-ECB", ENGINE_get_cipher_engine(NID_aes_128_ecb)); + log_engine("AES-128-CBC", ENGINE_get_cipher_engine(NID_aes_128_cbc)); +#ifdef NID_aes_128_ctr + log_engine("AES-128-CTR", ENGINE_get_cipher_engine(NID_aes_128_ctr)); +#endif +#ifdef NID_aes_128_gcm + log_engine("AES-128-GCM", ENGINE_get_cipher_engine(NID_aes_128_gcm)); +#endif + log_engine("AES-256-CBC", ENGINE_get_cipher_engine(NID_aes_256_cbc)); +#ifdef NID_aes_256_gcm + log_engine("AES-256-GCM", ENGINE_get_cipher_engine(NID_aes_256_gcm)); +#endif + +#endif /* defined(DISABLE_ENGINES) */ + } else { + log_info(LD_CRYPTO, "NOT using OpenSSL engine support."); + } + + if (crypto_force_rand_ssleay()) { + if (crypto_seed_rng() < 0) + return -1; + } + + evaluate_evp_for_aes(-1); + evaluate_ctr_for_aes(); + } + return 0; +} + +/** Free crypto resources held by this thread. */ +void +crypto_thread_cleanup(void) +{ +#ifndef NEW_THREAD_API + ERR_remove_thread_state(NULL); +#endif +} + +/** Allocate and return a new symmetric cipher using the provided key and iv. + * The key is <b>bits</b> bits long; the IV is CIPHER_IV_LEN bytes. Both + * must be provided. Key length must be 128, 192, or 256 */ +crypto_cipher_t * +crypto_cipher_new_with_iv_and_bits(const uint8_t *key, + const uint8_t *iv, + int bits) +{ + tor_assert(key); + tor_assert(iv); + + return aes_new_cipher((const uint8_t*)key, (const uint8_t*)iv, bits); +} + +/** Allocate and return a new symmetric cipher using the provided key and iv. + * The key is CIPHER_KEY_LEN bytes; the IV is CIPHER_IV_LEN bytes. Both + * must be provided. + */ +crypto_cipher_t * +crypto_cipher_new_with_iv(const char *key, const char *iv) +{ + return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)iv, + 128); +} + +/** Return a new crypto_cipher_t with the provided <b>key</b> and an IV of all + * zero bytes and key length <b>bits</b>. Key length must be 128, 192, or + * 256. */ +crypto_cipher_t * +crypto_cipher_new_with_bits(const char *key, int bits) +{ + char zeroiv[CIPHER_IV_LEN]; + memset(zeroiv, 0, sizeof(zeroiv)); + return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)zeroiv, + bits); +} + +/** Return a new crypto_cipher_t with the provided <b>key</b> (of + * CIPHER_KEY_LEN bytes) and an IV of all zero bytes. */ +crypto_cipher_t * +crypto_cipher_new(const char *key) +{ + return crypto_cipher_new_with_bits(key, 128); +} + +/** Free a symmetric cipher. + */ +void +crypto_cipher_free_(crypto_cipher_t *env) +{ + if (!env) + return; + + aes_cipher_free(env); +} + +/** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces + * every four characters. */ +void +crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in) +{ + int n = 0; + char *end = out+outlen; + tor_assert(outlen < SIZE_T_CEILING); + + while (*in && out<end) { + *out++ = *in++; + if (++n == 4 && *in && out<end) { + n = 0; + *out++ = ' '; + } + } + tor_assert(out<end); + *out = '\0'; +} + +/* symmetric crypto */ + +/** Encrypt <b>fromlen</b> bytes from <b>from</b> using the cipher + * <b>env</b>; on success, store the result to <b>to</b> and return 0. + * Does not check for failure. + */ +int +crypto_cipher_encrypt(crypto_cipher_t *env, char *to, + const char *from, size_t fromlen) +{ + tor_assert(env); + tor_assert(env); + tor_assert(from); + tor_assert(fromlen); + tor_assert(to); + tor_assert(fromlen < SIZE_T_CEILING); + + memcpy(to, from, fromlen); + aes_crypt_inplace(env, to, fromlen); + return 0; +} + +/** Decrypt <b>fromlen</b> bytes from <b>from</b> using the cipher + * <b>env</b>; on success, store the result to <b>to</b> and return 0. + * Does not check for failure. + */ +int +crypto_cipher_decrypt(crypto_cipher_t *env, char *to, + const char *from, size_t fromlen) +{ + tor_assert(env); + tor_assert(from); + tor_assert(to); + tor_assert(fromlen < SIZE_T_CEILING); + + memcpy(to, from, fromlen); + aes_crypt_inplace(env, to, fromlen); + return 0; +} + +/** Encrypt <b>len</b> bytes on <b>from</b> using the cipher in <b>env</b>; + * on success. Does not check for failure. + */ +void +crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *buf, size_t len) +{ + tor_assert(len < SIZE_T_CEILING); + aes_crypt_inplace(env, buf, len); +} + +/** Encrypt <b>fromlen</b> bytes (at least 1) from <b>from</b> with the key in + * <b>key</b> to the buffer in <b>to</b> of length + * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> plus + * CIPHER_IV_LEN bytes for the initialization vector. On success, return the + * number of bytes written, on failure, return -1. + */ +int +crypto_cipher_encrypt_with_iv(const char *key, + char *to, size_t tolen, + const char *from, size_t fromlen) +{ + crypto_cipher_t *cipher; + tor_assert(from); + tor_assert(to); + tor_assert(fromlen < INT_MAX); + + if (fromlen < 1) + return -1; + if (tolen < fromlen + CIPHER_IV_LEN) + return -1; + + char iv[CIPHER_IV_LEN]; + crypto_rand(iv, sizeof(iv)); + cipher = crypto_cipher_new_with_iv(key, iv); + + memcpy(to, iv, CIPHER_IV_LEN); + crypto_cipher_encrypt(cipher, to+CIPHER_IV_LEN, from, fromlen); + crypto_cipher_free(cipher); + memwipe(iv, 0, sizeof(iv)); + return (int)(fromlen + CIPHER_IV_LEN); +} + +/** Decrypt <b>fromlen</b> bytes (at least 1+CIPHER_IV_LEN) from <b>from</b> + * with the key in <b>key</b> to the buffer in <b>to</b> of length + * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> minus + * CIPHER_IV_LEN bytes for the initialization vector. On success, return the + * number of bytes written, on failure, return -1. + */ +int +crypto_cipher_decrypt_with_iv(const char *key, + char *to, size_t tolen, + const char *from, size_t fromlen) +{ + crypto_cipher_t *cipher; + tor_assert(key); + tor_assert(from); + tor_assert(to); + tor_assert(fromlen < INT_MAX); + + if (fromlen <= CIPHER_IV_LEN) + return -1; + if (tolen < fromlen - CIPHER_IV_LEN) + return -1; + + cipher = crypto_cipher_new_with_iv(key, from); + + crypto_cipher_encrypt(cipher, to, from+CIPHER_IV_LEN, fromlen-CIPHER_IV_LEN); + crypto_cipher_free(cipher); + return (int)(fromlen - CIPHER_IV_LEN); +} + +/** @{ */ +/** Uninitialize the crypto library. Return 0 on success. Does not detect + * failure. + */ +int +crypto_global_cleanup(void) +{ +#ifndef OPENSSL_1_1_API + EVP_cleanup(); +#endif +#ifndef NEW_THREAD_API + ERR_remove_thread_state(NULL); +#endif +#ifndef OPENSSL_1_1_API + ERR_free_strings(); +#endif + + crypto_dh_free_all(); + +#ifndef DISABLE_ENGINES +#ifndef OPENSSL_1_1_API + ENGINE_cleanup(); +#endif +#endif + + CONF_modules_unload(1); +#ifndef OPENSSL_1_1_API + CRYPTO_cleanup_all_ex_data(); +#endif + + crypto_openssl_free_all(); + + crypto_early_initialized_ = 0; + crypto_global_initialized_ = 0; + have_seeded_siphash = 0; + siphash_unset_global_key(); + + return 0; +} + +/** @} */ diff --git a/src/common/crypto.h b/src/lib/crypt_ops/crypto.h index c773557310..3a0b330be6 100644 --- a/src/common/crypto.h +++ b/src/lib/crypt_ops/crypto.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -16,10 +16,8 @@ #include "orconfig.h" #include <stdio.h> -#include "torint.h" -#include "compat.h" -#include "util.h" -#include "crypto_rsa.h" +#include "lib/cc/torint.h" +#include "lib/crypt_ops/crypto_rsa.h" /** Length of our symmetric cipher's keys of 128-bit. */ #define CIPHER_KEY_LEN 16 @@ -27,15 +25,12 @@ #define CIPHER_IV_LEN 16 /** Length of our symmetric cipher's keys of 256-bit. */ #define CIPHER256_KEY_LEN 32 -/** Length of our DH keys. */ -#define DH_BYTES (1024/8) /** Length of encoded public key fingerprints, including space; but not * including terminating NUL. */ #define FINGERPRINT_LEN 49 typedef struct aes_cnt_cipher crypto_cipher_t; -typedef struct crypto_dh_t crypto_dh_t; /* global state */ int crypto_init_siphash_key(void); @@ -43,15 +38,11 @@ int crypto_early_init(void) ATTR_WUR; int crypto_global_init(int hardwareAccel, const char *accelName, const char *accelPath) ATTR_WUR; -#ifdef USE_DMALLOC -int crypto_use_tor_alloc_functions(void); -#endif void crypto_thread_cleanup(void); int crypto_global_cleanup(void); /* environment setup */ -void crypto_set_tls_dh_prime(void); crypto_cipher_t *crypto_cipher_new(const char *key); crypto_cipher_t *crypto_cipher_new_with_bits(const char *key, int bits); crypto_cipher_t *crypto_cipher_new_with_iv(const char *key, const char *iv); @@ -78,37 +69,6 @@ int crypto_cipher_decrypt_with_iv(const char *key, char *to, size_t tolen, const char *from, size_t fromlen); -/* Key negotiation */ -#define DH_TYPE_CIRCUIT 1 -#define DH_TYPE_REND 2 -#define DH_TYPE_TLS 3 -crypto_dh_t *crypto_dh_new(int dh_type); -crypto_dh_t *crypto_dh_dup(const crypto_dh_t *dh); -int crypto_dh_get_bytes(crypto_dh_t *dh); -int crypto_dh_generate_public(crypto_dh_t *dh); -int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out, - size_t pubkey_out_len); -ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh, - const char *pubkey, size_t pubkey_len, - char *secret_out, size_t secret_out_len); -void crypto_dh_free_(crypto_dh_t *dh); -#define crypto_dh_free(dh) FREE_AND_NULL(crypto_dh_t, crypto_dh_free_, (dh)) - -int crypto_expand_key_material_TAP(const uint8_t *key_in, - size_t key_in_len, - uint8_t *key_out, size_t key_out_len); -int crypto_expand_key_material_rfc5869_sha256( - const uint8_t *key_in, size_t key_in_len, - const uint8_t *salt_in, size_t salt_in_len, - const uint8_t *info_in, size_t info_in_len, - uint8_t *key_out, size_t key_out_len); - -/* Prototypes for private functions only used by tortls.c, crypto.c, and the - * unit tests. */ -struct dh_st; -struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh); - void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in); #endif /* !defined(TOR_CRYPTO_H) */ - diff --git a/src/common/crypto_curve25519.c b/src/lib/crypt_ops/crypto_curve25519.c index 996d94c6e2..09f492e544 100644 --- a/src/common/crypto_curve25519.c +++ b/src/lib/crypt_ops/crypto_curve25519.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -20,17 +20,19 @@ #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif -#include "container.h" -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_format.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "util.h" -#include "torlog.h" +#include "lib/ctime/di_ops.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" #include "ed25519/donna/ed25519_donna_tor.h" +#include <string.h> + /* ============================== Part 1: wrap a suitable curve25519 implementation as curve25519_impl ============================== */ @@ -356,4 +358,3 @@ curve25519_init(void) { pick_curve25519_basepoint_impl(); } - diff --git a/src/common/crypto_curve25519.h b/src/lib/crypt_ops/crypto_curve25519.h index 4834fa0836..2e614848e4 100644 --- a/src/common/crypto_curve25519.h +++ b/src/lib/crypt_ops/crypto_curve25519.h @@ -1,13 +1,13 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CRYPTO_CURVE25519_H #define TOR_CRYPTO_CURVE25519_H -#include "testsupport.h" -#include "torint.h" -#include "crypto_digest.h" -#include "crypto_openssl_mgt.h" +#include "lib/testsupport/testsupport.h" +#include "lib/cc/torint.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_openssl_mgt.h" /** Length of a curve25519 public key when encoded. */ #define CURVE25519_PUBKEY_LEN 32 diff --git a/src/lib/crypt_ops/crypto_dh.c b/src/lib/crypt_ops/crypto_dh.c new file mode 100644 index 0000000000..a2622cfc2f --- /dev/null +++ b/src/lib/crypt_ops/crypto_dh.c @@ -0,0 +1,511 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_dh.c + * \brief Block of functions related with DH utilities and operations. + **/ + +#include "lib/crypt_ops/compat_openssl.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_hkdf.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +DISABLE_GCC_WARNING(redundant-decls) + +#include <openssl/dh.h> + +ENABLE_GCC_WARNING(redundant-decls) + +#include <openssl/bn.h> +#include <string.h> + +/** A structure to hold the first half (x, g^x) of a Diffie-Hellman handshake + * while we're waiting for the second.*/ +struct crypto_dh_t { + DH *dh; /**< The openssl DH object */ +}; + +static int tor_check_dh_key(int severity, const BIGNUM *bn); + +/** Used by tortls.c: Get the DH* from a crypto_dh_t. + */ +DH * +crypto_dh_get_dh_(crypto_dh_t *dh) +{ + return dh->dh; +} + +/** Our DH 'g' parameter */ +#define DH_GENERATOR 2 + +/** Shared P parameter for our circuit-crypto DH key exchanges. */ +static BIGNUM *dh_param_p = NULL; +/** Shared P parameter for our TLS DH key exchanges. */ +static BIGNUM *dh_param_p_tls = NULL; +/** Shared G parameter for our DH key exchanges. */ +static BIGNUM *dh_param_g = NULL; + +/** Validate a given set of Diffie-Hellman parameters. This is moderately + * computationally expensive (milliseconds), so should only be called when + * the DH parameters change. Returns 0 on success, * -1 on failure. + */ +static int +crypto_validate_dh_params(const BIGNUM *p, const BIGNUM *g) +{ + DH *dh = NULL; + int ret = -1; + + /* Copy into a temporary DH object, just so that DH_check() can be called. */ + if (!(dh = DH_new())) + goto out; +#ifdef OPENSSL_1_1_API + BIGNUM *dh_p, *dh_g; + if (!(dh_p = BN_dup(p))) + goto out; + if (!(dh_g = BN_dup(g))) + goto out; + if (!DH_set0_pqg(dh, dh_p, NULL, dh_g)) + goto out; +#else /* !(defined(OPENSSL_1_1_API)) */ + if (!(dh->p = BN_dup(p))) + goto out; + if (!(dh->g = BN_dup(g))) + goto out; +#endif /* defined(OPENSSL_1_1_API) */ + + /* Perform the validation. */ + int codes = 0; + if (!DH_check(dh, &codes)) + goto out; + if (BN_is_word(g, DH_GENERATOR_2)) { + /* Per https://wiki.openssl.org/index.php/Diffie-Hellman_parameters + * + * OpenSSL checks the prime is congruent to 11 when g = 2; while the + * IETF's primes are congruent to 23 when g = 2. + */ + BN_ULONG residue = BN_mod_word(p, 24); + if (residue == 11 || residue == 23) + codes &= ~DH_NOT_SUITABLE_GENERATOR; + } + if (codes != 0) /* Specifics on why the params suck is irrelevant. */ + goto out; + + /* Things are probably not evil. */ + ret = 0; + + out: + if (dh) + DH_free(dh); + return ret; +} + +/** Set the global Diffie-Hellman generator, used for both TLS and internal + * DH stuff. + */ +static void +crypto_set_dh_generator(void) +{ + BIGNUM *generator; + int r; + + if (dh_param_g) + return; + + generator = BN_new(); + tor_assert(generator); + + r = BN_set_word(generator, DH_GENERATOR); + tor_assert(r); + + dh_param_g = generator; +} + +/** Set the global TLS Diffie-Hellman modulus. Use the Apache mod_ssl DH + * modulus. */ +void +crypto_set_tls_dh_prime(void) +{ + BIGNUM *tls_prime = NULL; + int r; + + /* If the space is occupied, free the previous TLS DH prime */ + if (BUG(dh_param_p_tls)) { + /* LCOV_EXCL_START + * + * We shouldn't be calling this twice. + */ + BN_clear_free(dh_param_p_tls); + dh_param_p_tls = NULL; + /* LCOV_EXCL_STOP */ + } + + tls_prime = BN_new(); + tor_assert(tls_prime); + + /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see + * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this + * prime. + */ + r = BN_hex2bn(&tls_prime, + "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98" + "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A" + "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7" + "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68" + "B0E7393E0F24218EB3"); + tor_assert(r); + + tor_assert(tls_prime); + + dh_param_p_tls = tls_prime; + crypto_set_dh_generator(); + tor_assert(0 == crypto_validate_dh_params(dh_param_p_tls, dh_param_g)); +} + +/** Initialize dh_param_p and dh_param_g if they are not already + * set. */ +static void +init_dh_param(void) +{ + BIGNUM *circuit_dh_prime; + int r; + if (BUG(dh_param_p && dh_param_g)) + return; // LCOV_EXCL_LINE This function isn't supposed to be called twice. + + circuit_dh_prime = BN_new(); + tor_assert(circuit_dh_prime); + + /* This is from rfc2409, section 6.2. It's a safe prime, and + supposedly it equals: + 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }. + */ + r = BN_hex2bn(&circuit_dh_prime, + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE65381FFFFFFFFFFFFFFFF"); + tor_assert(r); + + /* Set the new values as the global DH parameters. */ + dh_param_p = circuit_dh_prime; + crypto_set_dh_generator(); + tor_assert(0 == crypto_validate_dh_params(dh_param_p, dh_param_g)); + + if (!dh_param_p_tls) { + crypto_set_tls_dh_prime(); + } +} + +/** Number of bits to use when choosing the x or y value in a Diffie-Hellman + * handshake. Since we exponentiate by this value, choosing a smaller one + * lets our handhake go faster. + */ +#define DH_PRIVATE_KEY_BITS 320 + +/** Allocate and return a new DH object for a key exchange. Returns NULL on + * failure. + */ +crypto_dh_t * +crypto_dh_new(int dh_type) +{ + crypto_dh_t *res = tor_malloc_zero(sizeof(crypto_dh_t)); + + tor_assert(dh_type == DH_TYPE_CIRCUIT || dh_type == DH_TYPE_TLS || + dh_type == DH_TYPE_REND); + + if (!dh_param_p) + init_dh_param(); + + if (!(res->dh = DH_new())) + goto err; + +#ifdef OPENSSL_1_1_API + BIGNUM *dh_p = NULL, *dh_g = NULL; + + if (dh_type == DH_TYPE_TLS) { + dh_p = BN_dup(dh_param_p_tls); + } else { + dh_p = BN_dup(dh_param_p); + } + if (!dh_p) + goto err; + + dh_g = BN_dup(dh_param_g); + if (!dh_g) { + BN_free(dh_p); + goto err; + } + + if (!DH_set0_pqg(res->dh, dh_p, NULL, dh_g)) { + goto err; + } + + if (!DH_set_length(res->dh, DH_PRIVATE_KEY_BITS)) + goto err; +#else /* !(defined(OPENSSL_1_1_API)) */ + if (dh_type == DH_TYPE_TLS) { + if (!(res->dh->p = BN_dup(dh_param_p_tls))) + goto err; + } else { + if (!(res->dh->p = BN_dup(dh_param_p))) + goto err; + } + + if (!(res->dh->g = BN_dup(dh_param_g))) + goto err; + + res->dh->length = DH_PRIVATE_KEY_BITS; +#endif /* defined(OPENSSL_1_1_API) */ + + return res; + + /* LCOV_EXCL_START + * This error condition is only reached when an allocation fails */ + err: + crypto_log_errors(LOG_WARN, "creating DH object"); + if (res->dh) DH_free(res->dh); /* frees p and g too */ + tor_free(res); + return NULL; + /* LCOV_EXCL_STOP */ +} + +/** Return a copy of <b>dh</b>, sharing its internal state. */ +crypto_dh_t * +crypto_dh_dup(const crypto_dh_t *dh) +{ + crypto_dh_t *dh_new = tor_malloc_zero(sizeof(crypto_dh_t)); + tor_assert(dh); + tor_assert(dh->dh); + dh_new->dh = dh->dh; + DH_up_ref(dh->dh); + return dh_new; +} + +/** Return the length of the DH key in <b>dh</b>, in bytes. + */ +int +crypto_dh_get_bytes(crypto_dh_t *dh) +{ + tor_assert(dh); + return DH_size(dh->dh); +} + +/** Generate \<x,g^x\> for our part of the key exchange. Return 0 on + * success, -1 on failure. + */ +int +crypto_dh_generate_public(crypto_dh_t *dh) +{ +#ifndef OPENSSL_1_1_API + again: +#endif + if (!DH_generate_key(dh->dh)) { + /* LCOV_EXCL_START + * To test this we would need some way to tell openssl to break DH. */ + crypto_log_errors(LOG_WARN, "generating DH key"); + return -1; + /* LCOV_EXCL_STOP */ + } +#ifdef OPENSSL_1_1_API + /* OpenSSL 1.1.x doesn't appear to let you regenerate a DH key, without + * recreating the DH object. I have no idea what sort of aliasing madness + * can occur here, so do the check, and just bail on failure. + */ + const BIGNUM *pub_key, *priv_key; + DH_get0_key(dh->dh, &pub_key, &priv_key); + if (tor_check_dh_key(LOG_WARN, pub_key)<0) { + log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" + "the-universe chances really do happen. Treating as a failure."); + return -1; + } +#else /* !(defined(OPENSSL_1_1_API)) */ + if (tor_check_dh_key(LOG_WARN, dh->dh->pub_key)<0) { + /* LCOV_EXCL_START + * If this happens, then openssl's DH implementation is busted. */ + log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" + "the-universe chances really do happen. Trying again."); + /* Free and clear the keys, so OpenSSL will actually try again. */ + BN_clear_free(dh->dh->pub_key); + BN_clear_free(dh->dh->priv_key); + dh->dh->pub_key = dh->dh->priv_key = NULL; + goto again; + /* LCOV_EXCL_STOP */ + } +#endif /* defined(OPENSSL_1_1_API) */ + return 0; +} + +/** Generate g^x as necessary, and write the g^x for the key exchange + * as a <b>pubkey_len</b>-byte value into <b>pubkey</b>. Return 0 on + * success, -1 on failure. <b>pubkey_len</b> must be \>= DH_BYTES. + */ +int +crypto_dh_get_public(crypto_dh_t *dh, char *pubkey, size_t pubkey_len) +{ + int bytes; + tor_assert(dh); + + const BIGNUM *dh_pub; + +#ifdef OPENSSL_1_1_API + const BIGNUM *dh_priv; + DH_get0_key(dh->dh, &dh_pub, &dh_priv); +#else + dh_pub = dh->dh->pub_key; +#endif /* defined(OPENSSL_1_1_API) */ + + if (!dh_pub) { + if (crypto_dh_generate_public(dh)<0) + return -1; + else { +#ifdef OPENSSL_1_1_API + DH_get0_key(dh->dh, &dh_pub, &dh_priv); +#else + dh_pub = dh->dh->pub_key; +#endif + } + } + + tor_assert(dh_pub); + bytes = BN_num_bytes(dh_pub); + tor_assert(bytes >= 0); + if (pubkey_len < (size_t)bytes) { + log_warn(LD_CRYPTO, + "Weird! pubkey_len (%d) was smaller than DH_BYTES (%d)", + (int) pubkey_len, bytes); + return -1; + } + + memset(pubkey, 0, pubkey_len); + BN_bn2bin(dh_pub, (unsigned char*)(pubkey+(pubkey_len-bytes))); + + return 0; +} + +/** Check for bad Diffie-Hellman public keys (g^x). Return 0 if the key is + * okay (in the subgroup [2,p-2]), or -1 if it's bad. + * See http://www.cl.cam.ac.uk/ftp/users/rja14/psandqs.ps.gz for some tips. + */ +static int +tor_check_dh_key(int severity, const BIGNUM *bn) +{ + BIGNUM *x; + char *s; + tor_assert(bn); + x = BN_new(); + tor_assert(x); + if (BUG(!dh_param_p)) + init_dh_param(); //LCOV_EXCL_LINE we already checked whether we did this. + BN_set_word(x, 1); + if (BN_cmp(bn,x)<=0) { + log_fn(severity, LD_CRYPTO, "DH key must be at least 2."); + goto err; + } + BN_copy(x,dh_param_p); + BN_sub_word(x, 1); + if (BN_cmp(bn,x)>=0) { + log_fn(severity, LD_CRYPTO, "DH key must be at most p-2."); + goto err; + } + BN_clear_free(x); + return 0; + err: + BN_clear_free(x); + s = BN_bn2hex(bn); + log_fn(severity, LD_CRYPTO, "Rejecting insecure DH key [%s]", s); + OPENSSL_free(s); + return -1; +} + +/** Given a DH key exchange object, and our peer's value of g^y (as a + * <b>pubkey_len</b>-byte value in <b>pubkey</b>) generate + * <b>secret_bytes_out</b> bytes of shared key material and write them + * to <b>secret_out</b>. Return the number of bytes generated on success, + * or -1 on failure. + * + * (We generate key material by computing + * SHA1( g^xy || "\x00" ) || SHA1( g^xy || "\x01" ) || ... + * where || is concatenation.) + */ +ssize_t +crypto_dh_compute_secret(int severity, crypto_dh_t *dh, + const char *pubkey, size_t pubkey_len, + char *secret_out, size_t secret_bytes_out) +{ + char *secret_tmp = NULL; + BIGNUM *pubkey_bn = NULL; + size_t secret_len=0, secret_tmp_len=0; + int result=0; + tor_assert(dh); + tor_assert(secret_bytes_out/DIGEST_LEN <= 255); + tor_assert(pubkey_len < INT_MAX); + + if (!(pubkey_bn = BN_bin2bn((const unsigned char*)pubkey, + (int)pubkey_len, NULL))) + goto error; + if (tor_check_dh_key(severity, pubkey_bn)<0) { + /* Check for invalid public keys. */ + log_fn(severity, LD_CRYPTO,"Rejected invalid g^x"); + goto error; + } + secret_tmp_len = crypto_dh_get_bytes(dh); + secret_tmp = tor_malloc(secret_tmp_len); + result = DH_compute_key((unsigned char*)secret_tmp, pubkey_bn, dh->dh); + if (result < 0) { + log_warn(LD_CRYPTO,"DH_compute_key() failed."); + goto error; + } + secret_len = result; + if (crypto_expand_key_material_TAP((uint8_t*)secret_tmp, secret_len, + (uint8_t*)secret_out, secret_bytes_out)<0) + goto error; + secret_len = secret_bytes_out; + + goto done; + error: + result = -1; + done: + crypto_log_errors(LOG_WARN, "completing DH handshake"); + if (pubkey_bn) + BN_clear_free(pubkey_bn); + if (secret_tmp) { + memwipe(secret_tmp, 0, secret_tmp_len); + tor_free(secret_tmp); + } + if (result < 0) + return result; + else + return secret_len; +} + +/** Free a DH key exchange object. + */ +void +crypto_dh_free_(crypto_dh_t *dh) +{ + if (!dh) + return; + tor_assert(dh->dh); + DH_free(dh->dh); + tor_free(dh); +} + +void +crypto_dh_free_all(void) +{ + if (dh_param_p) + BN_clear_free(dh_param_p); + if (dh_param_p_tls) + BN_clear_free(dh_param_p_tls); + if (dh_param_g) + BN_clear_free(dh_param_g); + + dh_param_p = dh_param_p_tls = dh_param_g = NULL; +} diff --git a/src/lib/crypt_ops/crypto_dh.h b/src/lib/crypt_ops/crypto_dh.h new file mode 100644 index 0000000000..7b03e128a2 --- /dev/null +++ b/src/lib/crypt_ops/crypto_dh.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_dh.h + * + * \brief Headers for crypto_dh.c + **/ + +#ifndef TOR_CRYPTO_DH_H +#define TOR_CRYPTO_DH_H + +#include "orconfig.h" + +/** Length of our DH keys. */ +#define DH_BYTES (1024/8) + +typedef struct crypto_dh_t crypto_dh_t; + +/* Key negotiation */ +#define DH_TYPE_CIRCUIT 1 +#define DH_TYPE_REND 2 +#define DH_TYPE_TLS 3 +void crypto_set_tls_dh_prime(void); +crypto_dh_t *crypto_dh_new(int dh_type); +crypto_dh_t *crypto_dh_dup(const crypto_dh_t *dh); +int crypto_dh_get_bytes(crypto_dh_t *dh); +int crypto_dh_generate_public(crypto_dh_t *dh); +int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out, + size_t pubkey_out_len); +ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh, + const char *pubkey, size_t pubkey_len, + char *secret_out, size_t secret_out_len); +void crypto_dh_free_(crypto_dh_t *dh); +#define crypto_dh_free(dh) FREE_AND_NULL(crypto_dh_t, crypto_dh_free_, (dh)) + +/* Crypto DH free */ +void crypto_dh_free_all(void); + +/* Prototypes for private functions only used by tortls.c, crypto.c, and the + * unit tests. */ +struct dh_st; +struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh); + +#endif /* !defined(TOR_CRYPTO_DH_H) */ diff --git a/src/common/crypto_digest.c b/src/lib/crypt_ops/crypto_digest.c index 9f9a1a1e2c..949e694053 100644 --- a/src/common/crypto_digest.c +++ b/src/lib/crypt_ops/crypto_digest.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,14 +10,20 @@ * operations. **/ -#include "container.h" -#include "crypto_digest.h" -#include "crypto_openssl_mgt.h" -#include "crypto_util.h" -#include "torlog.h" +#include "lib/container/smartlist.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_openssl_mgt.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" #include "keccak-tiny/keccak-tiny.h" +#include <stdlib.h> +#include <string.h> + +#include "lib/arch/bytes.h" + DISABLE_GCC_WARNING(redundant-decls) #include <openssl/hmac.h> @@ -580,4 +586,3 @@ crypto_xof_free_(crypto_xof_t *xof) memwipe(xof, 0, sizeof(crypto_xof_t)); tor_free(xof); } - diff --git a/src/common/crypto_digest.h b/src/lib/crypt_ops/crypto_digest.h index 3bd74acdfa..15bc5ad5b9 100644 --- a/src/common/crypto_digest.h +++ b/src/lib/crypt_ops/crypto_digest.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,18 +13,9 @@ #ifndef TOR_CRYPTO_DIGEST_H #define TOR_CRYPTO_DIGEST_H -#include <stdio.h> - -#include "container.h" -#include "torint.h" - -/** Length of the output of our message digest. */ -#define DIGEST_LEN 20 -/** Length of the output of our second (improved) message digests. (For now - * this is just sha256, but it could be any other 256-bit digest.) */ -#define DIGEST256_LEN 32 -/** Length of the output of our 64-bit optimized message digests (SHA512). */ -#define DIGEST512_LEN 64 +#include "lib/cc/torint.h" +#include "lib/defs/digest_sizes.h" +#include "lib/malloc/util_malloc.h" /** Length of a sha1 message digest when encoded in base32 with trailing = * signs removed. */ @@ -78,6 +69,8 @@ typedef struct { typedef struct crypto_digest_t crypto_digest_t; typedef struct crypto_xof_t crypto_xof_t; +struct smartlist_t; + /* SHA-1 and other digests */ int crypto_digest(char *digest, const char *m, size_t len); int crypto_digest256(char *digest, const char *m, size_t len, @@ -133,4 +126,3 @@ digest_algorithm_t crypto_digest_get_algorithm(crypto_digest_t *digest); #endif #endif /* !defined(TOR_CRYPTO_DIGEST_H) */ - diff --git a/src/common/crypto_ed25519.c b/src/lib/crypt_ops/crypto_ed25519.c index 9c13e3bdf0..985652ecba 100644 --- a/src/common/crypto_ed25519.c +++ b/src/lib/crypt_ops/crypto_ed25519.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,19 +21,23 @@ #include <sys/stat.h> #endif -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_ed25519.h" -#include "crypto_format.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "torlog.h" -#include "util.h" -#include "util_format.h" +#include "lib/ctime/di_ops.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/encoding/binascii.h" +#include "lib/string/util_string.h" #include "ed25519/ref10/ed25519_ref10.h" #include "ed25519/donna/ed25519_donna_tor.h" +#include <string.h> + static void pick_ed25519_impl(void); /** An Ed25519 implementation, as a set of function pointers. */ @@ -814,4 +818,3 @@ ed25519_validate_pubkey(const ed25519_public_key_t *pubkey) return 0; } - diff --git a/src/common/crypto_ed25519.h b/src/lib/crypt_ops/crypto_ed25519.h index 74269ccffd..7255a3ec9b 100644 --- a/src/common/crypto_ed25519.h +++ b/src/lib/crypt_ops/crypto_ed25519.h @@ -1,13 +1,12 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CRYPTO_ED25519_H #define TOR_CRYPTO_ED25519_H -#include "testsupport.h" -#include "torint.h" -#include "crypto_curve25519.h" -#include "util.h" +#include "lib/testsupport/testsupport.h" +#include "lib/cc/torint.h" +#include "lib/crypt_ops/crypto_curve25519.h" #define ED25519_PUBKEY_LEN 32 #define ED25519_SECKEY_LEN 64 @@ -142,4 +141,3 @@ MOCK_DECL(STATIC int, ed25519_impl_spot_check, (void)); #endif #endif /* !defined(TOR_CRYPTO_ED25519_H) */ - diff --git a/src/common/crypto_format.c b/src/lib/crypt_ops/crypto_format.c index 460e85bac1..8c71b265bf 100644 --- a/src/common/crypto_format.c +++ b/src/lib/crypt_ops/crypto_format.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,15 +14,21 @@ #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif -#include "container.h" -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_ed25519.h" -#include "crypto_format.h" -#include "crypto_util.h" -#include "util.h" -#include "util_format.h" -#include "torlog.h" +#include "lib/container/smartlist.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/string/compat_string.h" +#include "lib/string/util_string.h" +#include "lib/string/printf.h" +#include "lib/encoding/binascii.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/fs/files.h" + +#include <string.h> /** Write the <b>datalen</b> bytes from <b>data</b> to the file named * <b>fname</b> in the tagged-data format. This format contains a @@ -296,4 +302,3 @@ digest256_from_base64(char *digest, const char *d64) else return -1; } - diff --git a/src/common/crypto_format.h b/src/lib/crypt_ops/crypto_format.h index bbd85dc720..77983f2161 100644 --- a/src/common/crypto_format.h +++ b/src/lib/crypt_ops/crypto_format.h @@ -1,15 +1,15 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CRYPTO_FORMAT_H #define TOR_CRYPTO_FORMAT_H -#include "testsupport.h" -#include "torint.h" -#include "crypto_ed25519.h" +#include "lib/testsupport/testsupport.h" +#include "lib/cc/torint.h" +#include "lib/crypt_ops/crypto_ed25519.h" int crypto_write_tagged_contents_to_file(const char *fname, const char *typestring, diff --git a/src/lib/crypt_ops/crypto_hkdf.c b/src/lib/crypt_ops/crypto_hkdf.c new file mode 100644 index 0000000000..0200d0fe9c --- /dev/null +++ b/src/lib/crypt_ops/crypto_hkdf.c @@ -0,0 +1,198 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_hkdf.c + * \brief Block of functions related with HKDF utilities and operations. + **/ + +#include "lib/crypt_ops/crypto_hkdf.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/crypt_ops/crypto_digest.h" + +#include "lib/crypt_ops/crypto_openssl_mgt.h" +#include "lib/intmath/cmp.h" +#include "lib/log/util_bug.h" + +#include <openssl/opensslv.h> + +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) +#define HAVE_OPENSSL_HKDF 1 +#include <openssl/kdf.h> +#endif + +#include <string.h> + +/** Given <b>key_in_len</b> bytes of negotiated randomness in <b>key_in</b> + * ("K"), expand it into <b>key_out_len</b> bytes of negotiated key material in + * <b>key_out</b> by taking the first <b>key_out_len</b> bytes of + * H(K | [00]) | H(K | [01]) | .... + * + * This is the key expansion algorithm used in the "TAP" circuit extension + * mechanism; it shouldn't be used for new protocols. + * + * Return 0 on success, -1 on failure. + */ +int +crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len, + uint8_t *key_out, size_t key_out_len) +{ + int i, r = -1; + uint8_t *cp, *tmp = tor_malloc(key_in_len+1); + uint8_t digest[DIGEST_LEN]; + + /* If we try to get more than this amount of key data, we'll repeat blocks.*/ + tor_assert(key_out_len <= DIGEST_LEN*256); + + memcpy(tmp, key_in, key_in_len); + for (cp = key_out, i=0; cp < key_out+key_out_len; + ++i, cp += DIGEST_LEN) { + tmp[key_in_len] = i; + if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1) < 0) + goto exit; + memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out))); + } + + r = 0; + exit: + memwipe(tmp, 0, key_in_len+1); + tor_free(tmp); + memwipe(digest, 0, sizeof(digest)); + return r; +} + +#ifdef HAVE_OPENSSL_HKDF +/** + * Perform RFC5869 HKDF computation using OpenSSL (only to be called from + * crypto_expand_key_material_rfc5869_sha256_openssl). Note that OpenSSL + * requires input key to be nonempty and salt length to be equal or less + * than 1024. + */ +static int +crypto_expand_key_material_rfc5869_sha256_openssl( + const uint8_t *key_in, size_t key_in_len, + const uint8_t *salt_in, size_t salt_in_len, + const uint8_t *info_in, size_t info_in_len, + uint8_t *key_out, size_t key_out_len) +{ + int r; + EVP_PKEY_CTX *evp_pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); + tor_assert(evp_pkey_ctx); + tor_assert(key_in_len != 0); + tor_assert(salt_in_len <= 1024); + + r = EVP_PKEY_derive_init(evp_pkey_ctx); + tor_assert(r == 1); + + r = EVP_PKEY_CTX_set_hkdf_md(evp_pkey_ctx, EVP_sha256()); + tor_assert(r == 1); + + r = EVP_PKEY_CTX_set1_hkdf_salt(evp_pkey_ctx, salt_in, (int)salt_in_len); + tor_assert(r == 1); + + r = EVP_PKEY_CTX_set1_hkdf_key(evp_pkey_ctx, key_in, (int)key_in_len); + tor_assert(r == 1); + + r = EVP_PKEY_CTX_add1_hkdf_info(evp_pkey_ctx, info_in, (int)info_in_len); + tor_assert(r == 1); + + r = EVP_PKEY_derive(evp_pkey_ctx, key_out, &key_out_len); + tor_assert(r == 1); + + EVP_PKEY_CTX_free(evp_pkey_ctx); + return 0; +} + +#else + +/** + * Perform RFC5869 HKDF computation using our own legacy implementation. + * Only to be called from crypto_expand_key_material_rfc5869_sha256_openssl. + */ +static int +crypto_expand_key_material_rfc5869_sha256_legacy( + const uint8_t *key_in, size_t key_in_len, + const uint8_t *salt_in, size_t salt_in_len, + const uint8_t *info_in, size_t info_in_len, + uint8_t *key_out, size_t key_out_len) +{ + uint8_t prk[DIGEST256_LEN]; + uint8_t tmp[DIGEST256_LEN + 128 + 1]; + uint8_t mac[DIGEST256_LEN]; + int i; + uint8_t *outp; + size_t tmp_len; + + crypto_hmac_sha256((char*)prk, + (const char*)salt_in, salt_in_len, + (const char*)key_in, key_in_len); + + /* If we try to get more than this amount of key data, we'll repeat blocks.*/ + tor_assert(key_out_len <= DIGEST256_LEN * 256); + tor_assert(info_in_len <= 128); + memset(tmp, 0, sizeof(tmp)); + outp = key_out; + i = 1; + + while (key_out_len) { + size_t n; + if (i > 1) { + memcpy(tmp, mac, DIGEST256_LEN); + memcpy(tmp+DIGEST256_LEN, info_in, info_in_len); + tmp[DIGEST256_LEN+info_in_len] = i; + tmp_len = DIGEST256_LEN + info_in_len + 1; + } else { + memcpy(tmp, info_in, info_in_len); + tmp[info_in_len] = i; + tmp_len = info_in_len + 1; + } + crypto_hmac_sha256((char*)mac, + (const char*)prk, DIGEST256_LEN, + (const char*)tmp, tmp_len); + n = key_out_len < DIGEST256_LEN ? key_out_len : DIGEST256_LEN; + memcpy(outp, mac, n); + key_out_len -= n; + outp += n; + ++i; + } + + memwipe(tmp, 0, sizeof(tmp)); + memwipe(mac, 0, sizeof(mac)); + return 0; +} +#endif + +/** Expand some secret key material according to RFC5869, using SHA256 as the + * underlying hash. The <b>key_in_len</b> bytes at <b>key_in</b> are the + * secret key material; the <b>salt_in_len</b> bytes at <b>salt_in</b> and the + * <b>info_in_len</b> bytes in <b>info_in_len</b> are the algorithm's "salt" + * and "info" parameters respectively. On success, write <b>key_out_len</b> + * bytes to <b>key_out</b> and return 0. Assert on failure. + */ +int +crypto_expand_key_material_rfc5869_sha256( + const uint8_t *key_in, size_t key_in_len, + const uint8_t *salt_in, size_t salt_in_len, + const uint8_t *info_in, size_t info_in_len, + uint8_t *key_out, size_t key_out_len) +{ + tor_assert(key_in); + tor_assert(key_in_len > 0); + +#ifdef HAVE_OPENSSL_HKDF + return crypto_expand_key_material_rfc5869_sha256_openssl(key_in, + key_in_len, salt_in, + salt_in_len, info_in, + info_in_len, + key_out, key_out_len); +#else + return crypto_expand_key_material_rfc5869_sha256_legacy(key_in, + key_in_len, salt_in, + salt_in_len, info_in, + info_in_len, + key_out, key_out_len); +#endif +} diff --git a/src/lib/crypt_ops/crypto_hkdf.h b/src/lib/crypt_ops/crypto_hkdf.h new file mode 100644 index 0000000000..4c42584277 --- /dev/null +++ b/src/lib/crypt_ops/crypto_hkdf.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_hkdf.h + * + * \brief Headers for crypto_hkdf.h + **/ + +#ifndef TOR_CRYPTO_HKDF_H +#define TOR_CRYPTO_HKDF_H + +#include "lib/cc/torint.h" + +int crypto_expand_key_material_TAP(const uint8_t *key_in, + size_t key_in_len, + uint8_t *key_out, size_t key_out_len); +int crypto_expand_key_material_rfc5869_sha256( + const uint8_t *key_in, size_t key_in_len, + const uint8_t *salt_in, size_t salt_in_len, + const uint8_t *info_in, size_t info_in_len, + uint8_t *key_out, size_t key_out_len); + +#endif /* !defined(TOR_CRYPTO_HKDF_H) */ diff --git a/src/common/crypto_openssl_mgt.c b/src/lib/crypt_ops/crypto_openssl_mgt.c index ea3519efa2..d1affa7258 100644 --- a/src/common/crypto_openssl_mgt.c +++ b/src/lib/crypt_ops/crypto_openssl_mgt.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,8 +10,12 @@ * \brief Block of functions related to operations from OpenSSL. **/ -#include "compat_openssl.h" -#include "crypto_openssl_mgt.h" +#include "lib/crypt_ops/compat_openssl.h" +#include "lib/crypt_ops/crypto_openssl_mgt.h" +#include "lib/string/util_string.h" +#include "lib/lock/compat_mutex.h" +#include "lib/testsupport/testsupport.h" +#include "lib/thread/threads.h" DISABLE_GCC_WARNING(redundant-decls) @@ -29,6 +33,8 @@ DISABLE_GCC_WARNING(redundant-decls) ENABLE_GCC_WARNING(redundant-decls) +#include <string.h> + #ifndef NEW_THREAD_API /** A number of preallocated mutexes for use by OpenSSL. */ static tor_mutex_t **openssl_mutexes_ = NULL; @@ -158,4 +164,3 @@ crypto_openssl_free_all(void) } #endif /* !defined(NEW_THREAD_API) */ } - diff --git a/src/common/crypto_openssl_mgt.h b/src/lib/crypt_ops/crypto_openssl_mgt.h index 09b6737962..8251f65ecf 100644 --- a/src/common/crypto_openssl_mgt.h +++ b/src/lib/crypt_ops/crypto_openssl_mgt.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,9 +13,7 @@ #ifndef TOR_CRYPTO_OPENSSL_H #define TOR_CRYPTO_OPENSSL_H -#include <stdio.h> -#include "util.h" - +#include "orconfig.h" #include <openssl/engine.h> /* @@ -82,4 +80,3 @@ int setup_openssl_threading(void); void crypto_openssl_free_all(void); #endif /* !defined(TOR_CRYPTO_OPENSSL_H) */ - diff --git a/src/common/crypto_pwbox.c b/src/lib/crypt_ops/crypto_pwbox.c index c2bd1d26cb..c001e295da 100644 --- a/src/common/crypto_pwbox.c +++ b/src/lib/crypt_ops/crypto_pwbox.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,15 +8,19 @@ * them to disk. */ -#include "crypto.h" -#include "crypto_digest.h" -#include "crypto_pwbox.h" -#include "crypto_rand.h" -#include "crypto_s2k.h" -#include "crypto_util.h" -#include "di_ops.h" -#include "util.h" -#include "pwbox.h" +#include <string.h> + +#include "lib/arch/bytes.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_pwbox.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_s2k.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/ctime/di_ops.h" +#include "lib/intmath/muldiv.h" +#include "trunnel/pwbox.h" +#include "lib/log/util_bug.h" /* 8 bytes "TORBOX00" 1 byte: header len (H) @@ -74,7 +78,7 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out, pwbox_encoded_setlen_data(enc, encrypted_len); encrypted_portion = pwbox_encoded_getarray_data(enc); - set_uint32(encrypted_portion, htonl((uint32_t)input_len)); + set_uint32(encrypted_portion, tor_htonl((uint32_t)input_len)); memcpy(encrypted_portion+4, input, input_len); /* Now that all the data is in position, derive some keys, encrypt, and @@ -189,7 +193,7 @@ crypto_unpwbox(uint8_t **out, size_t *outlen_out, cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv); crypto_cipher_decrypt(cipher, (char*)&result_len, (char*)encrypted, 4); - result_len = ntohl(result_len); + result_len = tor_ntohl(result_len); if (encrypted_len < result_len + 4) goto err; @@ -212,4 +216,3 @@ crypto_unpwbox(uint8_t **out, size_t *outlen_out, memwipe(keys, 0, sizeof(keys)); return rv; } - diff --git a/src/common/crypto_pwbox.h b/src/lib/crypt_ops/crypto_pwbox.h index a26b6d2c17..9ed35a150e 100644 --- a/src/common/crypto_pwbox.h +++ b/src/lib/crypt_ops/crypto_pwbox.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef CRYPTO_PWBOX_H_INCLUDED_ #define CRYPTO_PWBOX_H_INCLUDED_ -#include "torint.h" +#include "lib/cc/torint.h" #define UNPWBOX_OKAY 0 #define UNPWBOX_BAD_SECRET -1 diff --git a/src/common/crypto_rand.c b/src/lib/crypt_ops/crypto_rand.c index df2e2f65d3..6f479b013b 100644 --- a/src/common/crypto_rand.c +++ b/src/lib/crypt_ops/crypto_rand.c @@ -14,22 +14,26 @@ #ifndef CRYPTO_RAND_PRIVATE #define CRYPTO_RAND_PRIVATE -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_rand.h" #ifdef _WIN32 #include <windows.h> #include <wincrypt.h> #endif /* defined(_WIN32) */ -#include "container.h" -#include "compat.h" -#include "compat_openssl.h" -#include "crypto_util.h" -#include "sandbox.h" -#include "testsupport.h" -#include "torlog.h" -#include "util.h" -#include "util_format.h" +#include "lib/container/smartlist.h" +#include "lib/crypt_ops/compat_openssl.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/encoding/binascii.h" +#include "lib/intmath/weakrng.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/sandbox/sandbox.h" +#include "lib/string/compat_string.h" +#include "lib/string/util_string.h" +#include "lib/testsupport/testsupport.h" +#include "lib/fs/files.h" DISABLE_GCC_WARNING(redundant-decls) #include <openssl/rand.h> @@ -62,6 +66,8 @@ ENABLE_GCC_WARNING(redundant-decls) #include <sys/random.h> #endif +#include <string.h> + /** * How many bytes of entropy we add at once. * @@ -237,7 +243,7 @@ crypto_strongest_rand_fallback(uint8_t *out, size_t out_len) fd = open(sandbox_intern_string(filenames[i]), O_RDONLY, 0); if (fd<0) continue; log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]); - n = read_all(fd, (char*)out, out_len, 0); + n = read_all_from_fd(fd, (char*)out, out_len); close(fd); if (n != out_len) { /* LCOV_EXCL_START @@ -612,4 +618,3 @@ crypto_force_rand_ssleay(void) } #endif /* !defined(CRYPTO_RAND_PRIVATE) */ - diff --git a/src/common/crypto_rand.h b/src/lib/crypt_ops/crypto_rand.h index bb02e51001..938f11909e 100644 --- a/src/common/crypto_rand.h +++ b/src/lib/crypt_ops/crypto_rand.h @@ -13,8 +13,9 @@ #ifndef TOR_CRYPTO_RAND_H #define TOR_CRYPTO_RAND_H -#include "torint.h" -#include "util.h" +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" /* random numbers */ int crypto_seed_rng(void) ATTR_WUR; @@ -49,4 +50,3 @@ extern int break_strongest_rng_fallback; #endif /* defined(CRYPTO_RAND_PRIVATE) */ #endif /* !defined(TOR_CRYPTO_RAND_H) */ - diff --git a/src/common/crypto_rsa.c b/src/lib/crypt_ops/crypto_rsa.c index f66cdef3c5..9290414de0 100644 --- a/src/common/crypto_rsa.c +++ b/src/lib/crypt_ops/crypto_rsa.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,14 +9,17 @@ * \brief Block of functions related with RSA utilities and operations. **/ -#include "crypto.h" -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_format.h" -#include "compat_openssl.h" -#include "crypto_rand.h" -#include "crypto_rsa.h" -#include "crypto_util.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/compat_openssl.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_rsa.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/ctime/di_ops.h" +#include "lib/log/util_bug.h" +#include "lib/fs/files.h" DISABLE_GCC_WARNING(redundant-decls) @@ -33,9 +36,10 @@ DISABLE_GCC_WARNING(redundant-decls) ENABLE_GCC_WARNING(redundant-decls) -#include "torlog.h" -#include "util.h" -#include "util_format.h" +#include "lib/log/torlog.h" +#include "lib/encoding/binascii.h" + +#include <string.h> /** Declaration for crypto_pk_t structure. */ struct crypto_pk_t @@ -44,27 +48,6 @@ struct crypto_pk_t RSA *key; /**< The key itself */ }; -/** Log all pending crypto errors at level <b>severity</b>. Use - * <b>doing</b> to describe our current activities. - */ -static void -crypto_log_errors(int severity, const char *doing) -{ - unsigned long err; - const char *msg, *lib, *func; - 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 (!msg) msg = "(null)"; - if (!lib) lib = "(null)"; - if (!func) func = "(null)"; - if (BUG(!doing)) doing = "(null)"; - tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", - doing, msg, lib, func); - } -} - /** Return the number of bytes added by padding method <b>padding</b>. */ int @@ -1180,4 +1163,3 @@ crypto_pk_base64_decode(const char *str, size_t len) tor_free(der); return pk; } - diff --git a/src/common/crypto_rsa.h b/src/lib/crypt_ops/crypto_rsa.h index e952089318..093f2cec6c 100644 --- a/src/common/crypto_rsa.h +++ b/src/lib/crypt_ops/crypto_rsa.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,13 +15,10 @@ #include "orconfig.h" -#include "crypto_digest.h" -#include <stdio.h> -#include "torint.h" -#include "testsupport.h" -#include "compat.h" -#include "util.h" -#include "torlog.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" +#include "lib/log/torlog.h" /** Length of our public keys. */ #define PK_BYTES (1024/8) @@ -116,4 +113,3 @@ void crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src); #endif #endif - diff --git a/src/common/crypto_s2k.c b/src/lib/crypt_ops/crypto_s2k.c index 8543760ec5..ab91d92f0e 100644 --- a/src/common/crypto_s2k.c +++ b/src/lib/crypt_ops/crypto_s2k.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,13 +12,14 @@ #define CRYPTO_S2K_PRIVATE -#include "compat.h" -#include "crypto.h" -#include "crypto_digest.h" -#include "crypto_rand.h" -#include "crypto_s2k.h" -#include "crypto_util.h" -#include "util.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_hkdf.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_s2k.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/ctime/di_ops.h" +#include "lib/log/util_bug.h" #include <openssl/evp.h> @@ -27,6 +28,8 @@ #include <libscrypt.h> #endif +#include <string.h> + /* Encoded secrets take the form: u8 type; @@ -472,4 +475,3 @@ secret_to_key_check(const uint8_t *spec_and_key, size_t spec_and_key_len, memwipe(buf, 0, sizeof(buf)); return rv; } - diff --git a/src/common/crypto_s2k.h b/src/lib/crypt_ops/crypto_s2k.h index 849ff59ce8..b270897b68 100644 --- a/src/common/crypto_s2k.h +++ b/src/lib/crypt_ops/crypto_s2k.h @@ -1,14 +1,14 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CRYPTO_S2K_H_INCLUDED #define TOR_CRYPTO_S2K_H_INCLUDED #include <stdio.h> -#include "torint.h" +#include "lib/cc/torint.h" /** Length of RFC2440-style S2K specifier: the first 8 bytes are a salt, the * 9th describes how much iteration to do. */ diff --git a/src/common/crypto_util.c b/src/lib/crypt_ops/crypto_util.c index b0d5b6b2f7..19b0885256 100644 --- a/src/common/crypto_util.c +++ b/src/lib/crypt_ops/crypto_util.c @@ -13,7 +13,8 @@ #ifndef CRYPTO_UTIL_PRIVATE #define CRYPTO_UTIL_PRIVATE -#include "crypto_util.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/cc/compat_compiler.h" #include <string.h> @@ -23,14 +24,16 @@ #include <wincrypt.h> #endif /* defined(_WIN32) */ -#include "util.h" - DISABLE_GCC_WARNING(redundant-decls) +#include <openssl/err.h> #include <openssl/crypto.h> ENABLE_GCC_WARNING(redundant-decls) +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + /** * Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to * the value <b>byte</b>. @@ -103,5 +106,24 @@ memwipe(void *mem, uint8_t byte, size_t sz) memset(mem, byte, sz); } +/** Log all pending crypto errors at level <b>severity</b>. Use + * <b>doing</b> to describe our current activities. + */ +void +crypto_log_errors(int severity, const char *doing) +{ + unsigned long err; + const char *msg, *lib, *func; + 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 (!msg) msg = "(null)"; + if (!lib) lib = "(null)"; + if (!func) func = "(null)"; + if (BUG(!doing)) doing = "(null)"; + tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", + doing, msg, lib, func); + } +} #endif /* !defined(CRYPTO_UTIL_PRIVATE) */ - diff --git a/src/common/crypto_util.h b/src/lib/crypt_ops/crypto_util.h index 922942b371..3ce34e6f23 100644 --- a/src/common/crypto_util.h +++ b/src/lib/crypt_ops/crypto_util.h @@ -13,11 +13,14 @@ #ifndef TOR_CRYPTO_UTIL_H #define TOR_CRYPTO_UTIL_H -#include "torint.h" +#include "lib/cc/torint.h" /** OpenSSL-based utility functions. */ void memwipe(void *mem, uint8_t byte, size_t sz); +/** Log utility function */ +void crypto_log_errors(int severity, const char *doing); + #ifdef CRYPTO_UTIL_PRIVATE #ifdef TOR_UNIT_TESTS #endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/lib/crypt_ops/digestset.c b/src/lib/crypt_ops/digestset.c new file mode 100644 index 0000000000..89dd377a9c --- /dev/null +++ b/src/lib/crypt_ops/digestset.c @@ -0,0 +1,58 @@ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file digestset.c + * \brief Implementation for a set of digests + **/ + +#include "orconfig.h" +#include "lib/container/bloomfilt.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/defs/digest_sizes.h" +#include "lib/crypt_ops/digestset.h" +#include "siphash.h" + +/* Wrap our hash function to have the signature that the bloom filter + * needs. */ +static uint64_t +bloomfilt_digest_hash(const struct sipkey *key, + const void *item) +{ + return siphash24(item, DIGEST_LEN, key); +} + +/** + * Allocate and return an digestset, suitable for holding up to + * <b>max_guess</b> distinct values. + */ +digestset_t * +digestset_new(int max_guess) +{ + uint8_t k[BLOOMFILT_KEY_LEN]; + crypto_rand((void*)k, sizeof(k)); + return bloomfilt_new(max_guess, bloomfilt_digest_hash, k); +} + +/** + * Add <b>digest</b> to <b>set</b>. + * + * All future queries for <b>digest</b> in set will return true. Removing + * items is not possible. + */ +void +digestset_add(digestset_t *set, const char *digest) +{ + bloomfilt_add(set, digest); +} + +/** + * Return true if <b>digest</b> is a member of <b>set</b>. (And probably, + * return false if <b>digest</b> is not a member of set.) + */ +int +digestset_probably_contains(const digestset_t *set, + const char *digest) +{ + return bloomfilt_probably_contains(set, digest); +} diff --git a/src/lib/crypt_ops/digestset.h b/src/lib/crypt_ops/digestset.h new file mode 100644 index 0000000000..328979ae0d --- /dev/null +++ b/src/lib/crypt_ops/digestset.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file digestset.h + * \brief Types to handle sets of digests, based on bloom filters. + **/ + +#ifndef TOR_DIGESTSET_H +#define TOR_DIGESTSET_H + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/container/bloomfilt.h" + +/** + * An digestset_t represents a set of 20-byte digest values. The + * implementation is probabilistic: false negatives cannot occur but false + * positives are possible. + */ +typedef struct bloomfilt_t digestset_t; + +digestset_t *digestset_new(int max_addresses_guess); +#define digestset_free(set) bloomfilt_free(set) +void digestset_add(digestset_t *set, const char *addr); +int digestset_probably_contains(const digestset_t *set, + const char *addr); + +#endif diff --git a/src/lib/crypt_ops/include.am b/src/lib/crypt_ops/include.am new file mode 100644 index 0000000000..1b88b880d0 --- /dev/null +++ b/src/lib/crypt_ops/include.am @@ -0,0 +1,46 @@ + +noinst_LIBRARIES += src/lib/libtor-crypt-ops.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-crypt-ops-testing.a +endif + +src_lib_libtor_crypt_ops_a_SOURCES = \ + src/lib/crypt_ops/aes.c \ + src/lib/crypt_ops/crypto.c \ + src/lib/crypt_ops/crypto_curve25519.c \ + src/lib/crypt_ops/crypto_dh.c \ + src/lib/crypt_ops/crypto_digest.c \ + src/lib/crypt_ops/crypto_ed25519.c \ + src/lib/crypt_ops/crypto_format.c \ + src/lib/crypt_ops/crypto_hkdf.c \ + src/lib/crypt_ops/crypto_openssl_mgt.c \ + src/lib/crypt_ops/crypto_pwbox.c \ + src/lib/crypt_ops/crypto_rand.c \ + src/lib/crypt_ops/crypto_rsa.c \ + src/lib/crypt_ops/crypto_s2k.c \ + src/lib/crypt_ops/crypto_util.c \ + src/lib/crypt_ops/digestset.c + +src_lib_libtor_crypt_ops_testing_a_SOURCES = \ + $(src_lib_libtor_crypt_ops_a_SOURCES) +src_lib_libtor_crypt_ops_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_crypt_ops_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/crypt_ops/aes.h \ + src/lib/crypt_ops/compat_openssl.h \ + src/lib/crypt_ops/crypto_curve25519.h \ + src/lib/crypt_ops/crypto_dh.h \ + src/lib/crypt_ops/crypto_digest.h \ + src/lib/crypt_ops/crypto_ed25519.h \ + src/lib/crypt_ops/crypto_format.h \ + src/lib/crypt_ops/crypto.h \ + src/lib/crypt_ops/crypto_hkdf.h \ + src/lib/crypt_ops/crypto_openssl_mgt.h \ + src/lib/crypt_ops/crypto_pwbox.h \ + src/lib/crypt_ops/crypto_rand.h \ + src/lib/crypt_ops/crypto_rsa.h \ + src/lib/crypt_ops/crypto_s2k.h \ + src/lib/crypt_ops/crypto_util.h \ + src/lib/crypt_ops/digestset.h diff --git a/src/lib/ctime/.may_include b/src/lib/ctime/.may_include new file mode 100644 index 0000000000..e74669bce1 --- /dev/null +++ b/src/lib/ctime/.may_include @@ -0,0 +1,5 @@ +orconfig.h +lib/cc/*.h +lib/ctime/*.h +lib/err/*.h +lib/malloc/*.h diff --git a/src/common/di_ops.c b/src/lib/ctime/di_ops.c index 90e9357c8e..287ff6080a 100644 --- a/src/common/di_ops.c +++ b/src/lib/ctime/di_ops.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ +/* Copyright (c) 2011-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,9 +7,11 @@ **/ #include "orconfig.h" -#include "di_ops.h" -#include "torlog.h" -#include "util.h" +#include "lib/ctime/di_ops.h" +#include "lib/err/torerr.h" +#include "lib/malloc/util_malloc.h" + +#include <string.h> /** * Timing-safe version of memcmp. As memcmp, compare the <b>sz</b> bytes at @@ -171,8 +173,8 @@ dimap_add_entry(di_digest256_map_t **map, di_digest256_map_t *new_ent; { void *old_val = dimap_search(*map, key, NULL); - tor_assert(! old_val); - tor_assert(val); + raw_assert(! old_val); + raw_assert(val); } new_ent = tor_malloc_zero(sizeof(di_digest256_map_t)); new_ent->next = *map; @@ -264,11 +266,10 @@ select_array_member_cumulative_timei(const uint64_t *entries, int n_entries, rand_val = INT64_MAX; } } - tor_assert(total_so_far == total); - tor_assert(n_chosen == 1); - tor_assert(i_chosen >= 0); - tor_assert(i_chosen < n_entries); + raw_assert(total_so_far == total); + raw_assert(n_chosen == 1); + raw_assert(i_chosen >= 0); + raw_assert(i_chosen < n_entries); return i_chosen; } - diff --git a/src/common/di_ops.h b/src/lib/ctime/di_ops.h index 67d9c9f0df..92af7ae278 100644 --- a/src/common/di_ops.h +++ b/src/lib/ctime/di_ops.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #define TOR_DI_OPS_H #include "orconfig.h" -#include "torint.h" +#include "lib/cc/torint.h" int tor_memcmp(const void *a, const void *b, size_t sz); int tor_memeq(const void *a, const void *b, size_t sz); diff --git a/src/lib/ctime/include.am b/src/lib/ctime/include.am new file mode 100644 index 0000000000..b46c43ba0c --- /dev/null +++ b/src/lib/ctime/include.am @@ -0,0 +1,25 @@ + +noinst_LIBRARIES += src/lib/libtor-ctime.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-ctime-testing.a +endif + +if ADD_MULODI4 +mulodi4_source=src/ext/mulodi/mulodi4.c +else +mulodi4_source= +endif + +src_lib_libtor_ctime_a_SOURCES = \ + $(mulodi4_source) \ + src/ext/csiphash.c \ + src/lib/ctime/di_ops.c + +src_lib_libtor_ctime_testing_a_SOURCES = \ + $(src_lib_libtor_ctime_a_SOURCES) +src_lib_libtor_ctime_a_CFLAGS = @CFLAGS_CONSTTIME@ +src_lib_libtor_ctime_testing_a_CFLAGS = @CFLAGS_CONSTTIME@ $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/ctime/di_ops.h diff --git a/src/lib/defs/.may_include b/src/lib/defs/.may_include new file mode 100644 index 0000000000..2b06e8519c --- /dev/null +++ b/src/lib/defs/.may_include @@ -0,0 +1 @@ +orconfig.h diff --git a/src/lib/defs/digest_sizes.h b/src/lib/defs/digest_sizes.h new file mode 100644 index 0000000000..f426fff20d --- /dev/null +++ b/src/lib/defs/digest_sizes.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_DIGEST_SIZES_H +#define TOR_DIGEST_SIZES_H + +/** Length of the output of our message digest. */ +#define DIGEST_LEN 20 +/** Length of the output of our second (improved) message digests. (For now + * this is just sha256, but it could be any other 256-bit digest.) */ +#define DIGEST256_LEN 32 +/** Length of the output of our 64-bit optimized message digests (SHA512). */ +#define DIGEST512_LEN 64 + +#endif diff --git a/src/lib/defs/include.am b/src/lib/defs/include.am new file mode 100644 index 0000000000..ff48cff07c --- /dev/null +++ b/src/lib/defs/include.am @@ -0,0 +1,3 @@ + +noinst_HEADERS += \ + src/lib/defs/digest_sizes.h diff --git a/src/lib/encoding/.may_include b/src/lib/encoding/.may_include new file mode 100644 index 0000000000..92231b5133 --- /dev/null +++ b/src/lib/encoding/.may_include @@ -0,0 +1,9 @@ +orconfig.h +lib/cc/*.h +lib/encoding/*.h +lib/intmath/*.h +lib/log/*.h +lib/malloc/*.h +lib/string/*.h +lib/testsupport/*.h +lib/wallclock/*.h diff --git a/src/common/util_format.c b/src/lib/encoding/binascii.c index e51757a4e8..df9bb4a813 100644 --- a/src/common/util_format.c +++ b/src/lib/encoding/binascii.c @@ -1,26 +1,45 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file util_format.c + * \file binascii.c * * \brief Miscellaneous functions for encoding and decoding various things * in base{16,32,64}. */ #include "orconfig.h" -#include "torlog.h" -#include "util.h" -#include "util_format.h" -#include "torint.h" + +#include "lib/encoding/binascii.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/cc/torint.h" +#include "lib/string/compat_ctype.h" +#include "lib/intmath/muldiv.h" +#include "lib/malloc/util_malloc.h" #include <stddef.h> #include <string.h> #include <stdlib.h> +/** Return a pointer to a NUL-terminated hexadecimal string encoding + * the first <b>fromlen</b> bytes of <b>from</b>. (fromlen must be \<= 32.) The + * result does not need to be deallocated, but repeated calls to + * hex_str will trash old results. + */ +const char * +hex_str(const char *from, size_t fromlen) +{ + static char buf[65]; + if (fromlen>(sizeof(buf)-1)/2) + fromlen = (sizeof(buf)-1)/2; + base16_encode(buf,sizeof(buf),from,fromlen); + return buf; +} + /* Return the base32 encoded size in bytes using the source length srclen. * * (WATCH OUT: This API counts the terminating NUL byte, but @@ -464,39 +483,6 @@ base16_encode(char *dest, size_t destlen, const char *src, size_t srclen) *cp = '\0'; } -/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */ -static inline int -hex_decode_digit_(char c) -{ - switch (c) { - case '0': return 0; - case '1': return 1; - case '2': return 2; - case '3': return 3; - case '4': return 4; - case '5': return 5; - case '6': return 6; - case '7': return 7; - case '8': return 8; - case '9': return 9; - case 'A': case 'a': return 10; - case 'B': case 'b': return 11; - case 'C': case 'c': return 12; - case 'D': case 'd': return 13; - case 'E': case 'e': return 14; - case 'F': case 'f': return 15; - default: - return -1; - } -} - -/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */ -int -hex_decode_digit(char c) -{ - return hex_decode_digit_(c); -} - /** Given a hexadecimal string of <b>srclen</b> bytes in <b>src</b>, decode * it and store the result in the <b>destlen</b>-byte buffer at <b>dest</b>. * Return the number of bytes decoded on success, -1 on failure. If @@ -519,8 +505,8 @@ base16_decode(char *dest, size_t destlen, const char *src, size_t srclen) end = src+srclen; while (src<end) { - v1 = hex_decode_digit_(*src); - v2 = hex_decode_digit_(*(src+1)); + v1 = hex_decode_digit(*src); + v2 = hex_decode_digit(*(src+1)); if (v1<0||v2<0) return -1; *(uint8_t*)dest = (v1<<4)|v2; @@ -532,4 +518,3 @@ base16_decode(char *dest, size_t destlen, const char *src, size_t srclen) return (int) (dest-dest_orig); } - diff --git a/src/common/util_format.h b/src/lib/encoding/binascii.h index 0aefe3a44e..67f9eb0e87 100644 --- a/src/common/util_format.h +++ b/src/lib/encoding/binascii.h @@ -1,14 +1,18 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#ifndef TOR_UTIL_FORMAT_H -#define TOR_UTIL_FORMAT_H +#ifndef TOR_BINASCII_H +#define TOR_BINASCII_H -#include "testsupport.h" -#include "torint.h" +#include "orconfig.h" +#include <stddef.h> +#include "lib/testsupport/testsupport.h" +#include "lib/cc/torint.h" + +const char *hex_str(const char *from, size_t fromlen); /** @{ */ /** These macros don't check for overflow. Use them only for constant inputs @@ -44,9 +48,7 @@ void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen); int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen); size_t base32_encoded_size(size_t srclen); -int hex_decode_digit(char c); void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen); int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen); #endif /* !defined(TOR_UTIL_FORMAT_H) */ - diff --git a/src/common/confline.c b/src/lib/encoding/confline.c index bf613ab742..7f535b321a 100644 --- a/src/common/confline.c +++ b/src/lib/encoding/confline.c @@ -1,29 +1,19 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "compat.h" -#include "confline.h" -#include "torlog.h" -#include "util.h" -#include "container.h" - -static int config_get_lines_aux(const char *string, config_line_t **result, - int extended, int allow_include, - int *has_include, smartlist_t *opened_lst, - int recursion_level, config_line_t **last); -static smartlist_t *config_get_file_list(const char *path, - smartlist_t *opened_files); -static int config_get_included_config(const char *path, int recursion_level, - int extended, config_line_t **config, - config_line_t **config_last, - smartlist_t *opened_lst); -static int config_process_include(const char *path, int recursion_level, - int extended, config_line_t **list, - config_line_t **list_last, - smartlist_t *opened_lst); +#include "lib/encoding/confline.h" +#include "lib/encoding/cstring.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/compat_ctype.h" +#include "lib/string/compat_string.h" +#include "lib/string/util_string.h" + +#include <string.h> /** Helper: allocate a new configuration option mapping 'key' to 'val', * append it to *<b>lst</b>. */ @@ -86,11 +76,12 @@ config_line_find(const config_line_t *lines, * <b>opened_lst</b> will have a list of opened files if provided. * Returns the a pointer to the last element of the <b>result</b> in * <b>last</b>. */ -static int +int config_get_lines_aux(const char *string, config_line_t **result, int extended, int allow_include, int *has_include, - smartlist_t *opened_lst, int recursion_level, - config_line_t **last) + struct smartlist_t *opened_lst, int recursion_level, + config_line_t **last, + include_handler_fn handle_include) { config_line_t *list = NULL, **next, *list_last = NULL; char *k, *v; @@ -133,13 +124,13 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended, } } - if (allow_include && !strcmp(k, "%include")) { + if (allow_include && !strcmp(k, "%include") && handle_include) { tor_free(k); include_used = 1; config_line_t *include_list; - if (config_process_include(v, recursion_level, extended, &include_list, - &list_last, opened_lst) < 0) { + if (handle_include(v, recursion_level, extended, &include_list, + &list_last, opened_lst) < 0) { log_warn(LD_CONFIG, "Error reading included configuration " "file or directory: \"%s\".", v); config_free_lines(list); @@ -178,152 +169,12 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended, return 0; } -/** Helper: parse the config string and strdup into key/value - * strings. Set *result to the list, or NULL if parsing the string - * failed. Set *has_include to 1 if <b>result</b> has values from - * %included files. <b>opened_lst</b> will have a list of opened files if - * provided. Return 0 on success, -1 on failure. Warn and ignore any - * misformatted lines. - * - * If <b>extended</b> is set, then treat keys beginning with / and with + as - * indicating "clear" and "append" respectively. */ -int -config_get_lines_include(const char *string, config_line_t **result, - int extended, int *has_include, - smartlist_t *opened_lst) -{ - return config_get_lines_aux(string, result, extended, 1, has_include, - opened_lst, 1, NULL); -} - /** Same as config_get_lines_include but does not allow %include */ int config_get_lines(const char *string, config_line_t **result, int extended) { return config_get_lines_aux(string, result, extended, 0, NULL, NULL, 1, - NULL); -} - -/** Adds a list of configuration files present on <b>path</b> to - * <b>file_list</b>. <b>path</b> can be a file or a directory. If it is a file, - * only that file will be added to <b>file_list</b>. If it is a directory, - * all paths for files on that directory root (no recursion) except for files - * whose name starts with a dot will be added to <b>file_list</b>. - * <b>opened_files</b> will have a list of files opened by this function - * if provided. Return 0 on success, -1 on failure. Ignores empty files. - */ -static smartlist_t * -config_get_file_list(const char *path, smartlist_t *opened_files) -{ - smartlist_t *file_list = smartlist_new(); - - if (opened_files) { - smartlist_add_strdup(opened_files, path); - } - - file_status_t file_type = file_status(path); - if (file_type == FN_FILE) { - smartlist_add_strdup(file_list, path); - return file_list; - } else if (file_type == FN_DIR) { - smartlist_t *all_files = tor_listdir(path); - if (!all_files) { - smartlist_free(file_list); - return NULL; - } - smartlist_sort_strings(all_files); - SMARTLIST_FOREACH_BEGIN(all_files, char *, f) { - if (f[0] == '.') { - tor_free(f); - continue; - } - - char *fullname; - tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f); - tor_free(f); - - if (opened_files) { - smartlist_add_strdup(opened_files, fullname); - } - - if (file_status(fullname) != FN_FILE) { - tor_free(fullname); - continue; - } - smartlist_add(file_list, fullname); - } SMARTLIST_FOREACH_END(f); - smartlist_free(all_files); - return file_list; - } else if (file_type == FN_EMPTY) { - return file_list; - } else { - smartlist_free(file_list); - return NULL; - } -} - -/** Creates a list of config lines present on included <b>path</b>. - * Set <b>config</b> to the list and <b>config_last</b> to the last element of - * <b>config</b>. <b>opened_lst</b> will have a list of opened files if - * provided. Return 0 on success, -1 on failure. */ -static int -config_get_included_config(const char *path, int recursion_level, int extended, - config_line_t **config, config_line_t **config_last, - smartlist_t *opened_lst) -{ - char *included_conf = read_file_to_str(path, 0, NULL); - if (!included_conf) { - return -1; - } - - if (config_get_lines_aux(included_conf, config, extended, 1, NULL, - opened_lst, recursion_level+1, config_last) < 0) { - tor_free(included_conf); - return -1; - } - - tor_free(included_conf); - return 0; -} - -/** Process an %include <b>path</b> in a config file. Set <b>list</b> to the - * list of configuration settings obtained and <b>list_last</b> to the last - * element of the same list. <b>opened_lst</b> will have a list of opened - * files if provided. Return 0 on success, -1 on failure. */ -static int -config_process_include(const char *path, int recursion_level, int extended, - config_line_t **list, config_line_t **list_last, - smartlist_t *opened_lst) -{ - config_line_t *ret_list = NULL; - config_line_t **next = &ret_list; - - smartlist_t *config_files = config_get_file_list(path, opened_lst); - if (!config_files) { - return -1; - } - - int rv = -1; - SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) { - config_line_t *included_config = NULL; - if (config_get_included_config(config_file, recursion_level, extended, - &included_config, list_last, - opened_lst) < 0) { - goto done; - } - - *next = included_config; - if (*list_last) - next = &(*list_last)->next; - - } SMARTLIST_FOREACH_END(config_file); - *list = ret_list; - rv = 0; - - done: - SMARTLIST_FOREACH(config_files, char *, f, tor_free(f)); - smartlist_free(config_files); - return rv; + NULL, NULL); } /** @@ -535,4 +386,3 @@ parse_config_line_from_str_verbose(const char *line, char **key_out, return line; } - diff --git a/src/common/confline.h b/src/lib/encoding/confline.h index 772a9bbbdc..f03faed5eb 100644 --- a/src/common/confline.h +++ b/src/lib/encoding/confline.h @@ -1,13 +1,13 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CONFLINE_H #define TOR_CONFLINE_H -#include "container.h" +struct smartlist_t; /** Ordinary configuration line. */ #define CONFIG_LINE_NORMAL 0 @@ -44,10 +44,6 @@ const config_line_t *config_line_find(const config_line_t *lines, const char *key); int config_lines_eq(config_line_t *a, config_line_t *b); int config_count_key(const config_line_t *a, const char *key); -int config_get_lines(const char *string, config_line_t **result, int extended); -int config_get_lines_include(const char *string, config_line_t **result, - int extended, int *has_include, - smartlist_t *opened_lst); void config_free_lines_(config_line_t *front); #define config_free_lines(front) \ do { \ @@ -57,5 +53,20 @@ void config_free_lines_(config_line_t *front); const char *parse_config_line_from_str_verbose(const char *line, char **key_out, char **value_out, const char **err_out); -#endif /* !defined(TOR_CONFLINE_H) */ +int config_get_lines(const char *string, struct config_line_t **result, + int extended); + +typedef int (*include_handler_fn)(const char *, int, int, + struct config_line_t **, + struct config_line_t **, + struct smartlist_t *); + +int config_get_lines_aux(const char *string, struct config_line_t **result, + int extended, + int allow_include, int *has_include, + struct smartlist_t *opened_lst, int recursion_level, + config_line_t **last, + include_handler_fn handle_include); + +#endif /* !defined(TOR_CONFLINE_H) */ diff --git a/src/lib/encoding/cstring.c b/src/lib/encoding/cstring.c new file mode 100644 index 0000000000..86c17f0d2c --- /dev/null +++ b/src/lib/encoding/cstring.c @@ -0,0 +1,132 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/encoding/cstring.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/compat_ctype.h" + +#include <string.h> + +#define TOR_ISODIGIT(c) ('0' <= (c) && (c) <= '7') + +/** Given a c-style double-quoted escaped string in <b>s</b>, extract and + * decode its contents into a newly allocated string. On success, assign this + * string to *<b>result</b>, assign its length to <b>size_out</b> (if + * provided), and return a pointer to the position in <b>s</b> immediately + * after the string. On failure, return NULL. + */ +const char * +unescape_string(const char *s, char **result, size_t *size_out) +{ + const char *cp; + char *out; + if (s[0] != '\"') + return NULL; + cp = s+1; + while (1) { + switch (*cp) { + case '\0': + case '\n': + return NULL; + case '\"': + goto end_of_loop; + case '\\': + if (cp[1] == 'x' || cp[1] == 'X') { + if (!(TOR_ISXDIGIT(cp[2]) && TOR_ISXDIGIT(cp[3]))) + return NULL; + cp += 4; + } else if (TOR_ISODIGIT(cp[1])) { + cp += 2; + if (TOR_ISODIGIT(*cp)) ++cp; + if (TOR_ISODIGIT(*cp)) ++cp; + } else if (cp[1] == 'n' || cp[1] == 'r' || cp[1] == 't' || cp[1] == '"' + || cp[1] == '\\' || cp[1] == '\'') { + cp += 2; + } else { + return NULL; + } + break; + default: + ++cp; + break; + } + } + end_of_loop: + out = *result = tor_malloc(cp-s + 1); + cp = s+1; + while (1) { + switch (*cp) + { + case '\"': + *out = '\0'; + if (size_out) *size_out = out - *result; + return cp+1; + + /* LCOV_EXCL_START -- we caught this in parse_config_from_line. */ + case '\0': + tor_fragile_assert(); + tor_free(*result); + return NULL; + /* LCOV_EXCL_STOP */ + case '\\': + switch (cp[1]) + { + case 'n': *out++ = '\n'; cp += 2; break; + case 'r': *out++ = '\r'; cp += 2; break; + case 't': *out++ = '\t'; cp += 2; break; + case 'x': case 'X': + { + int x1, x2; + + x1 = hex_decode_digit(cp[2]); + x2 = hex_decode_digit(cp[3]); + if (x1 == -1 || x2 == -1) { + /* LCOV_EXCL_START */ + /* we caught this above in the initial loop. */ + tor_assert_nonfatal_unreached(); + tor_free(*result); + return NULL; + /* LCOV_EXCL_STOP */ + } + + *out++ = ((x1<<4) + x2); + cp += 4; + } + break; + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': + { + int n = cp[1]-'0'; + cp += 2; + if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; } + if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; } + if (n > 255) { tor_free(*result); return NULL; } + *out++ = (char)n; + } + break; + case '\'': + case '\"': + case '\\': + case '\?': + *out++ = cp[1]; + cp += 2; + break; + + /* LCOV_EXCL_START */ + default: + /* we caught this above in the initial loop. */ + tor_assert_nonfatal_unreached(); + tor_free(*result); return NULL; + /* LCOV_EXCL_STOP */ + } + break; + default: + *out++ = *cp++; + } + } +} diff --git a/src/lib/encoding/cstring.h b/src/lib/encoding/cstring.h new file mode 100644 index 0000000000..3dff5e7f7f --- /dev/null +++ b/src/lib/encoding/cstring.h @@ -0,0 +1,13 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_CSTRING_H +#define TOR_CSTRING_H + +#include <stddef.h> +const char *unescape_string(const char *s, char **result, size_t *size_out); + +#endif /* !defined(TOR_CSTRING_H) */ diff --git a/src/lib/encoding/include.am b/src/lib/encoding/include.am new file mode 100644 index 0000000000..cf9fb1b259 --- /dev/null +++ b/src/lib/encoding/include.am @@ -0,0 +1,24 @@ +noinst_LIBRARIES += src/lib/libtor-encoding.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-encoding-testing.a +endif + +src_lib_libtor_encoding_a_SOURCES = \ + src/lib/encoding/binascii.c \ + src/lib/encoding/confline.c \ + src/lib/encoding/cstring.c \ + src/lib/encoding/keyval.c \ + src/lib/encoding/time_fmt.c + +src_lib_libtor_encoding_testing_a_SOURCES = \ + $(src_lib_libtor_encoding_a_SOURCES) +src_lib_libtor_encoding_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_encoding_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/encoding/binascii.h \ + src/lib/encoding/confline.h \ + src/lib/encoding/cstring.h \ + src/lib/encoding/keyval.h \ + src/lib/encoding/time_fmt.h diff --git a/src/lib/encoding/keyval.c b/src/lib/encoding/keyval.c new file mode 100644 index 0000000000..cffd6f6dbc --- /dev/null +++ b/src/lib/encoding/keyval.c @@ -0,0 +1,46 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/encoding/keyval.h" +#include "lib/log/escape.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +#include <stdlib.h> +#include <string.h> + +/** Return true if <b>string</b> is a valid 'key=[value]' string. + * "value" is optional, to indicate the empty string. Log at logging + * <b>severity</b> if something ugly happens. */ +int +string_is_key_value(int severity, const char *string) +{ + /* position of equal sign in string */ + const char *equal_sign_pos = NULL; + + tor_assert(string); + + if (strlen(string) < 2) { /* "x=" is shortest args string */ + tor_log(severity, LD_GENERAL, "'%s' is too short to be a k=v value.", + escaped(string)); + return 0; + } + + equal_sign_pos = strchr(string, '='); + if (!equal_sign_pos) { + tor_log(severity, LD_GENERAL, "'%s' is not a k=v value.", escaped(string)); + return 0; + } + + /* validate that the '=' is not in the beginning of the string. */ + if (equal_sign_pos == string) { + tor_log(severity, LD_GENERAL, "'%s' is not a valid k=v value.", + escaped(string)); + return 0; + } + + return 1; +} diff --git a/src/lib/encoding/keyval.h b/src/lib/encoding/keyval.h new file mode 100644 index 0000000000..7458555207 --- /dev/null +++ b/src/lib/encoding/keyval.h @@ -0,0 +1,11 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_KEYVAL_H +#define TOR_KEYVAL_H + +int string_is_key_value(int severity, const char *string); + +#endif diff --git a/src/lib/encoding/time_fmt.c b/src/lib/encoding/time_fmt.c new file mode 100644 index 0000000000..ef60f17e36 --- /dev/null +++ b/src/lib/encoding/time_fmt.c @@ -0,0 +1,493 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/encoding/time_fmt.h" +#include "lib/log/torlog.h" +#include "lib/log/escape.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/printf.h" +#include "lib/string/scanf.h" +#include "lib/wallclock/tm_cvt.h" + +#include <string.h> +#include <time.h> + +/** As localtime_r, but defined for platforms that don't have it: + * + * Convert *<b>timep</b> to a struct tm in local time, and store the value in + * *<b>result</b>. Return the result on success, or NULL on failure. + */ +struct tm * +tor_localtime_r(const time_t *timep, struct tm *result) +{ + char *err = NULL; + struct tm *r = tor_localtime_r_msg(timep, result, &err); + if (err) { + log_warn(LD_BUG, "%s", err); + tor_free(err); + } + return r; +} + +/** As gmtime_r, but defined for platforms that don't have it: + * + * Convert *<b>timep</b> to a struct tm in UTC, and store the value in + * *<b>result</b>. Return the result on success, or NULL on failure. + */ +struct tm * +tor_gmtime_r(const time_t *timep, struct tm *result) +{ + char *err = NULL; + struct tm *r = tor_gmtime_r_msg(timep, result, &err); + if (err) { + log_warn(LD_BUG, "%s", err); + tor_free(err); + } + return r; +} + +/** Yield true iff <b>y</b> is a leap-year. */ +#define IS_LEAPYEAR(y) (!(y % 4) && ((y % 100) || !(y % 400))) +/** Helper: Return the number of leap-days between Jan 1, y1 and Jan 1, y2. */ +static int +n_leapdays(int year1, int year2) +{ + --year1; + --year2; + return (year2/4 - year1/4) - (year2/100 - year1/100) + + (year2/400 - year1/400); +} +/** Number of days per month in non-leap year; used by tor_timegm and + * parse_rfc1123_time. */ +static const int days_per_month[] = + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/** Compute a time_t given a struct tm. The result is given in UTC, and + * does not account for leap seconds. Return 0 on success, -1 on failure. + */ +int +tor_timegm(const struct tm *tm, time_t *time_out) +{ + /* This is a pretty ironclad timegm implementation, snarfed from Python2.2. + * It's way more brute-force than fiddling with tzset(). + * + * We use int64_t rather than time_t to avoid overflow on multiplication on + * platforms with 32-bit time_t. Since year is clipped to INT32_MAX, and + * since 365 * 24 * 60 * 60 is approximately 31 million, it's not possible + * for INT32_MAX years to overflow int64_t when converted to seconds. */ + int64_t year, days, hours, minutes, seconds; + int i, invalid_year, dpm; + + /* Initialize time_out to 0 for now, to avoid bad usage in case this function + fails and the caller ignores the return value. */ + tor_assert(time_out); + *time_out = 0; + + /* avoid int overflow on addition */ + if (tm->tm_year < INT32_MAX-1900) { + year = tm->tm_year + 1900; + } else { + /* clamp year */ + year = INT32_MAX; + } + invalid_year = (year < 1970 || tm->tm_year >= INT32_MAX-1900); + + if (tm->tm_mon >= 0 && tm->tm_mon <= 11) { + dpm = days_per_month[tm->tm_mon]; + if (tm->tm_mon == 1 && !invalid_year && IS_LEAPYEAR(tm->tm_year)) { + dpm = 29; + } + } else { + /* invalid month - default to 0 days per month */ + dpm = 0; + } + + if (invalid_year || + tm->tm_mon < 0 || tm->tm_mon > 11 || + tm->tm_mday < 1 || tm->tm_mday > dpm || + tm->tm_hour < 0 || tm->tm_hour > 23 || + tm->tm_min < 0 || tm->tm_min > 59 || + tm->tm_sec < 0 || tm->tm_sec > 60) { + log_warn(LD_BUG, "Out-of-range argument to tor_timegm"); + return -1; + } + days = 365 * (year-1970) + n_leapdays(1970,(int)year); + for (i = 0; i < tm->tm_mon; ++i) + days += days_per_month[i]; + if (tm->tm_mon > 1 && IS_LEAPYEAR(year)) + ++days; + days += tm->tm_mday - 1; + hours = days*24 + tm->tm_hour; + + minutes = hours*60 + tm->tm_min; + seconds = minutes*60 + tm->tm_sec; + /* Check that "seconds" will fit in a time_t. On platforms where time_t is + * 32-bit, this check will fail for dates in and after 2038. + * + * We already know that "seconds" can't be negative because "year" >= 1970 */ +#if SIZEOF_TIME_T < 8 + if (seconds < TIME_MIN || seconds > TIME_MAX) { + log_warn(LD_BUG, "Result does not fit in tor_timegm"); + return -1; + } +#endif /* SIZEOF_TIME_T < 8 */ + *time_out = (time_t)seconds; + return 0; +} + +/* strftime is locale-specific, so we need to replace those parts */ + +/** A c-locale array of 3-letter names of weekdays, starting with Sun. */ +static const char *WEEKDAY_NAMES[] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +/** A c-locale array of 3-letter names of months, starting with Jan. */ +static const char *MONTH_NAMES[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +/** Set <b>buf</b> to the RFC1123 encoding of the UTC value of <b>t</b>. + * The buffer must be at least RFC1123_TIME_LEN+1 bytes long. + * + * (RFC1123 format is "Fri, 29 Sep 2006 15:54:20 GMT". Note the "GMT" + * rather than "UTC".) + */ +void +format_rfc1123_time(char *buf, time_t t) +{ + struct tm tm; + + tor_gmtime_r(&t, &tm); + + strftime(buf, RFC1123_TIME_LEN+1, "___, %d ___ %Y %H:%M:%S GMT", &tm); + tor_assert(tm.tm_wday >= 0); + tor_assert(tm.tm_wday <= 6); + memcpy(buf, WEEKDAY_NAMES[tm.tm_wday], 3); + tor_assert(tm.tm_mon >= 0); + tor_assert(tm.tm_mon <= 11); + memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3); +} + +/** Parse the (a subset of) the RFC1123 encoding of some time (in UTC) from + * <b>buf</b>, and store the result in *<b>t</b>. + * + * Note that we only accept the subset generated by format_rfc1123_time above, + * not the full range of formats suggested by RFC 1123. + * + * Return 0 on success, -1 on failure. +*/ +int +parse_rfc1123_time(const char *buf, time_t *t) +{ + struct tm tm; + char month[4]; + char weekday[4]; + int i, m, invalid_year; + unsigned tm_mday, tm_year, tm_hour, tm_min, tm_sec; + unsigned dpm; + + if (strlen(buf) != RFC1123_TIME_LEN) + return -1; + memset(&tm, 0, sizeof(tm)); + if (tor_sscanf(buf, "%3s, %2u %3s %u %2u:%2u:%2u GMT", weekday, + &tm_mday, month, &tm_year, &tm_hour, + &tm_min, &tm_sec) < 7) { + char *esc = esc_for_log(buf); + log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc); + tor_free(esc); + return -1; + } + + m = -1; + for (i = 0; i < 12; ++i) { + if (!strcmp(month, MONTH_NAMES[i])) { + m = i; + break; + } + } + if (m<0) { + char *esc = esc_for_log(buf); + log_warn(LD_GENERAL, "Got invalid RFC1123 time %s: No such month", esc); + tor_free(esc); + return -1; + } + tm.tm_mon = m; + + invalid_year = (tm_year >= INT32_MAX || tm_year < 1970); + tor_assert(m >= 0 && m <= 11); + dpm = days_per_month[m]; + if (m == 1 && !invalid_year && IS_LEAPYEAR(tm_year)) { + dpm = 29; + } + + if (invalid_year || tm_mday < 1 || tm_mday > dpm || + tm_hour > 23 || tm_min > 59 || tm_sec > 60) { + char *esc = esc_for_log(buf); + log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc); + tor_free(esc); + return -1; + } + tm.tm_mday = (int)tm_mday; + tm.tm_year = (int)tm_year; + tm.tm_hour = (int)tm_hour; + tm.tm_min = (int)tm_min; + tm.tm_sec = (int)tm_sec; + + if (tm.tm_year < 1970) { + /* LCOV_EXCL_START + * XXXX I think this is dead code; we already checked for + * invalid_year above. */ + tor_assert_nonfatal_unreached(); + char *esc = esc_for_log(buf); + log_warn(LD_GENERAL, + "Got invalid RFC1123 time %s. (Before 1970)", esc); + tor_free(esc); + return -1; + /* LCOV_EXCL_STOP */ + } + tm.tm_year -= 1900; + + return tor_timegm(&tm, t); +} + +/** Set <b>buf</b> to the ISO8601 encoding of the local value of <b>t</b>. + * The buffer must be at least ISO_TIME_LEN+1 bytes long. + * + * (ISO8601 format is 2006-10-29 10:57:20) + */ +void +format_local_iso_time(char *buf, time_t t) +{ + struct tm tm; + strftime(buf, ISO_TIME_LEN+1, "%Y-%m-%d %H:%M:%S", tor_localtime_r(&t, &tm)); +} + +/** Set <b>buf</b> to the ISO8601 encoding of the GMT value of <b>t</b>. + * The buffer must be at least ISO_TIME_LEN+1 bytes long. + */ +void +format_iso_time(char *buf, time_t t) +{ + struct tm tm; + strftime(buf, ISO_TIME_LEN+1, "%Y-%m-%d %H:%M:%S", tor_gmtime_r(&t, &tm)); +} + +/** As format_local_iso_time, but use the yyyy-mm-ddThh:mm:ss format to avoid + * embedding an internal space. */ +void +format_local_iso_time_nospace(char *buf, time_t t) +{ + format_local_iso_time(buf, t); + buf[10] = 'T'; +} + +/** As format_iso_time, but use the yyyy-mm-ddThh:mm:ss format to avoid + * embedding an internal space. */ +void +format_iso_time_nospace(char *buf, time_t t) +{ + format_iso_time(buf, t); + buf[10] = 'T'; +} + +/** As format_iso_time_nospace, but include microseconds in decimal + * fixed-point format. Requires that buf be at least ISO_TIME_USEC_LEN+1 + * bytes long. */ +void +format_iso_time_nospace_usec(char *buf, const struct timeval *tv) +{ + tor_assert(tv); + format_iso_time_nospace(buf, (time_t)tv->tv_sec); + tor_snprintf(buf+ISO_TIME_LEN, 8, ".%06d", (int)tv->tv_usec); +} + +/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>, + * parse it and store its value in *<b>t</b>. Return 0 on success, -1 on + * failure. Ignore extraneous stuff in <b>cp</b> after the end of the time + * string, unless <b>strict</b> is set. If <b>nospace</b> is set, + * expect the YYYY-MM-DDTHH:MM:SS format. */ +int +parse_iso_time_(const char *cp, time_t *t, int strict, int nospace) +{ + struct tm st_tm; + unsigned int year=0, month=0, day=0, hour=0, minute=0, second=0; + int n_fields; + char extra_char, separator_char; + n_fields = tor_sscanf(cp, "%u-%2u-%2u%c%2u:%2u:%2u%c", + &year, &month, &day, + &separator_char, + &hour, &minute, &second, &extra_char); + if (strict ? (n_fields != 7) : (n_fields < 7)) { + char *esc = esc_for_log(cp); + log_warn(LD_GENERAL, "ISO time %s was unparseable", esc); + tor_free(esc); + return -1; + } + if (separator_char != (nospace ? 'T' : ' ')) { + char *esc = esc_for_log(cp); + log_warn(LD_GENERAL, "ISO time %s was unparseable", esc); + tor_free(esc); + return -1; + } + if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || + hour > 23 || minute > 59 || second > 60 || year >= INT32_MAX) { + char *esc = esc_for_log(cp); + log_warn(LD_GENERAL, "ISO time %s was nonsensical", esc); + tor_free(esc); + return -1; + } + st_tm.tm_year = (int)year-1900; + st_tm.tm_mon = month-1; + st_tm.tm_mday = day; + st_tm.tm_hour = hour; + st_tm.tm_min = minute; + st_tm.tm_sec = second; + st_tm.tm_wday = 0; /* Should be ignored. */ + + if (st_tm.tm_year < 70) { + /* LCOV_EXCL_START + * XXXX I think this is dead code; we already checked for + * year < 1970 above. */ + tor_assert_nonfatal_unreached(); + char *esc = esc_for_log(cp); + log_warn(LD_GENERAL, "Got invalid ISO time %s. (Before 1970)", esc); + tor_free(esc); + return -1; + /* LCOV_EXCL_STOP */ + } + return tor_timegm(&st_tm, t); +} + +/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>, + * parse it and store its value in *<b>t</b>. Return 0 on success, -1 on + * failure. Reject the string if any characters are present after the time. + */ +int +parse_iso_time(const char *cp, time_t *t) +{ + return parse_iso_time_(cp, t, 1, 0); +} + +/** + * As parse_iso_time, but parses a time encoded by format_iso_time_nospace(). + */ +int +parse_iso_time_nospace(const char *cp, time_t *t) +{ + return parse_iso_time_(cp, t, 1, 1); +} + +/** Given a <b>date</b> in one of the three formats allowed by HTTP (ugh), + * parse it into <b>tm</b>. Return 0 on success, negative on failure. */ +int +parse_http_time(const char *date, struct tm *tm) +{ + const char *cp; + char month[4]; + char wkday[4]; + int i; + unsigned tm_mday, tm_year, tm_hour, tm_min, tm_sec; + + tor_assert(tm); + memset(tm, 0, sizeof(*tm)); + + /* First, try RFC1123 or RFC850 format: skip the weekday. */ + if ((cp = strchr(date, ','))) { + ++cp; + if (*cp != ' ') + return -1; + ++cp; + if (tor_sscanf(cp, "%2u %3s %4u %2u:%2u:%2u GMT", + &tm_mday, month, &tm_year, + &tm_hour, &tm_min, &tm_sec) == 6) { + /* rfc1123-date */ + tm_year -= 1900; + } else if (tor_sscanf(cp, "%2u-%3s-%2u %2u:%2u:%2u GMT", + &tm_mday, month, &tm_year, + &tm_hour, &tm_min, &tm_sec) == 6) { + /* rfc850-date */ + } else { + return -1; + } + } else { + /* No comma; possibly asctime() format. */ + if (tor_sscanf(date, "%3s %3s %2u %2u:%2u:%2u %4u", + wkday, month, &tm_mday, + &tm_hour, &tm_min, &tm_sec, &tm_year) == 7) { + tm_year -= 1900; + } else { + return -1; + } + } + tm->tm_mday = (int)tm_mday; + tm->tm_year = (int)tm_year; + tm->tm_hour = (int)tm_hour; + tm->tm_min = (int)tm_min; + tm->tm_sec = (int)tm_sec; + tm->tm_wday = 0; /* Leave this unset. */ + + month[3] = '\0'; + /* Okay, now decode the month. */ + /* set tm->tm_mon to dummy value so the check below fails. */ + tm->tm_mon = -1; + for (i = 0; i < 12; ++i) { + if (!strcasecmp(MONTH_NAMES[i], month)) { + tm->tm_mon = i; + } + } + + if (tm->tm_year < 0 || + tm->tm_mon < 0 || tm->tm_mon > 11 || + tm->tm_mday < 1 || tm->tm_mday > 31 || + tm->tm_hour < 0 || tm->tm_hour > 23 || + tm->tm_min < 0 || tm->tm_min > 59 || + tm->tm_sec < 0 || tm->tm_sec > 60) + return -1; /* Out of range, or bad month. */ + + return 0; +} + +/** Given an <b>interval</b> in seconds, try to write it to the + * <b>out_len</b>-byte buffer in <b>out</b> in a human-readable form. + * Returns a non-negative integer on success, -1 on failure. + */ +int +format_time_interval(char *out, size_t out_len, long interval) +{ + /* We only report seconds if there's no hours. */ + long sec = 0, min = 0, hour = 0, day = 0; + + /* -LONG_MIN is LONG_MAX + 1, which causes signed overflow */ + if (interval < -LONG_MAX) + interval = LONG_MAX; + else if (interval < 0) + interval = -interval; + + if (interval >= 86400) { + day = interval / 86400; + interval %= 86400; + } + if (interval >= 3600) { + hour = interval / 3600; + interval %= 3600; + } + if (interval >= 60) { + min = interval / 60; + interval %= 60; + } + sec = interval; + + if (day) { + return tor_snprintf(out, out_len, "%ld days, %ld hours, %ld minutes", + day, hour, min); + } else if (hour) { + return tor_snprintf(out, out_len, "%ld hours, %ld minutes", hour, min); + } else if (min) { + return tor_snprintf(out, out_len, "%ld minutes, %ld seconds", min, sec); + } else { + return tor_snprintf(out, out_len, "%ld seconds", sec); + } +} diff --git a/src/lib/encoding/time_fmt.h b/src/lib/encoding/time_fmt.h new file mode 100644 index 0000000000..41508ce5e6 --- /dev/null +++ b/src/lib/encoding/time_fmt.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_TIME_FMT_H +#define TOR_TIME_FMT_H + +#include "orconfig.h" +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +struct tm; +struct timeval; + +struct tm *tor_localtime_r(const time_t *timep, struct tm *result); +struct tm *tor_gmtime_r(const time_t *timep, struct tm *result); +int tor_timegm(const struct tm *tm, time_t *time_out); + +#define RFC1123_TIME_LEN 29 +void format_rfc1123_time(char *buf, time_t t); +int parse_rfc1123_time(const char *buf, time_t *t); +#define ISO_TIME_LEN 19 +#define ISO_TIME_USEC_LEN (ISO_TIME_LEN+7) +void format_local_iso_time(char *buf, time_t t); +void format_iso_time(char *buf, time_t t); +void format_local_iso_time_nospace(char *buf, time_t t); +void format_iso_time_nospace(char *buf, time_t t); +void format_iso_time_nospace_usec(char *buf, const struct timeval *tv); +int parse_iso_time_(const char *cp, time_t *t, int strict, int nospace); +int parse_iso_time(const char *buf, time_t *t); +int parse_iso_time_nospace(const char *cp, time_t *t); +int parse_http_time(const char *buf, struct tm *tm); +int format_time_interval(char *out, size_t out_len, long interval); + +#endif diff --git a/src/lib/err/.may_include b/src/lib/err/.may_include new file mode 100644 index 0000000000..48cc0ef088 --- /dev/null +++ b/src/lib/err/.may_include @@ -0,0 +1,3 @@ +orconfig.h +lib/cc/*.h +lib/err/*.h diff --git a/src/common/backtrace.c b/src/lib/err/backtrace.c index f2498b2aa6..cded6459f7 100644 --- a/src/common/backtrace.c +++ b/src/lib/err/backtrace.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,9 +14,7 @@ */ #include "orconfig.h" -#include "compat.h" -#include "util.h" -#include "torlog.h" +#include "lib/err/torerr.h" #ifdef HAVE_EXECINFO_H #include <execinfo.h> @@ -30,6 +28,9 @@ #ifdef HAVE_SIGNAL_H #include <signal.h> #endif +#include <errno.h> +#include <stdlib.h> +#include <string.h> #ifdef HAVE_CYGWIN_SIGNAL_H #include <cygwin/signal.h> @@ -39,8 +40,13 @@ #include <ucontext.h> #endif /* defined(HAVE_CYGWIN_SIGNAL_H) || ... */ +#ifdef HAVE_PTHREAD_H +#include <pthread.h> +#endif + #define EXPOSE_CLEAN_BACKTRACE -#include "backtrace.h" +#include "lib/err/backtrace.h" +#include "lib/err/torerr.h" #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) @@ -51,17 +57,21 @@ #define NO_BACKTRACE_IMPL #endif -/** Version of Tor to report in backtrace messages. */ -static char *bt_version = NULL; +// Redundant with util.h, but doing it here so we can avoid that dependency. +#define raw_free free #ifdef USE_BACKTRACE +/** Version of Tor to report in backtrace messages. */ +static char bt_version[128] = ""; + /** Largest stack depth to try to dump. */ #define MAX_DEPTH 256 /** Static allocation of stack to dump. This is static so we avoid stack * pressure. */ static void *cb_buf[MAX_DEPTH]; -/** Protects cb_buf from concurrent access */ -static tor_mutex_t cb_buf_mutex; +/** Protects cb_buf from concurrent access. Pthreads, since this code + * is Unix-only, and since this code needs to be lowest-level. */ +static pthread_mutex_t cb_buf_mutex = PTHREAD_MUTEX_INITIALIZER; /** Change a stacktrace in <b>stack</b> of depth <b>depth</b> so that it will * log the correct function from which a signal was received with context @@ -94,33 +104,35 @@ clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx) } /** Log a message <b>msg</b> at <b>severity</b> in <b>domain</b>, and follow - * that with a backtrace log. */ + * that with a backtrace log. Send messages via the tor_log function at + * logger". */ void -log_backtrace(int severity, int domain, const char *msg) +log_backtrace_impl(int severity, int domain, const char *msg, + tor_log_fn logger) { size_t depth; char **symbols; size_t i; - tor_mutex_acquire(&cb_buf_mutex); + pthread_mutex_lock(&cb_buf_mutex); depth = backtrace(cb_buf, MAX_DEPTH); symbols = backtrace_symbols(cb_buf, (int)depth); - tor_log(severity, domain, "%s. Stack trace:", msg); + logger(severity, domain, "%s. Stack trace:", msg); if (!symbols) { /* LCOV_EXCL_START -- we can't provoke this. */ - tor_log(severity, domain, " Unable to generate backtrace."); + logger(severity, domain, " Unable to generate backtrace."); goto done; /* LCOV_EXCL_STOP */ } for (i=0; i < depth; ++i) { - tor_log(severity, domain, " %s", symbols[i]); + logger(severity, domain, " %s", symbols[i]); } raw_free(symbols); done: - tor_mutex_release(&cb_buf_mutex); + pthread_mutex_unlock(&cb_buf_mutex); } static void crash_handler(int sig, siginfo_t *si, void *ctx_) @@ -155,18 +167,34 @@ crash_handler(int sig, siginfo_t *si, void *ctx_) abort(); } +/** Write a backtrace to all of the emergency-error fds. */ +void +dump_stack_symbols_to_error_fds(void) +{ + int n_fds, i; + const int *fds = NULL; + size_t depth; + + depth = backtrace(cb_buf, MAX_DEPTH); + + n_fds = tor_log_get_sigsafe_err_fds(&fds); + for (i=0; i < n_fds; ++i) + backtrace_symbols_fd(cb_buf, (int)depth, fds[i]); +} + /** Install signal handlers as needed so that when we crash, we produce a - * useful stack trace. Return 0 on success, -1 on failure. */ + * useful stack trace. Return 0 on success, -errno on failure. */ static int -install_bt_handler(void) +install_bt_handler(const char *software) { int trap_signals[] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS, SIGIO, -1 }; int i, rv=0; - struct sigaction sa; + strncpy(bt_version, software, sizeof(bt_version) - 1); + bt_version[sizeof(bt_version) - 1] = 0; - tor_mutex_init(&cb_buf_mutex); + struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = crash_handler; @@ -176,8 +204,7 @@ install_bt_handler(void) for (i = 0; trap_signals[i] >= 0; ++i) { if (sigaction(trap_signals[i], &sa, NULL) == -1) { /* LCOV_EXCL_START */ - log_warn(LD_BUG, "Sigaction failed: %s", strerror(errno)); - rv = -1; + rv = -errno; /* LCOV_EXCL_STOP */ } } @@ -200,20 +227,21 @@ install_bt_handler(void) static void remove_bt_handler(void) { - tor_mutex_uninit(&cb_buf_mutex); } #endif /* defined(USE_BACKTRACE) */ #ifdef NO_BACKTRACE_IMPL void -log_backtrace(int severity, int domain, const char *msg) +log_backtrace_impl(int severity, int domain, const char *msg, + tor_log_fn logger) { - tor_log(severity, domain, "%s. (Stack trace not available)", msg); + logger(severity, domain, "%s. (Stack trace not available)", msg); } static int -install_bt_handler(void) +install_bt_handler(const char *software) { + (void) software; return 0; } @@ -221,19 +249,28 @@ static void remove_bt_handler(void) { } + +void +dump_stack_symbols_to_error_fds(void) +{ +} #endif /* defined(NO_BACKTRACE_IMPL) */ /** Set up code to handle generating error messages on crashes. */ int configure_backtrace_handler(const char *tor_version) { - tor_free(bt_version); - if (tor_version) - tor_asprintf(&bt_version, "Tor %s", tor_version); - else - tor_asprintf(&bt_version, "Tor"); + char version[128]; + strncpy(version, "Tor", sizeof(version)-1); + + if (tor_version) { + strncat(version, " ", sizeof(version)-1); + strncat(version, tor_version, sizeof(version)-1); + } - return install_bt_handler(); + version[sizeof(version) - 1] = 0; + + return install_bt_handler(version); } /** Perform end-of-process cleanup for code that generates error messages on @@ -242,7 +279,4 @@ void clean_up_backtrace_handler(void) { remove_bt_handler(); - - tor_free(bt_version); } - diff --git a/src/common/backtrace.h b/src/lib/err/backtrace.h index 3d0ab8a90a..7f77428436 100644 --- a/src/common/backtrace.h +++ b/src/lib/err/backtrace.h @@ -1,14 +1,23 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_BACKTRACE_H #define TOR_BACKTRACE_H #include "orconfig.h" +#include "lib/cc/compat_compiler.h" -void log_backtrace(int severity, int domain, const char *msg); +typedef void (*tor_log_fn)(int, unsigned, const char *fmt, ...) + CHECK_PRINTF(3,4); + +void log_backtrace_impl(int severity, int domain, const char *msg, + tor_log_fn logger); int configure_backtrace_handler(const char *tor_version); void clean_up_backtrace_handler(void); +void dump_stack_symbols_to_error_fds(void); + +#define log_backtrace(sev, dom, msg) \ + log_backtrace_impl((sev), (dom), (msg), tor_log) #ifdef EXPOSE_CLEAN_BACKTRACE #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ @@ -18,4 +27,3 @@ void clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx); #endif /* defined(EXPOSE_CLEAN_BACKTRACE) */ #endif /* !defined(TOR_BACKTRACE_H) */ - diff --git a/src/lib/err/include.am b/src/lib/err/include.am new file mode 100644 index 0000000000..f2a409c51e --- /dev/null +++ b/src/lib/err/include.am @@ -0,0 +1,19 @@ + +noinst_LIBRARIES += src/lib/libtor-err.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-err-testing.a +endif + +src_lib_libtor_err_a_SOURCES = \ + src/lib/err/backtrace.c \ + src/lib/err/torerr.c + +src_lib_libtor_err_testing_a_SOURCES = \ + $(src_lib_libtor_err_a_SOURCES) +src_lib_libtor_err_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_err_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/err/backtrace.h \ + src/lib/err/torerr.h diff --git a/src/lib/err/torerr.c b/src/lib/err/torerr.c new file mode 100644 index 0000000000..8d8f694f1d --- /dev/null +++ b/src/lib/err/torerr.c @@ -0,0 +1,230 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file torerr.c + * + * \brief Handling code for unrecoverable emergencies, at a lower level + * than the logging code. + */ + +#include "orconfig.h" +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_TIME_H +#include <time.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#include "lib/err/torerr.h" +#include "lib/err/backtrace.h" + +/** Array of fds to log crash-style warnings to. */ +static int sigsafe_log_fds[TOR_SIGSAFE_LOG_MAX_FDS] = { STDERR_FILENO }; +/** The number of elements used in sigsafe_log_fds */ +static int n_sigsafe_log_fds = 1; +/** Log granularity in milliseconds. */ +static int log_granularity = 1000; + +/** Write <b>s</b> to each element of sigsafe_log_fds. Return 0 on success, -1 + * on failure. */ +static int +tor_log_err_sigsafe_write(const char *s) +{ + int i; + ssize_t r; + size_t len = strlen(s); + int err = 0; + for (i=0; i < n_sigsafe_log_fds; ++i) { + r = write(sigsafe_log_fds[i], s, len); + err += (r != (ssize_t)len); + } + return err ? -1 : 0; +} + +/** Given a list of string arguments ending with a NULL, writes them + * to our logs and to stderr (if possible). This function is safe to call + * from within a signal handler. */ +void +tor_log_err_sigsafe(const char *m, ...) +{ + va_list ap; + const char *x; + char timebuf[33]; + time_t now = time(NULL); + + if (!m) + return; + if (log_granularity >= 2000) { + int g = log_granularity / 1000; + now -= now % g; + } + timebuf[0] = now < 0 ? '-' : ' '; + if (now < 0) now = -now; + timebuf[1] = '\0'; + format_dec_number_sigsafe(now, timebuf+1, sizeof(timebuf)-1); + tor_log_err_sigsafe_write("\n==========================================" + "================== T="); + tor_log_err_sigsafe_write(timebuf); + tor_log_err_sigsafe_write("\n"); + tor_log_err_sigsafe_write(m); + va_start(ap, m); + while ((x = va_arg(ap, const char*))) { + tor_log_err_sigsafe_write(x); + } + va_end(ap); +} + +/** Set *<b>out</b> to a pointer to an array of the fds to log errors to from + * inside a signal handler or other emergency condition. Return the number of + * elements in the array. */ +int +tor_log_get_sigsafe_err_fds(const int **out) +{ + *out = sigsafe_log_fds; + return n_sigsafe_log_fds; +} + +/** + * Update the list of fds that get errors from inside a signal handler or + * other emergency condition. Ignore any beyond the first + * TOR_SIGSAFE_LOG_MAX_FDS. + */ +void +tor_log_set_sigsafe_err_fds(const int *fds, int n) +{ + if (n > TOR_SIGSAFE_LOG_MAX_FDS) { + n = TOR_SIGSAFE_LOG_MAX_FDS; + } + + memcpy(sigsafe_log_fds, fds, n * sizeof(int)); + n_sigsafe_log_fds = n; +} + +/** + * Set the granularity (in ms) to use when reporting fatal errors outside + * the logging system. + */ +void +tor_log_sigsafe_err_set_granularity(int ms) +{ + log_granularity = ms; +} + +/** + * Log an emergency assertion failure message. + * + * This kind of message is safe to send from within a log handler, + * a signal handler, or other emergency situation. + */ +void +tor_raw_assertion_failed_msg_(const char *file, int line, const char *expr, + const char *msg) +{ + char linebuf[16]; + format_dec_number_sigsafe(line, linebuf, sizeof(linebuf)); + tor_log_err_sigsafe("INTERNAL ERROR: Raw assertion failed at ", + file, ":", linebuf, ": ", expr, NULL); + if (msg) { + tor_log_err_sigsafe_write(msg); + tor_log_err_sigsafe_write("\n"); + } + + dump_stack_symbols_to_error_fds(); +} + +/* As format_{hex,dex}_number_sigsafe, but takes a <b>radix</b> argument + * in range 2..16 inclusive. */ +static int +format_number_sigsafe(unsigned long x, char *buf, int buf_len, + unsigned int radix) +{ + unsigned long tmp; + int len; + char *cp; + + /* NOT tor_assert. This needs to be safe to run from within a signal + * handler, and from within the 'tor_assert() has failed' code. Not even + * raw_assert(), since raw_assert() calls this function on failure. */ + if (radix < 2 || radix > 16) + return 0; + + /* Count how many digits we need. */ + tmp = x; + len = 1; + while (tmp >= radix) { + tmp /= radix; + ++len; + } + + /* Not long enough */ + if (!buf || len >= buf_len) + return 0; + + cp = buf + len; + *cp = '\0'; + do { + unsigned digit = (unsigned) (x % radix); + if (cp <= buf) { + /* Not tor_assert(); see above. */ + abort(); + } + --cp; + *cp = "0123456789ABCDEF"[digit]; + x /= radix; + } while (x); + + /* NOT tor_assert; see above. */ + if (cp != buf) { + abort(); // LCOV_EXCL_LINE + } + + return len; +} + +/** + * Helper function to output hex numbers from within a signal handler. + * + * Writes the nul-terminated hexadecimal digits of <b>x</b> into a buffer + * <b>buf</b> of size <b>buf_len</b>, and return the actual number of digits + * written, not counting the terminal NUL. + * + * If there is insufficient space, write nothing and return 0. + * + * This accepts an unsigned int because format_helper_exit_status() needs to + * call it with a signed int and an unsigned char, and since the C standard + * does not guarantee that an int is wider than a char (an int must be at + * least 16 bits but it is permitted for a char to be that wide as well), we + * can't assume a signed int is sufficient to accommodate an unsigned char. + * Thus, format_helper_exit_status() will still need to emit any require '-' + * on its own. + * + * For most purposes, you'd want to use tor_snprintf("%x") instead of this + * function; it's designed to be used in code paths where you can't call + * arbitrary C functions. + */ +int +format_hex_number_sigsafe(unsigned long x, char *buf, int buf_len) +{ + return format_number_sigsafe(x, buf, buf_len, 16); +} + +/** As format_hex_number_sigsafe, but format the number in base 10. */ +int +format_dec_number_sigsafe(unsigned long x, char *buf, int buf_len) +{ + return format_number_sigsafe(x, buf, buf_len, 10); +} diff --git a/src/lib/err/torerr.h b/src/lib/err/torerr.h new file mode 100644 index 0000000000..d4bba6916f --- /dev/null +++ b/src/lib/err/torerr.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file torerr.h + * + * \brief Headers for torerr.c. + **/ + +#ifndef TOR_TORERR_H +#define TOR_TORERR_H + +#include "lib/cc/compat_compiler.h" + +/* The raw_assert...() variants are for use within code that can't call + * tor_assertion_failed_() because of call circularity issues. */ +#define raw_assert(expr) STMT_BEGIN \ + if (!(expr)) { \ + tor_raw_assertion_failed_msg_(__FILE__, __LINE__, #expr, NULL); \ + abort(); \ + } \ + STMT_END +#define raw_assert_unreached(expr) raw_assert(0) +#define raw_assert_unreached_msg(msg) STMT_BEGIN \ + tor_raw_assertion_failed_msg_(__FILE__, __LINE__, "0", (msg)); \ + abort(); \ + STMT_END + +void tor_raw_assertion_failed_msg_(const char *file, int line, + const char *expr, + const char *msg); + +/** Maximum number of fds that will get notifications if we crash */ +#define TOR_SIGSAFE_LOG_MAX_FDS 8 + +void tor_log_err_sigsafe(const char *m, ...); +int tor_log_get_sigsafe_err_fds(const int **out); +void tor_log_set_sigsafe_err_fds(const int *fds, int n); +void tor_log_sigsafe_err_set_granularity(int ms); + +int format_hex_number_sigsafe(unsigned long x, char *buf, int max_len); +int format_dec_number_sigsafe(unsigned long x, char *buf, int max_len); + +#endif /* !defined(TOR_TORLOG_H) */ diff --git a/src/lib/fdio/.may_include b/src/lib/fdio/.may_include new file mode 100644 index 0000000000..30fd277b81 --- /dev/null +++ b/src/lib/fdio/.may_include @@ -0,0 +1,4 @@ +orconfig.h +lib/cc/*.h +lib/err/*.h +lib/fdio/*.h diff --git a/src/lib/fdio/fdio.c b/src/lib/fdio/fdio.c new file mode 100644 index 0000000000..21577e1845 --- /dev/null +++ b/src/lib/fdio/fdio.c @@ -0,0 +1,109 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef _WIN32 +#include <windows.h> +#endif + +#include "lib/fdio/fdio.h" +#include "lib/cc/torint.h" +#include "lib/err/torerr.h" + +#include <stdlib.h> + +/** @{ */ +/** Some old versions of Unix didn't define constants for these values, + * and instead expect you to say 0, 1, or 2. */ +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif +#ifndef SEEK_END +#define SEEK_END 2 +#endif +/** @} */ + +/** Return the position of <b>fd</b> with respect to the start of the file. */ +off_t +tor_fd_getpos(int fd) +{ +#ifdef _WIN32 + return (off_t) _lseek(fd, 0, SEEK_CUR); +#else + return (off_t) lseek(fd, 0, SEEK_CUR); +#endif +} + +/** Move <b>fd</b> to the end of the file. Return -1 on error, 0 on success. + * If the file is a pipe, do nothing and succeed. + **/ +int +tor_fd_seekend(int fd) +{ +#ifdef _WIN32 + return _lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; +#else + off_t rc = lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; +#ifdef ESPIPE + /* If we get an error and ESPIPE, then it's a pipe or a socket of a fifo: + * no need to worry. */ + if (rc < 0 && errno == ESPIPE) + rc = 0; +#endif /* defined(ESPIPE) */ + return (rc < 0) ? -1 : 0; +#endif /* defined(_WIN32) */ +} + +/** Move <b>fd</b> to position <b>pos</b> in the file. Return -1 on error, 0 + * on success. */ +int +tor_fd_setpos(int fd, off_t pos) +{ +#ifdef _WIN32 + return _lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; +#else + return lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; +#endif +} + +/** Replacement for ftruncate(fd, 0): move to the front of the file and remove + * all the rest of the file. Return -1 on error, 0 on success. */ +int +tor_ftruncate(int fd) +{ + /* Rumor has it that some versions of ftruncate do not move the file pointer. + */ + if (tor_fd_setpos(fd, 0) < 0) + return -1; + +#ifdef _WIN32 + return _chsize(fd, 0); +#else + return ftruncate(fd, 0); +#endif +} + +/** Minimal version of write_all, for use by logging. */ +int +write_all_to_fd_minimal(int fd, const char *buf, size_t count) +{ + size_t written = 0; + raw_assert(count < SSIZE_MAX); + + while (written < count) { + ssize_t result = write(fd, buf+written, count-written); + if (result<0) + return -1; + written += result; + } + return 0; +} diff --git a/src/lib/fdio/fdio.h b/src/lib/fdio/fdio.h new file mode 100644 index 0000000000..0fb3ed1e62 --- /dev/null +++ b/src/lib/fdio/fdio.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_FDIO_H +#define TOR_FDIO_H + +#include <stddef.h> + +off_t tor_fd_getpos(int fd); +int tor_fd_setpos(int fd, off_t pos); +int tor_fd_seekend(int fd); +int tor_ftruncate(int fd); +int write_all_to_fd_minimal(int fd, const char *buf, size_t count); + +#endif /* !defined(TOR_FDIO_H) */ diff --git a/src/lib/fdio/include.am b/src/lib/fdio/include.am new file mode 100644 index 0000000000..6c18f00a0d --- /dev/null +++ b/src/lib/fdio/include.am @@ -0,0 +1,17 @@ + +noinst_LIBRARIES += src/lib/libtor-fdio.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-fdio-testing.a +endif + +src_lib_libtor_fdio_a_SOURCES = \ + src/lib/fdio/fdio.c + +src_lib_libtor_fdio_testing_a_SOURCES = \ + $(src_lib_libtor_fdio_a_SOURCES) +src_lib_libtor_fdio_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_fdio_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/fdio/fdio.h diff --git a/src/lib/fs/.may_include b/src/lib/fs/.may_include new file mode 100644 index 0000000000..6c9ce6ca04 --- /dev/null +++ b/src/lib/fs/.may_include @@ -0,0 +1,13 @@ +orconfig.h +lib/cc/*.h +lib/container/*.h +lib/encoding/*.h +lib/err/*.h +lib/fdio/*.h +lib/fs/*.h +lib/log/*.h +lib/malloc/*.h +lib/memarea/*.h +lib/sandbox/*.h +lib/string/*.h +lib/testsupport/testsupport.h diff --git a/src/lib/fs/conffile.c b/src/lib/fs/conffile.c new file mode 100644 index 0000000000..37bd9f0368 --- /dev/null +++ b/src/lib/fs/conffile.c @@ -0,0 +1,168 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/fs/conffile.h" + +#include "lib/container/smartlist.h" +#include "lib/encoding/confline.h" +#include "lib/fs/dir.h" +#include "lib/fs/files.h" +#include "lib/fs/path.h" +#include "lib/log/torlog.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/printf.h" + +static smartlist_t *config_get_file_list(const char *path, + smartlist_t *opened_files); +static int config_get_included_config(const char *path, int recursion_level, + int extended, config_line_t **config, + config_line_t **config_last, + smartlist_t *opened_lst); +static int config_process_include(const char *path, int recursion_level, + int extended, config_line_t **list, + config_line_t **list_last, + smartlist_t *opened_lst); + +/** Helper: parse the config string and strdup into key/value + * strings. Set *result to the list, or NULL if parsing the string + * failed. Set *has_include to 1 if <b>result</b> has values from + * %included files. <b>opened_lst</b> will have a list of opened files if + * provided. Return 0 on success, -1 on failure. Warn and ignore any + * misformatted lines. + * + * If <b>extended</b> is set, then treat keys beginning with / and with + as + * indicating "clear" and "append" respectively. */ +int +config_get_lines_include(const char *string, config_line_t **result, + int extended, int *has_include, + smartlist_t *opened_lst) +{ + return config_get_lines_aux(string, result, extended, 1, has_include, + opened_lst, 1, NULL, config_process_include); +} + +/** Adds a list of configuration files present on <b>path</b> to + * <b>file_list</b>. <b>path</b> can be a file or a directory. If it is a file, + * only that file will be added to <b>file_list</b>. If it is a directory, + * all paths for files on that directory root (no recursion) except for files + * whose name starts with a dot will be added to <b>file_list</b>. + * <b>opened_files</b> will have a list of files opened by this function + * if provided. Return 0 on success, -1 on failure. Ignores empty files. + */ +static smartlist_t * +config_get_file_list(const char *path, smartlist_t *opened_files) +{ + smartlist_t *file_list = smartlist_new(); + + if (opened_files) { + smartlist_add_strdup(opened_files, path); + } + + file_status_t file_type = file_status(path); + if (file_type == FN_FILE) { + smartlist_add_strdup(file_list, path); + return file_list; + } else if (file_type == FN_DIR) { + smartlist_t *all_files = tor_listdir(path); + if (!all_files) { + smartlist_free(file_list); + return NULL; + } + smartlist_sort_strings(all_files); + SMARTLIST_FOREACH_BEGIN(all_files, char *, f) { + if (f[0] == '.') { + tor_free(f); + continue; + } + + char *fullname; + tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f); + tor_free(f); + + if (opened_files) { + smartlist_add_strdup(opened_files, fullname); + } + + if (file_status(fullname) != FN_FILE) { + tor_free(fullname); + continue; + } + smartlist_add(file_list, fullname); + } SMARTLIST_FOREACH_END(f); + smartlist_free(all_files); + return file_list; + } else if (file_type == FN_EMPTY) { + return file_list; + } else { + smartlist_free(file_list); + return NULL; + } +} + +/** Creates a list of config lines present on included <b>path</b>. + * Set <b>config</b> to the list and <b>config_last</b> to the last element of + * <b>config</b>. <b>opened_lst</b> will have a list of opened files if + * provided. Return 0 on success, -1 on failure. */ +static int +config_get_included_config(const char *path, int recursion_level, int extended, + config_line_t **config, config_line_t **config_last, + smartlist_t *opened_lst) +{ + char *included_conf = read_file_to_str(path, 0, NULL); + if (!included_conf) { + return -1; + } + + if (config_get_lines_aux(included_conf, config, extended, 1, NULL, + opened_lst, recursion_level+1, config_last, + config_process_include) < 0) { + tor_free(included_conf); + return -1; + } + + tor_free(included_conf); + return 0; +} + +/** Process an %include <b>path</b> in a config file. Set <b>list</b> to the + * list of configuration settings obtained and <b>list_last</b> to the last + * element of the same list. <b>opened_lst</b> will have a list of opened + * files if provided. Return 0 on success, -1 on failure. */ +static int +config_process_include(const char *path, int recursion_level, int extended, + config_line_t **list, config_line_t **list_last, + smartlist_t *opened_lst) +{ + config_line_t *ret_list = NULL; + config_line_t **next = &ret_list; + + smartlist_t *config_files = config_get_file_list(path, opened_lst); + if (!config_files) { + return -1; + } + + int rv = -1; + SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) { + config_line_t *included_config = NULL; + if (config_get_included_config(config_file, recursion_level, extended, + &included_config, list_last, + opened_lst) < 0) { + goto done; + } + + *next = included_config; + if (*list_last) + next = &(*list_last)->next; + + } SMARTLIST_FOREACH_END(config_file); + *list = ret_list; + rv = 0; + + done: + SMARTLIST_FOREACH(config_files, char *, f, tor_free(f)); + smartlist_free(config_files); + return rv; +} diff --git a/src/lib/fs/conffile.h b/src/lib/fs/conffile.h new file mode 100644 index 0000000000..bd8250b002 --- /dev/null +++ b/src/lib/fs/conffile.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_CONFFILE_H +#define TOR_CONFFILE_H + +struct smartlist_t; +struct config_line_t; + +int config_get_lines_include(const char *string, struct config_line_t **result, + int extended, int *has_include, + struct smartlist_t *opened_lst); + +#endif /* !defined(TOR_CONFLINE_H) */ diff --git a/src/lib/fs/dir.c b/src/lib/fs/dir.c new file mode 100644 index 0000000000..9f09327d84 --- /dev/null +++ b/src/lib/fs/dir.c @@ -0,0 +1,360 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/fs/dir.h" +#include "lib/fs/path.h" +#include "lib/fs/userdb.h" + +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/log/win32err.h" +#include "lib/container/smartlist.h" +#include "lib/sandbox/sandbox.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/printf.h" +#include "lib/string/compat_string.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#ifdef _WIN32 +#include <io.h> +#include <direct.h> +#include <windows.h> +#else /* !(defined(_WIN32)) */ +#include <dirent.h> +#include <pwd.h> +#include <grp.h> +#endif /* defined(_WIN32) */ + +#include <errno.h> +#include <string.h> + +/** Check whether <b>dirname</b> exists and is private. If yes return 0. + * If <b>dirname</b> does not exist: + * - if <b>check</b>&CPD_CREATE, try to create it and return 0 on success. + * - if <b>check</b>&CPD_CHECK, and we think we can create it, return 0. + * - if <b>check</b>&CPD_CHECK is false, and the directory exists, return 0. + * - otherwise, return -1. + * If CPD_GROUP_OK is set, then it's okay if the directory + * is group-readable, but in all cases we create the directory mode 0700. + * If CPD_GROUP_READ is set, existing directory behaves as CPD_GROUP_OK and + * if the directory is created it will use mode 0750 with group read + * permission. Group read privileges also assume execute permission + * as norm for directories. If CPD_CHECK_MODE_ONLY is set, then we don't + * alter the directory permissions if they are too permissive: + * we just return -1. + * When effective_user is not NULL, check permissions against the given user + * and its primary group. + */ +MOCK_IMPL(int, +check_private_dir,(const char *dirname, cpd_check_t check, + const char *effective_user)) +{ + int r; + struct stat st; + + tor_assert(dirname); + +#ifndef _WIN32 + int fd; + const struct passwd *pw = NULL; + uid_t running_uid; + gid_t running_gid; + + /* + * Goal is to harden the implementation by removing any + * potential for race between stat() and chmod(). + * chmod() accepts filename as argument. If an attacker can move + * the file between stat() and chmod(), a potential race exists. + * + * Several suggestions taken from: + * https://developer.apple.com/library/mac/documentation/ + * Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html + */ + + /* Open directory. + * O_NOFOLLOW to ensure that it does not follow symbolic links */ + fd = open(sandbox_intern_string(dirname), O_NOFOLLOW); + + /* Was there an error? Maybe the directory does not exist? */ + if (fd == -1) { + + if (errno != ENOENT) { + /* Other directory error */ + log_warn(LD_FS, "Directory %s cannot be read: %s", dirname, + strerror(errno)); + return -1; + } + + /* Received ENOENT: Directory does not exist */ + + /* Should we create the directory? */ + if (check & CPD_CREATE) { + log_info(LD_GENERAL, "Creating directory %s", dirname); + if (check & CPD_GROUP_READ) { + r = mkdir(dirname, 0750); + } else { + r = mkdir(dirname, 0700); + } + + /* check for mkdir() error */ + if (r) { + log_warn(LD_FS, "Error creating directory %s: %s", dirname, + strerror(errno)); + return -1; + } + + /* we just created the directory. try to open it again. + * permissions on the directory will be checked again below.*/ + fd = open(sandbox_intern_string(dirname), O_NOFOLLOW); + + if (fd == -1) { + log_warn(LD_FS, "Could not reopen recently created directory %s: %s", + dirname, + strerror(errno)); + return -1; + } else { + close(fd); + } + + } else if (!(check & CPD_CHECK)) { + log_warn(LD_FS, "Directory %s does not exist.", dirname); + return -1; + } + + /* XXXX In the case where check==CPD_CHECK, we should look at the + * parent directory a little harder. */ + return 0; + } + + tor_assert(fd >= 0); + + //f = tor_strdup(dirname); + //clean_name_for_stat(f); + log_debug(LD_FS, "stat()ing %s", dirname); + //r = stat(sandbox_intern_string(f), &st); + r = fstat(fd, &st); + if (r == -1) { + log_warn(LD_FS, "fstat() on directory %s failed.", dirname); + close(fd); + return -1; + } + //tor_free(f); + + /* check that dirname is a directory */ + if (!(st.st_mode & S_IFDIR)) { + log_warn(LD_FS, "%s is not a directory", dirname); + close(fd); + return -1; + } + + if (effective_user) { + /* Look up the user and group information. + * If we have a problem, bail out. */ + pw = tor_getpwnam(effective_user); + if (pw == NULL) { + log_warn(LD_CONFIG, "Error setting configured user: %s not found", + effective_user); + close(fd); + return -1; + } + running_uid = pw->pw_uid; + running_gid = pw->pw_gid; + } else { + running_uid = getuid(); + running_gid = getgid(); + } + if (st.st_uid != running_uid) { + char *process_ownername = NULL, *file_ownername = NULL; + + { + const struct passwd *pw_running = tor_getpwuid(running_uid); + process_ownername = pw_running ? tor_strdup(pw_running->pw_name) : + tor_strdup("<unknown>"); + } + + { + const struct passwd *pw_stat = tor_getpwuid(st.st_uid); + file_ownername = pw_stat ? tor_strdup(pw_stat->pw_name) : + tor_strdup("<unknown>"); + } + + log_warn(LD_FS, "%s is not owned by this user (%s, %d) but by " + "%s (%d). Perhaps you are running Tor as the wrong user?", + dirname, process_ownername, (int)running_uid, + file_ownername, (int)st.st_uid); + + tor_free(process_ownername); + tor_free(file_ownername); + close(fd); + return -1; + } + if ( (check & (CPD_GROUP_OK|CPD_GROUP_READ)) + && (st.st_gid != running_gid) && (st.st_gid != 0)) { + struct group *gr; + char *process_groupname = NULL; + gr = getgrgid(running_gid); + process_groupname = gr ? tor_strdup(gr->gr_name) : tor_strdup("<unknown>"); + gr = getgrgid(st.st_gid); + + log_warn(LD_FS, "%s is not owned by this group (%s, %d) but by group " + "%s (%d). Are you running Tor as the wrong user?", + dirname, process_groupname, (int)running_gid, + gr ? gr->gr_name : "<unknown>", (int)st.st_gid); + + tor_free(process_groupname); + close(fd); + return -1; + } + unsigned unwanted_bits = 0; + if (check & (CPD_GROUP_OK|CPD_GROUP_READ)) { + unwanted_bits = 0027; + } else { + unwanted_bits = 0077; + } + unsigned check_bits_filter = ~0; + if (check & CPD_RELAX_DIRMODE_CHECK) { + check_bits_filter = 0022; + } + if ((st.st_mode & unwanted_bits & check_bits_filter) != 0) { + unsigned new_mode; + if (check & CPD_CHECK_MODE_ONLY) { + log_warn(LD_FS, "Permissions on directory %s are too permissive.", + dirname); + close(fd); + return -1; + } + log_warn(LD_FS, "Fixing permissions on directory %s", dirname); + new_mode = st.st_mode; + new_mode |= 0700; /* Owner should have rwx */ + if (check & CPD_GROUP_READ) { + new_mode |= 0050; /* Group should have rx */ + } + new_mode &= ~unwanted_bits; /* Clear the bits that we didn't want set...*/ + if (fchmod(fd, new_mode)) { + log_warn(LD_FS, "Could not chmod directory %s: %s", dirname, + strerror(errno)); + close(fd); + return -1; + } else { + close(fd); + return 0; + } + } + close(fd); +#else /* !(!defined(_WIN32)) */ + /* Win32 case: we can't open() a directory. */ + (void)effective_user; + + char *f = tor_strdup(dirname); + clean_fname_for_stat(f); + log_debug(LD_FS, "stat()ing %s", f); + r = stat(sandbox_intern_string(f), &st); + tor_free(f); + if (r) { + if (errno != ENOENT) { + log_warn(LD_FS, "Directory %s cannot be read: %s", dirname, + strerror(errno)); + return -1; + } + if (check & CPD_CREATE) { + log_info(LD_GENERAL, "Creating directory %s", dirname); + r = mkdir(dirname); + if (r) { + log_warn(LD_FS, "Error creating directory %s: %s", dirname, + strerror(errno)); + return -1; + } + } else if (!(check & CPD_CHECK)) { + log_warn(LD_FS, "Directory %s does not exist.", dirname); + return -1; + } + return 0; + } + if (!(st.st_mode & S_IFDIR)) { + log_warn(LD_FS, "%s is not a directory", dirname); + return -1; + } + +#endif /* !defined(_WIN32) */ + return 0; +} + +/** Return a new list containing the filenames in the directory <b>dirname</b>. + * Return NULL on error or if <b>dirname</b> is not a directory. + */ +MOCK_IMPL(smartlist_t *, +tor_listdir, (const char *dirname)) +{ + smartlist_t *result; +#ifdef _WIN32 + char *pattern=NULL; + TCHAR tpattern[MAX_PATH] = {0}; + char name[MAX_PATH*2+1] = {0}; + HANDLE handle; + WIN32_FIND_DATA findData; + tor_asprintf(&pattern, "%s\\*", dirname); +#ifdef UNICODE + mbstowcs(tpattern,pattern,MAX_PATH); +#else + strlcpy(tpattern, pattern, MAX_PATH); +#endif + if (INVALID_HANDLE_VALUE == (handle = FindFirstFile(tpattern, &findData))) { + tor_free(pattern); + return NULL; + } + result = smartlist_new(); + while (1) { +#ifdef UNICODE + wcstombs(name,findData.cFileName,MAX_PATH); + name[sizeof(name)-1] = '\0'; +#else + strlcpy(name,findData.cFileName,sizeof(name)); +#endif /* defined(UNICODE) */ + if (strcmp(name, ".") && + strcmp(name, "..")) { + smartlist_add_strdup(result, name); + } + if (!FindNextFile(handle, &findData)) { + DWORD err; + if ((err = GetLastError()) != ERROR_NO_MORE_FILES) { + char *errstr = format_win32_error(err); + log_warn(LD_FS, "Error reading directory '%s': %s", dirname, errstr); + tor_free(errstr); + } + break; + } + } + FindClose(handle); + tor_free(pattern); +#else /* !(defined(_WIN32)) */ + const char *prot_dname = sandbox_intern_string(dirname); + DIR *d; + struct dirent *de; + if (!(d = opendir(prot_dname))) + return NULL; + + result = smartlist_new(); + while ((de = readdir(d))) { + if (!strcmp(de->d_name, ".") || + !strcmp(de->d_name, "..")) + continue; + smartlist_add_strdup(result, de->d_name); + } + closedir(d); +#endif /* defined(_WIN32) */ + return result; +} diff --git a/src/lib/fs/dir.h b/src/lib/fs/dir.h new file mode 100644 index 0000000000..925211fbd6 --- /dev/null +++ b/src/lib/fs/dir.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_DIR_H +#define TOR_DIR_H + +#include "lib/cc/compat_compiler.h" +#include "lib/testsupport/testsupport.h" + +/** Possible behaviors for check_private_dir() on encountering a nonexistent + * directory; see that function's documentation for details. */ +typedef unsigned int cpd_check_t; +#define CPD_NONE 0 +#define CPD_CREATE (1u << 0) +#define CPD_CHECK (1u << 1) +#define CPD_GROUP_OK (1u << 2) +#define CPD_GROUP_READ (1u << 3) +#define CPD_CHECK_MODE_ONLY (1u << 4) +#define CPD_RELAX_DIRMODE_CHECK (1u << 5) +MOCK_DECL(int, check_private_dir, (const char *dirname, cpd_check_t check, + const char *effective_user)); + +MOCK_DECL(struct smartlist_t *, tor_listdir, (const char *dirname)); + +#endif diff --git a/src/lib/fs/files.c b/src/lib/fs/files.c new file mode 100644 index 0000000000..0335f6dc59 --- /dev/null +++ b/src/lib/fs/files.c @@ -0,0 +1,711 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifdef _WIN32 +#include <windows.h> +#endif + +#include "lib/fs/files.h" +#include "lib/fs/path.h" +#include "lib/container/smartlist.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/log/escape.h" +#include "lib/err/torerr.h" +#include "lib/malloc/util_malloc.h" +#include "lib/sandbox/sandbox.h" +#include "lib/string/printf.h" +#include "lib/string/util_string.h" +#include "lib/fdio/fdio.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UTIME_H +#include <utime.h> +#endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <errno.h> +#include <stdio.h> +#include <string.h> + +/** As open(path, flags, mode), but return an fd with the close-on-exec mode + * set. */ +int +tor_open_cloexec(const char *path, int flags, unsigned mode) +{ + int fd; + const char *p = sandbox_intern_string(path); +#ifdef O_CLOEXEC + fd = open(p, flags|O_CLOEXEC, mode); + if (fd >= 0) + return fd; + /* If we got an error, see if it is EINVAL. EINVAL might indicate that, + * even though we were built on a system with O_CLOEXEC support, we + * are running on one without. */ + if (errno != EINVAL) + return -1; +#endif /* defined(O_CLOEXEC) */ + + log_debug(LD_FS, "Opening %s with flags %x", p, flags); + fd = open(p, flags, mode); +#ifdef FD_CLOEXEC + if (fd >= 0) { + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { + log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); + close(fd); + return -1; + } + } +#endif /* defined(FD_CLOEXEC) */ + return fd; +} + +/** As fopen(path,mode), but ensures that the O_CLOEXEC bit is set on the + * underlying file handle. */ +FILE * +tor_fopen_cloexec(const char *path, const char *mode) +{ + FILE *result = fopen(path, mode); +#ifdef FD_CLOEXEC + if (result != NULL) { + if (fcntl(fileno(result), F_SETFD, FD_CLOEXEC) == -1) { + log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); + fclose(result); + return NULL; + } + } +#endif /* defined(FD_CLOEXEC) */ + return result; +} + +/** As rename(), but work correctly with the sandbox. */ +int +tor_rename(const char *path_old, const char *path_new) +{ + log_debug(LD_FS, "Renaming %s to %s", path_old, path_new); + return rename(sandbox_intern_string(path_old), + sandbox_intern_string(path_new)); +} + +/** + * Rename the file <b>from</b> to the file <b>to</b>. On Unix, this is + * the same as rename(2). On windows, this removes <b>to</b> first if + * it already exists. + * Returns 0 on success. Returns -1 and sets errno on failure. + */ +int +replace_file(const char *from, const char *to) +{ +#ifndef _WIN32 + return tor_rename(from, to); +#else + switch (file_status(to)) + { + case FN_NOENT: + break; + case FN_FILE: + case FN_EMPTY: + if (unlink(to)) return -1; + break; + case FN_ERROR: + return -1; + case FN_DIR: + errno = EISDIR; + return -1; + } + return tor_rename(from,to); +#endif /* !defined(_WIN32) */ +} + +/** Change <b>fname</b>'s modification time to now. */ +int +touch_file(const char *fname) +{ + if (utime(fname, NULL)!=0) + return -1; + return 0; +} + +/** Wrapper for unlink() to make it mockable for the test suite; returns 0 + * if unlinking the file succeeded, -1 and sets errno if unlinking fails. + */ + +MOCK_IMPL(int, +tor_unlink,(const char *pathname)) +{ + return unlink(pathname); +} + +/** Write <b>count</b> bytes from <b>buf</b> to <b>fd</b>. Return the number + * of bytes written, or -1 on error. Only use if fd is a blocking fd. */ +ssize_t +write_all_to_fd(int fd, const char *buf, size_t count) +{ + size_t written = 0; + ssize_t result; + raw_assert(count < SSIZE_MAX); + + while (written != count) { + result = write(fd, buf+written, count-written); + if (result<0) + return -1; + written += result; + } + return (ssize_t)count; +} + +/** Read from <b>fd</b> to <b>buf</b>, until we get <b>count</b> bytes or + * reach the end of the file. Return the number of bytes read, or -1 on + * error. Only use if fd is a blocking fd. */ +ssize_t +read_all_from_fd(int fd, char *buf, size_t count) +{ + size_t numread = 0; + ssize_t result; + + if (count > SIZE_T_CEILING || count > SSIZE_MAX) { + errno = EINVAL; + return -1; + } + + while (numread < count) { + result = read(fd, buf+numread, count-numread); + if (result<0) + return -1; + else if (result == 0) + break; + numread += result; + } + return (ssize_t)numread; +} + +/** Return: + * FN_ERROR if filename can't be read, is NULL, or is zero-length, + * FN_NOENT if it doesn't exist, + * FN_FILE if it is a non-empty regular file, or a FIFO on unix-like systems, + * FN_EMPTY for zero-byte regular files, + * FN_DIR if it's a directory, and + * FN_ERROR for any other file type. + * On FN_ERROR and FN_NOENT, sets errno. (errno is not set when FN_ERROR + * is returned due to an unhandled file type.) */ +file_status_t +file_status(const char *fname) +{ + struct stat st; + char *f; + int r; + if (!fname || strlen(fname) == 0) { + return FN_ERROR; + } + f = tor_strdup(fname); + clean_fname_for_stat(f); + log_debug(LD_FS, "stat()ing %s", f); + r = stat(sandbox_intern_string(f), &st); + tor_free(f); + if (r) { + if (errno == ENOENT) { + return FN_NOENT; + } + return FN_ERROR; + } + if (st.st_mode & S_IFDIR) { + return FN_DIR; + } else if (st.st_mode & S_IFREG) { + if (st.st_size > 0) { + return FN_FILE; + } else if (st.st_size == 0) { + return FN_EMPTY; + } else { + return FN_ERROR; + } +#ifndef _WIN32 + } else if (st.st_mode & S_IFIFO) { + return FN_FILE; +#endif + } else { + return FN_ERROR; + } +} + +/** Create a file named <b>fname</b> with the contents <b>str</b>. Overwrite + * the previous <b>fname</b> if possible. Return 0 on success, -1 on failure. + * + * This function replaces the old file atomically, if possible. This + * function, and all other functions in util.c that create files, create them + * with mode 0600. + */ +MOCK_IMPL(int, +write_str_to_file,(const char *fname, const char *str, int bin)) +{ +#ifdef _WIN32 + if (!bin && strchr(str, '\r')) { + log_warn(LD_BUG, + "We're writing a text string that already contains a CR to %s", + escaped(fname)); + } +#endif /* defined(_WIN32) */ + return write_bytes_to_file(fname, str, strlen(str), bin); +} + +/** Represents a file that we're writing to, with support for atomic commit: + * we can write into a temporary file, and either remove the file on + * failure, or replace the original file on success. */ +struct open_file_t { + char *tempname; /**< Name of the temporary file. */ + char *filename; /**< Name of the original file. */ + unsigned rename_on_close:1; /**< Are we using the temporary file or not? */ + unsigned binary:1; /**< Did we open in binary mode? */ + int fd; /**< fd for the open file. */ + FILE *stdio_file; /**< stdio wrapper for <b>fd</b>. */ +}; + +/** Try to start writing to the file in <b>fname</b>, passing the flags + * <b>open_flags</b> to the open() syscall, creating the file (if needed) with + * access value <b>mode</b>. If the O_APPEND flag is set, we append to the + * original file. Otherwise, we open a new temporary file in the same + * directory, and either replace the original or remove the temporary file + * when we're done. + * + * Return the fd for the newly opened file, and store working data in + * *<b>data_out</b>. The caller should not close the fd manually: + * instead, call finish_writing_to_file() or abort_writing_to_file(). + * Returns -1 on failure. + * + * NOTE: When not appending, the flags O_CREAT and O_TRUNC are treated + * as true and the flag O_EXCL is treated as false. + * + * NOTE: Ordinarily, O_APPEND means "seek to the end of the file before each + * write()". We don't do that. + */ +int +start_writing_to_file(const char *fname, int open_flags, int mode, + open_file_t **data_out) +{ + open_file_t *new_file = tor_malloc_zero(sizeof(open_file_t)); + const char *open_name; + int append = 0; + + tor_assert(fname); + tor_assert(data_out); +#if (O_BINARY != 0 && O_TEXT != 0) + tor_assert((open_flags & (O_BINARY|O_TEXT)) != 0); +#endif + new_file->fd = -1; + new_file->filename = tor_strdup(fname); + if (open_flags & O_APPEND) { + open_name = fname; + new_file->rename_on_close = 0; + append = 1; + open_flags &= ~O_APPEND; + } else { + tor_asprintf(&new_file->tempname, "%s.tmp", fname); + open_name = new_file->tempname; + /* We always replace an existing temporary file if there is one. */ + open_flags |= O_CREAT|O_TRUNC; + open_flags &= ~O_EXCL; + new_file->rename_on_close = 1; + } +#if O_BINARY != 0 + if (open_flags & O_BINARY) + new_file->binary = 1; +#endif + + new_file->fd = tor_open_cloexec(open_name, open_flags, mode); + if (new_file->fd < 0) { + log_warn(LD_FS, "Couldn't open \"%s\" (%s) for writing: %s", + open_name, fname, strerror(errno)); + goto err; + } + if (append) { + if (tor_fd_seekend(new_file->fd) < 0) { + log_warn(LD_FS, "Couldn't seek to end of file \"%s\": %s", open_name, + strerror(errno)); + goto err; + } + } + + *data_out = new_file; + + return new_file->fd; + + err: + if (new_file->fd >= 0) + close(new_file->fd); + *data_out = NULL; + tor_free(new_file->filename); + tor_free(new_file->tempname); + tor_free(new_file); + return -1; +} + +/** Given <b>file_data</b> from start_writing_to_file(), return a stdio FILE* + * that can be used to write to the same file. The caller should not mix + * stdio calls with non-stdio calls. */ +FILE * +fdopen_file(open_file_t *file_data) +{ + tor_assert(file_data); + if (file_data->stdio_file) + return file_data->stdio_file; + tor_assert(file_data->fd >= 0); + if (!(file_data->stdio_file = fdopen(file_data->fd, + file_data->binary?"ab":"a"))) { + log_warn(LD_FS, "Couldn't fdopen \"%s\" [%d]: %s", file_data->filename, + file_data->fd, strerror(errno)); + } + return file_data->stdio_file; +} + +/** Combines start_writing_to_file with fdopen_file(): arguments are as + * for start_writing_to_file, but */ +FILE * +start_writing_to_stdio_file(const char *fname, int open_flags, int mode, + open_file_t **data_out) +{ + FILE *res; + if (start_writing_to_file(fname, open_flags, mode, data_out)<0) + return NULL; + if (!(res = fdopen_file(*data_out))) { + abort_writing_to_file(*data_out); + *data_out = NULL; + } + return res; +} + +/** Helper function: close and free the underlying file and memory in + * <b>file_data</b>. If we were writing into a temporary file, then delete + * that file (if abort_write is true) or replaces the target file with + * the temporary file (if abort_write is false). */ +static int +finish_writing_to_file_impl(open_file_t *file_data, int abort_write) +{ + int r = 0; + + tor_assert(file_data && file_data->filename); + if (file_data->stdio_file) { + if (fclose(file_data->stdio_file)) { + log_warn(LD_FS, "Error closing \"%s\": %s", file_data->filename, + strerror(errno)); + abort_write = r = -1; + } + } else if (file_data->fd >= 0 && close(file_data->fd) < 0) { + log_warn(LD_FS, "Error flushing \"%s\": %s", file_data->filename, + strerror(errno)); + abort_write = r = -1; + } + + if (file_data->rename_on_close) { + tor_assert(file_data->tempname && file_data->filename); + if (!abort_write) { + tor_assert(strcmp(file_data->filename, file_data->tempname)); + if (replace_file(file_data->tempname, file_data->filename)) { + log_warn(LD_FS, "Error replacing \"%s\": %s", file_data->filename, + strerror(errno)); + abort_write = r = -1; + } + } + if (abort_write) { + int res = unlink(file_data->tempname); + if (res != 0) { + /* We couldn't unlink and we'll leave a mess behind */ + log_warn(LD_FS, "Failed to unlink %s: %s", + file_data->tempname, strerror(errno)); + r = -1; + } + } + } + + tor_free(file_data->filename); + tor_free(file_data->tempname); + tor_free(file_data); + + return r; +} + +/** Finish writing to <b>file_data</b>: close the file handle, free memory as + * needed, and if using a temporary file, replace the original file with + * the temporary file. */ +int +finish_writing_to_file(open_file_t *file_data) +{ + return finish_writing_to_file_impl(file_data, 0); +} + +/** Finish writing to <b>file_data</b>: close the file handle, free memory as + * needed, and if using a temporary file, delete it. */ +int +abort_writing_to_file(open_file_t *file_data) +{ + return finish_writing_to_file_impl(file_data, 1); +} + +/** Helper: given a set of flags as passed to open(2), open the file + * <b>fname</b> and write all the sized_chunk_t structs in <b>chunks</b> to + * the file. Do so as atomically as possible e.g. by opening temp files and + * renaming. */ +static int +write_chunks_to_file_impl(const char *fname, const smartlist_t *chunks, + int open_flags) +{ + open_file_t *file = NULL; + int fd; + ssize_t result; + fd = start_writing_to_file(fname, open_flags, 0600, &file); + if (fd<0) + return -1; + SMARTLIST_FOREACH(chunks, sized_chunk_t *, chunk, + { + result = write_all_to_fd(fd, chunk->bytes, chunk->len); + if (result < 0) { + log_warn(LD_FS, "Error writing to \"%s\": %s", fname, + strerror(errno)); + goto err; + } + tor_assert((size_t)result == chunk->len); + }); + + return finish_writing_to_file(file); + err: + abort_writing_to_file(file); + return -1; +} + +/** Given a smartlist of sized_chunk_t, write them to a file + * <b>fname</b>, overwriting or creating the file as necessary. + * If <b>no_tempfile</b> is 0 then the file will be written + * atomically. */ +int +write_chunks_to_file(const char *fname, const smartlist_t *chunks, int bin, + int no_tempfile) +{ + int flags = OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT); + + if (no_tempfile) { + /* O_APPEND stops write_chunks_to_file from using tempfiles */ + flags |= O_APPEND; + } + return write_chunks_to_file_impl(fname, chunks, flags); +} + +/** Write <b>len</b> bytes, starting at <b>str</b>, to <b>fname</b> + using the open() flags passed in <b>flags</b>. */ +static int +write_bytes_to_file_impl(const char *fname, const char *str, size_t len, + int flags) +{ + int r; + sized_chunk_t c = { str, len }; + smartlist_t *chunks = smartlist_new(); + smartlist_add(chunks, &c); + r = write_chunks_to_file_impl(fname, chunks, flags); + smartlist_free(chunks); + return r; +} + +/** As write_str_to_file, but does not assume a NUL-terminated + * string. Instead, we write <b>len</b> bytes, starting at <b>str</b>. */ +MOCK_IMPL(int, +write_bytes_to_file,(const char *fname, const char *str, size_t len, + int bin)) +{ + return write_bytes_to_file_impl(fname, str, len, + OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT)); +} + +/** As write_bytes_to_file, but if the file already exists, append the bytes + * to the end of the file instead of overwriting it. */ +int +append_bytes_to_file(const char *fname, const char *str, size_t len, + int bin) +{ + return write_bytes_to_file_impl(fname, str, len, + OPEN_FLAGS_APPEND|(bin?O_BINARY:O_TEXT)); +} + +/** Like write_str_to_file(), but also return -1 if there was a file + already residing in <b>fname</b>. */ +int +write_bytes_to_new_file(const char *fname, const char *str, size_t len, + int bin) +{ + return write_bytes_to_file_impl(fname, str, len, + OPEN_FLAGS_DONT_REPLACE| + (bin?O_BINARY:O_TEXT)); +} + +/** + * Read the contents of the open file <b>fd</b> presuming it is a FIFO + * (or similar) file descriptor for which the size of the file isn't + * known ahead of time. Return NULL on failure, and a NUL-terminated + * string on success. On success, set <b>sz_out</b> to the number of + * bytes read. + */ +char * +read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) +{ + ssize_t r; + size_t pos = 0; + char *string = NULL; + size_t string_max = 0; + + if (max_bytes_to_read+1 >= SIZE_T_CEILING) { + errno = EINVAL; + return NULL; + } + + do { + /* XXXX This "add 1K" approach is a little goofy; if we care about + * performance here, we should be doubling. But in practice we shouldn't + * be using this function on big files anyway. */ + string_max = pos + 1024; + if (string_max > max_bytes_to_read) + string_max = max_bytes_to_read + 1; + string = tor_realloc(string, string_max); + r = read(fd, string + pos, string_max - pos - 1); + if (r < 0) { + int save_errno = errno; + tor_free(string); + errno = save_errno; + return NULL; + } + + pos += r; + } while (r > 0 && pos < max_bytes_to_read); + + tor_assert(pos < string_max); + *sz_out = pos; + string[pos] = '\0'; + return string; +} + +/** Read the contents of <b>filename</b> into a newly allocated + * string; return the string on success or NULL on failure. + * + * If <b>stat_out</b> is provided, store the result of stat()ing the + * file into <b>stat_out</b>. + * + * If <b>flags</b> & RFTS_BIN, open the file in binary mode. + * If <b>flags</b> & RFTS_IGNORE_MISSING, don't warn if the file + * doesn't exist. + */ +/* + * This function <em>may</em> return an erroneous result if the file + * is modified while it is running, but must not crash or overflow. + * Right now, the error case occurs when the file length grows between + * the call to stat and the call to read_all: the resulting string will + * be truncated. + */ +MOCK_IMPL(char *, +read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) +{ + int fd; /* router file */ + struct stat statbuf; + char *string; + ssize_t r; + int bin = flags & RFTS_BIN; + + tor_assert(filename); + + fd = tor_open_cloexec(filename,O_RDONLY|(bin?O_BINARY:O_TEXT),0); + if (fd<0) { + int severity = LOG_WARN; + int save_errno = errno; + if (errno == ENOENT && (flags & RFTS_IGNORE_MISSING)) + severity = LOG_INFO; + log_fn(severity, LD_FS,"Could not open \"%s\": %s",filename, + strerror(errno)); + errno = save_errno; + return NULL; + } + + if (fstat(fd, &statbuf)<0) { + int save_errno = errno; + close(fd); + log_warn(LD_FS,"Could not fstat \"%s\".",filename); + errno = save_errno; + return NULL; + } + +#ifndef _WIN32 +/** When we detect that we're reading from a FIFO, don't read more than + * this many bytes. It's insane overkill for most uses. */ +#define FIFO_READ_MAX (1024*1024) + if (S_ISFIFO(statbuf.st_mode)) { + size_t sz = 0; + string = read_file_to_str_until_eof(fd, FIFO_READ_MAX, &sz); + int save_errno = errno; + if (string && stat_out) { + statbuf.st_size = sz; + memcpy(stat_out, &statbuf, sizeof(struct stat)); + } + close(fd); + if (!string) + errno = save_errno; + return string; + } +#endif /* !defined(_WIN32) */ + + if ((uint64_t)(statbuf.st_size)+1 >= SIZE_T_CEILING) { + close(fd); + errno = EINVAL; + return NULL; + } + + string = tor_malloc((size_t)(statbuf.st_size+1)); + + r = read_all_from_fd(fd,string,(size_t)statbuf.st_size); + if (r<0) { + int save_errno = errno; + log_warn(LD_FS,"Error reading from file \"%s\": %s", filename, + strerror(errno)); + tor_free(string); + close(fd); + errno = save_errno; + return NULL; + } + string[r] = '\0'; /* NUL-terminate the result. */ + +#if defined(_WIN32) || defined(__CYGWIN__) + if (!bin && strchr(string, '\r')) { + log_debug(LD_FS, "We didn't convert CRLF to LF as well as we hoped " + "when reading %s. Coping.", + filename); + tor_strstrip(string, "\r"); + r = strlen(string); + } + if (!bin) { + statbuf.st_size = (size_t) r; + } else +#endif /* defined(_WIN32) || defined(__CYGWIN__) */ + if (r != statbuf.st_size) { + /* Unless we're using text mode on win32, we'd better have an exact + * match for size. */ + int save_errno = errno; + log_warn(LD_FS,"Could read only %d of %ld bytes of file \"%s\".", + (int)r, (long)statbuf.st_size,filename); + tor_free(string); + close(fd); + errno = save_errno; + return NULL; + } + close(fd); + if (stat_out) { + memcpy(stat_out, &statbuf, sizeof(struct stat)); + } + + return string; +} diff --git a/src/lib/fs/files.h b/src/lib/fs/files.h new file mode 100644 index 0000000000..be4ec485f1 --- /dev/null +++ b/src/lib/fs/files.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_FS_H +#define TOR_FS_H + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" + +#include <stddef.h> +#include <stdio.h> + +#ifdef _WIN32 +/* We need these for struct stat to work */ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifndef O_TEXT +#define O_TEXT 0 +#endif +#ifndef O_NOFOLLOW +#define O_NOFOLLOW 0 +#endif + +struct stat; + +int tor_open_cloexec(const char *path, int flags, unsigned mode); +FILE *tor_fopen_cloexec(const char *path, const char *mode); +int tor_rename(const char *path_old, const char *path_new); + +int replace_file(const char *from, const char *to); +int touch_file(const char *fname); + +MOCK_DECL(int,tor_unlink,(const char *pathname)); + +/** Return values from file_status(); see that function's documentation + * for details. */ +typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR, FN_EMPTY } file_status_t; + +file_status_t file_status(const char *filename); + +int64_t tor_get_avail_disk_space(const char *path); + +ssize_t write_all_to_fd(int fd, const char *buf, size_t count); +ssize_t read_all_from_fd(int fd, char *buf, size_t count); + +#define OPEN_FLAGS_REPLACE (O_WRONLY|O_CREAT|O_TRUNC) +#define OPEN_FLAGS_APPEND (O_WRONLY|O_CREAT|O_APPEND) +#define OPEN_FLAGS_DONT_REPLACE (O_CREAT|O_EXCL|O_APPEND|O_WRONLY) +typedef struct open_file_t open_file_t; +int start_writing_to_file(const char *fname, int open_flags, int mode, + open_file_t **data_out); +FILE *start_writing_to_stdio_file(const char *fname, int open_flags, int mode, + open_file_t **data_out); +FILE *fdopen_file(open_file_t *file_data); +int finish_writing_to_file(open_file_t *file_data); +int abort_writing_to_file(open_file_t *file_data); +MOCK_DECL(int, write_str_to_file,(const char *fname, const char *str, + int bin)); +MOCK_DECL(int, write_bytes_to_file,(const char *fname, const char *str, + size_t len,int bin)); + +/** An ad-hoc type to hold a string of characters and a count; used by + * write_chunks_to_file. */ +typedef struct sized_chunk_t { + const char *bytes; + size_t len; +} sized_chunk_t; +struct smartlist_t; +int write_chunks_to_file(const char *fname, const struct smartlist_t *chunks, + int bin, int no_tempfile); +int append_bytes_to_file(const char *fname, const char *str, size_t len, + int bin); +int write_bytes_to_new_file(const char *fname, const char *str, size_t len, + int bin); + +/** Flag for read_file_to_str: open the file in binary mode. */ +#define RFTS_BIN 1 +/** Flag for read_file_to_str: it's okay if the file doesn't exist. */ +#define RFTS_IGNORE_MISSING 2 + +MOCK_DECL_ATTR(char *, read_file_to_str,(const char *filename, int flags, + struct stat *stat_out), + ATTR_MALLOC); +char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, + size_t *sz_out) + ATTR_MALLOC; + +#endif diff --git a/src/lib/fs/freespace.c b/src/lib/fs/freespace.c new file mode 100644 index 0000000000..926b17dbde --- /dev/null +++ b/src/lib/fs/freespace.c @@ -0,0 +1,56 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/fs/files.h" +#include "lib/cc/torint.h" + +#ifdef HAVE_SYS_STATVFS_H +#include <sys/statvfs.h> +#endif +#ifdef _WIN32 +#include <windows.h> +#endif + +#include <string.h> + +/** Return the amount of free disk space we have permission to use, in + * bytes. Return -1 if the amount of free space can't be determined. */ +int64_t +tor_get_avail_disk_space(const char *path) +{ +#ifdef HAVE_STATVFS + struct statvfs st; + int r; + memset(&st, 0, sizeof(st)); + + r = statvfs(path, &st); + if (r < 0) + return -1; + + int64_t result = st.f_bavail; + if (st.f_frsize) { + result *= st.f_frsize; + } else if (st.f_bsize) { + result *= st.f_bsize; + } else { + return -1; + } + + return result; +#elif defined(_WIN32) + ULARGE_INTEGER freeBytesAvail; + BOOL ok; + + ok = GetDiskFreeSpaceEx(path, &freeBytesAvail, NULL, NULL); + if (!ok) { + return -1; + } + return (int64_t)freeBytesAvail.QuadPart; +#else + (void)path; + errno = ENOSYS; + return -1; +#endif /* defined(HAVE_STATVFS) || ... */ +} diff --git a/src/lib/fs/include.am b/src/lib/fs/include.am new file mode 100644 index 0000000000..f33e4d6430 --- /dev/null +++ b/src/lib/fs/include.am @@ -0,0 +1,37 @@ + +noinst_LIBRARIES += src/lib/libtor-fs.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-fs-testing.a +endif + +src_lib_libtor_fs_a_SOURCES = \ + src/lib/fs/conffile.c \ + src/lib/fs/dir.c \ + src/lib/fs/files.c \ + src/lib/fs/freespace.c \ + src/lib/fs/lockfile.c \ + src/lib/fs/mmap.c \ + src/lib/fs/path.c \ + src/lib/fs/storagedir.c \ + src/lib/fs/userdb.c + +if WIN32 +src_lib_libtor_fs_a_SOURCES += src/lib/fs/winlib.c +endif + +src_lib_libtor_fs_testing_a_SOURCES = \ + $(src_lib_libtor_fs_a_SOURCES) +src_lib_libtor_fs_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_fs_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/fs/conffile.h \ + src/lib/fs/dir.h \ + src/lib/fs/files.h \ + src/lib/fs/lockfile.h \ + src/lib/fs/mmap.h \ + src/lib/fs/path.h \ + src/lib/fs/storagedir.h \ + src/lib/fs/userdb.h \ + src/lib/fs/winlib.h diff --git a/src/lib/fs/lockfile.c b/src/lib/fs/lockfile.c new file mode 100644 index 0000000000..3fc9cd4264 --- /dev/null +++ b/src/lib/fs/lockfile.c @@ -0,0 +1,138 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/fs/files.h" +#include "lib/fs/lockfile.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" + +#ifdef HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef _WIN32 +#include <windows.h> +#include <sys/locking.h> +#endif + +#include <errno.h> +#include <string.h> + +/** Represents a lockfile on which we hold the lock. */ +struct tor_lockfile_t { + /** Name of the file */ + char *filename; + /** File descriptor used to hold the file open */ + int fd; +}; + +/** Try to get a lock on the lockfile <b>filename</b>, creating it as + * necessary. If someone else has the lock and <b>blocking</b> is true, + * wait until the lock is available. Otherwise return immediately whether + * we succeeded or not. + * + * Set *<b>locked_out</b> to true if somebody else had the lock, and to false + * otherwise. + * + * Return a <b>tor_lockfile_t</b> on success, NULL on failure. + * + * (Implementation note: because we need to fall back to fcntl on some + * platforms, these locks are per-process, not per-thread. If you want + * to do in-process locking, use tor_mutex_t like a normal person. + * On Windows, when <b>blocking</b> is true, the maximum time that + * is actually waited is 10 seconds, after which NULL is returned + * and <b>locked_out</b> is set to 1.) + */ +tor_lockfile_t * +tor_lockfile_lock(const char *filename, int blocking, int *locked_out) +{ + tor_lockfile_t *result; + int fd; + *locked_out = 0; + + log_info(LD_FS, "Locking \"%s\"", filename); + fd = tor_open_cloexec(filename, O_RDWR|O_CREAT|O_TRUNC, 0600); + if (fd < 0) { + log_warn(LD_FS,"Couldn't open \"%s\" for locking: %s", filename, + strerror(errno)); + return NULL; + } + +#ifdef _WIN32 + _lseek(fd, 0, SEEK_SET); + if (_locking(fd, blocking ? _LK_LOCK : _LK_NBLCK, 1) < 0) { + if (errno != EACCES && errno != EDEADLOCK) + log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno)); + else + *locked_out = 1; + close(fd); + return NULL; + } +#elif defined(HAVE_FLOCK) + if (flock(fd, LOCK_EX|(blocking ? 0 : LOCK_NB)) < 0) { + if (errno != EWOULDBLOCK) + log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno)); + else + *locked_out = 1; + close(fd); + return NULL; + } +#else + { + struct flock lock; + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + if (fcntl(fd, blocking ? F_SETLKW : F_SETLK, &lock) < 0) { + if (errno != EACCES && errno != EAGAIN) + log_warn(LD_FS, "Couldn't lock \"%s\": %s", filename, strerror(errno)); + else + *locked_out = 1; + close(fd); + return NULL; + } + } +#endif /* defined(_WIN32) || ... */ + + result = tor_malloc(sizeof(tor_lockfile_t)); + result->filename = tor_strdup(filename); + result->fd = fd; + return result; +} + +/** Release the lock held as <b>lockfile</b>. */ +void +tor_lockfile_unlock(tor_lockfile_t *lockfile) +{ + tor_assert(lockfile); + + log_info(LD_FS, "Unlocking \"%s\"", lockfile->filename); +#ifdef _WIN32 + _lseek(lockfile->fd, 0, SEEK_SET); + if (_locking(lockfile->fd, _LK_UNLCK, 1) < 0) { + log_warn(LD_FS,"Error unlocking \"%s\": %s", lockfile->filename, + strerror(errno)); + } +#elif defined(HAVE_FLOCK) + if (flock(lockfile->fd, LOCK_UN) < 0) { + log_warn(LD_FS, "Error unlocking \"%s\": %s", lockfile->filename, + strerror(errno)); + } +#else + /* Closing the lockfile is sufficient. */ +#endif /* defined(_WIN32) || ... */ + + close(lockfile->fd); + lockfile->fd = -1; + tor_free(lockfile->filename); + tor_free(lockfile); +} diff --git a/src/lib/fs/lockfile.h b/src/lib/fs/lockfile.h new file mode 100644 index 0000000000..1c5bb023b5 --- /dev/null +++ b/src/lib/fs/lockfile.h @@ -0,0 +1,14 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_LOCKFILE_H +#define TOR_LOCKFILE_H + +typedef struct tor_lockfile_t tor_lockfile_t; +tor_lockfile_t *tor_lockfile_lock(const char *filename, int blocking, + int *locked_out); +void tor_lockfile_unlock(tor_lockfile_t *lockfile); + +#endif diff --git a/src/lib/fs/mmap.c b/src/lib/fs/mmap.c new file mode 100644 index 0000000000..6d69fd5e78 --- /dev/null +++ b/src/lib/fs/mmap.c @@ -0,0 +1,234 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/fs/mmap.h" +#include "lib/fs/files.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/log/win32err.h" +#include "lib/string/compat_string.h" +#include "lib/malloc/util_malloc.h" + +#ifdef HAVE_MMAP +#include <sys/mman.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#ifdef _WIN32 +#include <windows.h> +#endif + +#include <errno.h> +#include <string.h> + +#if defined(HAVE_MMAP) || defined(RUNNING_DOXYGEN) +/** Try to create a memory mapping for <b>filename</b> and return it. On + * failure, return NULL. Sets errno properly, using ERANGE to mean + * "empty file". Must only be called on trusted Tor-owned files, as changing + * the underlying file's size causes unspecified behavior. */ +tor_mmap_t * +tor_mmap_file(const char *filename) +{ + int fd; /* router file */ + char *string; + int result; + tor_mmap_t *res; + size_t size, filesize; + struct stat st; + + tor_assert(filename); + + fd = tor_open_cloexec(filename, O_RDONLY, 0); + if (fd<0) { + int save_errno = errno; + int severity = (errno == ENOENT) ? LOG_INFO : LOG_WARN; + log_fn(severity, LD_FS,"Could not open \"%s\" for mmap(): %s",filename, + strerror(errno)); + errno = save_errno; + return NULL; + } + + /* Get the size of the file */ + result = fstat(fd, &st); + if (result != 0) { + int save_errno = errno; + log_warn(LD_FS, + "Couldn't fstat opened descriptor for \"%s\" during mmap: %s", + filename, strerror(errno)); + close(fd); + errno = save_errno; + return NULL; + } + size = filesize = (size_t)(st.st_size); + + if (st.st_size > SSIZE_T_CEILING || (off_t)size < st.st_size) { + log_warn(LD_FS, "File \"%s\" is too large. Ignoring.",filename); + errno = EFBIG; + close(fd); + return NULL; + } + if (!size) { + /* Zero-length file. If we call mmap on it, it will succeed but + * return NULL, and bad things will happen. So just fail. */ + log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); + errno = ERANGE; + close(fd); + return NULL; + } + + string = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + if (string == MAP_FAILED) { + int save_errno = errno; + log_warn(LD_FS,"Could not mmap file \"%s\": %s", filename, + strerror(errno)); + errno = save_errno; + return NULL; + } + + res = tor_malloc_zero(sizeof(tor_mmap_t)); + res->data = string; + res->size = filesize; + res->mapping_size = size; + + return res; +} +/** Release storage held for a memory mapping; returns 0 on success, + * or -1 on failure (and logs a warning). */ +int +tor_munmap_file(tor_mmap_t *handle) +{ + int res; + + if (handle == NULL) + return 0; + + res = munmap((char*)handle->data, handle->mapping_size); + if (res == 0) { + /* munmap() succeeded */ + tor_free(handle); + } else { + log_warn(LD_FS, "Failed to munmap() in tor_munmap_file(): %s", + strerror(errno)); + res = -1; + } + + return res; +} +#elif defined(_WIN32) +tor_mmap_t * +tor_mmap_file(const char *filename) +{ + TCHAR tfilename[MAX_PATH]= {0}; + tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t)); + int empty = 0; + HANDLE file_handle = INVALID_HANDLE_VALUE; + DWORD size_low, size_high; + uint64_t real_size; + res->mmap_handle = NULL; +#ifdef UNICODE + mbstowcs(tfilename,filename,MAX_PATH); +#else + strlcpy(tfilename,filename,MAX_PATH); +#endif + file_handle = CreateFile(tfilename, + GENERIC_READ, FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0); + + if (file_handle == INVALID_HANDLE_VALUE) + goto win_err; + + size_low = GetFileSize(file_handle, &size_high); + + if (size_low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { + log_warn(LD_FS,"Error getting size of \"%s\".",filename); + goto win_err; + } + if (size_low == 0 && size_high == 0) { + log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); + empty = 1; + goto err; + } + real_size = (((uint64_t)size_high)<<32) | size_low; + if (real_size > SIZE_MAX) { + log_warn(LD_FS,"File \"%s\" is too big to map; not trying.",filename); + goto err; + } + res->size = real_size; + + res->mmap_handle = CreateFileMapping(file_handle, + NULL, + PAGE_READONLY, + size_high, + size_low, + NULL); + if (res->mmap_handle == NULL) + goto win_err; + res->data = (char*) MapViewOfFile(res->mmap_handle, + FILE_MAP_READ, + 0, 0, 0); + if (!res->data) + goto win_err; + + CloseHandle(file_handle); + return res; + win_err: { + DWORD e = GetLastError(); + int severity = (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) ? + LOG_INFO : LOG_WARN; + char *msg = format_win32_error(e); + log_fn(severity, LD_FS, "Couldn't mmap file \"%s\": %s", filename, msg); + tor_free(msg); + if (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) + errno = ENOENT; + else + errno = EINVAL; + } + err: + if (empty) + errno = ERANGE; + if (file_handle != INVALID_HANDLE_VALUE) + CloseHandle(file_handle); + tor_munmap_file(res); + return NULL; +} + +/* Unmap the file, and return 0 for success or -1 for failure */ +int +tor_munmap_file(tor_mmap_t *handle) +{ + if (handle == NULL) + return 0; + + if (handle->data) { + /* This is an ugly cast, but without it, "data" in struct tor_mmap_t would + have to be redefined as non-const. */ + BOOL ok = UnmapViewOfFile( (LPVOID) handle->data); + if (!ok) { + log_warn(LD_FS, "Failed to UnmapViewOfFile() in tor_munmap_file(): %d", + (int)GetLastError()); + } + } + + if (handle->mmap_handle != NULL) + CloseHandle(handle->mmap_handle); + tor_free(handle); + + return 0; +} +#else +#error "cannot implement tor_mmap_file" +#endif /* defined(HAVE_MMAP) || ... || ... */ diff --git a/src/lib/fs/mmap.h b/src/lib/fs/mmap.h new file mode 100644 index 0000000000..b0585775f5 --- /dev/null +++ b/src/lib/fs/mmap.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_MMAP_H +#define TOR_MMAP_H + +#include "lib/cc/compat_compiler.h" +#include <stddef.h> + +#ifdef _WIN32 +#include <windef.h> +#endif + +/** Represents an mmaped file. Allocated via tor_mmap_file; freed with + * tor_munmap_file. */ +typedef struct tor_mmap_t { + const char *data; /**< Mapping of the file's contents. */ + size_t size; /**< Size of the file. */ + + /* None of the fields below should be accessed from outside compat.c */ +#ifdef HAVE_MMAP + size_t mapping_size; /**< Size of the actual mapping. (This is this file + * size, rounded up to the nearest page.) */ +#elif defined _WIN32 + HANDLE mmap_handle; +#endif /* defined(HAVE_MMAP) || ... */ + +} tor_mmap_t; + +tor_mmap_t *tor_mmap_file(const char *filename) ATTR_NONNULL((1)); +int tor_munmap_file(tor_mmap_t *handle) ATTR_NONNULL((1)); + +#endif diff --git a/src/lib/fs/path.c b/src/lib/fs/path.c new file mode 100644 index 0000000000..68cda67765 --- /dev/null +++ b/src/lib/fs/path.c @@ -0,0 +1,289 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/fs/path.h" +#include "lib/malloc/util_malloc.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/string/printf.h" +#include "lib/string/util_string.h" +#include "lib/string/compat_ctype.h" +#include "lib/fs/userdb.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <errno.h> +#include <string.h> + +/** Removes enclosing quotes from <b>path</b> and unescapes quotes between the + * enclosing quotes. Backslashes are not unescaped. Return the unquoted + * <b>path</b> on success or 0 if <b>path</b> is not quoted correctly. */ +char * +get_unquoted_path(const char *path) +{ + size_t len = strlen(path); + + if (len == 0) { + return tor_strdup(""); + } + + int has_start_quote = (path[0] == '\"'); + int has_end_quote = (len > 0 && path[len-1] == '\"'); + if (has_start_quote != has_end_quote || (len == 1 && has_start_quote)) { + return NULL; + } + + char *unquoted_path = tor_malloc(len - has_start_quote - has_end_quote + 1); + char *s = unquoted_path; + size_t i; + for (i = has_start_quote; i < len - has_end_quote; i++) { + if (path[i] == '\"' && (i > 0 && path[i-1] == '\\')) { + *(s-1) = path[i]; + } else if (path[i] != '\"') { + *s++ = path[i]; + } else { /* unescaped quote */ + tor_free(unquoted_path); + return NULL; + } + } + *s = '\0'; + return unquoted_path; +} + +/** Expand any homedir prefix on <b>filename</b>; return a newly allocated + * string. */ +char * +expand_filename(const char *filename) +{ + tor_assert(filename); +#ifdef _WIN32 + /* Might consider using GetFullPathName() as described here: + * http://etutorials.org/Programming/secure+programming/ + * Chapter+3.+Input+Validation/3.7+Validating+Filenames+and+Paths/ + */ + return tor_strdup(filename); +#else /* !(defined(_WIN32)) */ + if (*filename == '~') { + char *home, *result=NULL; + const char *rest; + + if (filename[1] == '/' || filename[1] == '\0') { + home = getenv("HOME"); + if (!home) { + log_warn(LD_CONFIG, "Couldn't find $HOME environment variable while " + "expanding \"%s\"; defaulting to \"\".", filename); + home = tor_strdup(""); + } else { + home = tor_strdup(home); + } + rest = strlen(filename)>=2?(filename+2):""; + } else { +#ifdef HAVE_PWD_H + char *username, *slash; + slash = strchr(filename, '/'); + if (slash) + username = tor_strndup(filename+1,slash-filename-1); + else + username = tor_strdup(filename+1); + if (!(home = get_user_homedir(username))) { + log_warn(LD_CONFIG,"Couldn't get homedir for \"%s\"",username); + tor_free(username); + return NULL; + } + tor_free(username); + rest = slash ? (slash+1) : ""; +#else /* !(defined(HAVE_PWD_H)) */ + log_warn(LD_CONFIG, "Couldn't expand homedir on system without pwd.h"); + return tor_strdup(filename); +#endif /* defined(HAVE_PWD_H) */ + } + tor_assert(home); + /* Remove trailing slash. */ + if (strlen(home)>1 && !strcmpend(home,PATH_SEPARATOR)) { + home[strlen(home)-1] = '\0'; + } + tor_asprintf(&result,"%s"PATH_SEPARATOR"%s",home,rest); + tor_free(home); + return result; + } else { + return tor_strdup(filename); + } +#endif /* defined(_WIN32) */ +} + +/** Return true iff <b>filename</b> is a relative path. */ +int +path_is_relative(const char *filename) +{ + if (filename && filename[0] == '/') + return 0; +#ifdef _WIN32 + else if (filename && filename[0] == '\\') + return 0; + else if (filename && strlen(filename)>3 && TOR_ISALPHA(filename[0]) && + filename[1] == ':' && filename[2] == '\\') + return 0; +#endif /* defined(_WIN32) */ + else + return 1; +} + +/** Clean up <b>name</b> so that we can use it in a call to "stat". On Unix, + * we do nothing. On Windows, we remove a trailing slash, unless the path is + * the root of a disk. */ +void +clean_fname_for_stat(char *name) +{ +#ifdef _WIN32 + size_t len = strlen(name); + if (!len) + return; + if (name[len-1]=='\\' || name[len-1]=='/') { + if (len == 1 || (len==3 && name[1]==':')) + return; + name[len-1]='\0'; + } +#else /* !(defined(_WIN32)) */ + (void)name; +#endif /* defined(_WIN32) */ +} + +/** Modify <b>fname</b> to contain the name of its parent directory. Doesn't + * actually examine the filesystem; does a purely syntactic modification. + * + * The parent of the root director is considered to be iteself. + * + * Path separators are the forward slash (/) everywhere and additionally + * the backslash (\) on Win32. + * + * Cuts off any number of trailing path separators but otherwise ignores + * them for purposes of finding the parent directory. + * + * Returns 0 if a parent directory was successfully found, -1 otherwise (fname + * did not have any path separators or only had them at the end). + * */ +int +get_parent_directory(char *fname) +{ + char *cp; + int at_end = 1; + tor_assert(fname); +#ifdef _WIN32 + /* If we start with, say, c:, then don't consider that the start of the path + */ + if (fname[0] && fname[1] == ':') { + fname += 2; + } +#endif /* defined(_WIN32) */ + /* Now we want to remove all path-separators at the end of the string, + * and to remove the end of the string starting with the path separator + * before the last non-path-separator. In perl, this would be + * s#[/]*$##; s#/[^/]*$##; + * on a unixy platform. + */ + cp = fname + strlen(fname); + at_end = 1; + while (--cp >= fname) { + int is_sep = (*cp == '/' +#ifdef _WIN32 + || *cp == '\\' +#endif + ); + if (is_sep) { + if (cp == fname) { + /* This is the first separator in the file name; don't remove it! */ + cp[1] = '\0'; + return 0; + } + *cp = '\0'; + if (! at_end) + return 0; + } else { + at_end = 0; + } + } + return -1; +} + +#ifndef _WIN32 +/** Return a newly allocated string containing the output of getcwd(). Return + * NULL on failure. (We can't just use getcwd() into a PATH_MAX buffer, since + * Hurd hasn't got a PATH_MAX.) + */ +static char * +alloc_getcwd(void) +{ +#ifdef HAVE_GET_CURRENT_DIR_NAME + /* Glibc makes this nice and simple for us. */ + char *cwd = get_current_dir_name(); + char *result = NULL; + if (cwd) { + /* We make a copy here, in case tor_malloc() is not malloc(). */ + result = tor_strdup(cwd); + raw_free(cwd); // alias for free to avoid tripping check-spaces. + } + return result; +#else /* !(defined(HAVE_GET_CURRENT_DIR_NAME)) */ + size_t size = 1024; + char *buf = NULL; + char *ptr = NULL; + + while (ptr == NULL) { + buf = tor_realloc(buf, size); + ptr = getcwd(buf, size); + + if (ptr == NULL && errno != ERANGE) { + tor_free(buf); + return NULL; + } + + size *= 2; + } + return buf; +#endif /* defined(HAVE_GET_CURRENT_DIR_NAME) */ +} +#endif /* !defined(_WIN32) */ + +/** Expand possibly relative path <b>fname</b> to an absolute path. + * Return a newly allocated string, possibly equal to <b>fname</b>. */ +char * +make_path_absolute(char *fname) +{ +#ifdef _WIN32 + char *absfname_malloced = _fullpath(NULL, fname, 1); + + /* We don't want to assume that tor_free can free a string allocated + * with malloc. On failure, return fname (it's better than nothing). */ + char *absfname = tor_strdup(absfname_malloced ? absfname_malloced : fname); + if (absfname_malloced) raw_free(absfname_malloced); + + return absfname; +#else /* !(defined(_WIN32)) */ + char *absfname = NULL, *path = NULL; + + tor_assert(fname); + + if (fname[0] == '/') { + absfname = tor_strdup(fname); + } else { + path = alloc_getcwd(); + if (path) { + tor_asprintf(&absfname, "%s/%s", path, fname); + tor_free(path); + } else { + /* LCOV_EXCL_START Can't make getcwd fail. */ + /* If getcwd failed, the best we can do here is keep using the + * relative path. (Perhaps / isn't readable by this UID/GID.) */ + log_warn(LD_GENERAL, "Unable to find current working directory: %s", + strerror(errno)); + absfname = tor_strdup(fname); + /* LCOV_EXCL_STOP */ + } + } + return absfname; +#endif /* defined(_WIN32) */ +} diff --git a/src/lib/fs/path.h b/src/lib/fs/path.h new file mode 100644 index 0000000000..a3073a99ec --- /dev/null +++ b/src/lib/fs/path.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_PATH_H +#define TOR_PATH_H + +#include "lib/cc/compat_compiler.h" + +#ifdef _WIN32 +#define PATH_SEPARATOR "\\" +#else +#define PATH_SEPARATOR "/" +#endif + +char *get_unquoted_path(const char *path); +char *expand_filename(const char *filename); +int path_is_relative(const char *filename); +void clean_fname_for_stat(char *name); +int get_parent_directory(char *fname); +char *make_path_absolute(char *fname); + +#endif diff --git a/src/common/storagedir.c b/src/lib/fs/storagedir.c index e2c7b4bb87..d013e4550d 100644 --- a/src/common/storagedir.c +++ b/src/lib/fs/storagedir.c @@ -1,14 +1,21 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "container.h" -#include "compat.h" -#include "confline.h" -#include "memarea.h" -#include "sandbox.h" -#include "storagedir.h" -#include "torlog.h" -#include "util.h" +#include "lib/fs/storagedir.h" + +#include "lib/container/smartlist.h" +#include "lib/encoding/confline.h" +#include "lib/fs/dir.h" +#include "lib/fs/files.h" +#include "lib/fs/mmap.h" +#include "lib/log/escape.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/memarea/memarea.h" +#include "lib/sandbox/sandbox.h" +#include "lib/string/printf.h" +#include "lib/string/util_string.h" #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> @@ -19,6 +26,9 @@ #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#include <stdlib.h> +#include <errno.h> +#include <string.h> #define FNAME_MIN_NUM 1000 @@ -583,4 +593,3 @@ storage_dir_get_max_files(storage_dir_t *d) { return d->max_files; } - diff --git a/src/common/storagedir.h b/src/lib/fs/storagedir.h index d99bd7ec52..1ecb1c0a11 100644 --- a/src/common/storagedir.h +++ b/src/lib/fs/storagedir.h @@ -1,12 +1,17 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_STORAGEDIR_H #define TOR_STORAGEDIR_H +#include "lib/cc/torint.h" +#include <stddef.h> + typedef struct storage_dir_t storage_dir_t; struct config_line_t; struct sandbox_cfg_elem; +struct tor_mmap_t; +struct smartlist_t; storage_dir_t * storage_dir_new(const char *dirname, int n_files); void storage_dir_free_(storage_dir_t *d); @@ -15,9 +20,9 @@ void storage_dir_free_(storage_dir_t *d); int storage_dir_register_with_sandbox(storage_dir_t *d, struct sandbox_cfg_elem **cfg); -const smartlist_t *storage_dir_list(storage_dir_t *d); +const struct smartlist_t *storage_dir_list(storage_dir_t *d); uint64_t storage_dir_get_usage(storage_dir_t *d); -tor_mmap_t *storage_dir_map(storage_dir_t *d, const char *fname); +struct tor_mmap_t *storage_dir_map(storage_dir_t *d, const char *fname); uint8_t *storage_dir_read(storage_dir_t *d, const char *fname, int bin, size_t *sz_out); int storage_dir_save_bytes_to_file(storage_dir_t *d, @@ -34,7 +39,7 @@ int storage_dir_save_labeled_to_file(storage_dir_t *d, const uint8_t *data, size_t length, char **fname_out); -tor_mmap_t *storage_dir_map_labeled(storage_dir_t *dir, +struct tor_mmap_t *storage_dir_map_labeled(storage_dir_t *dir, const char *fname, struct config_line_t **labels_out, const uint8_t **data_out, @@ -51,4 +56,3 @@ int storage_dir_remove_all(storage_dir_t *d); int storage_dir_get_max_files(storage_dir_t *d); #endif /* !defined(TOR_STORAGEDIR_H) */ - diff --git a/src/lib/fs/userdb.c b/src/lib/fs/userdb.c new file mode 100644 index 0000000000..b7abbc7813 --- /dev/null +++ b/src/lib/fs/userdb.c @@ -0,0 +1,132 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/fs/userdb.h" + +#ifndef _WIN32 +#include "lib/malloc/util_malloc.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +#include <pwd.h> +#include <stddef.h> +#include <string.h> + +/** Cached struct from the last getpwname() call we did successfully. */ +static struct passwd *passwd_cached = NULL; + +/** Helper: copy a struct passwd object. + * + * We only copy the fields pw_uid, pw_gid, pw_name, pw_dir. Tor doesn't use + * any others, and I don't want to run into incompatibilities. + */ +static struct passwd * +tor_passwd_dup(const struct passwd *pw) +{ + struct passwd *new_pw = tor_malloc_zero(sizeof(struct passwd)); + if (pw->pw_name) + new_pw->pw_name = tor_strdup(pw->pw_name); + if (pw->pw_dir) + new_pw->pw_dir = tor_strdup(pw->pw_dir); + new_pw->pw_uid = pw->pw_uid; + new_pw->pw_gid = pw->pw_gid; + + return new_pw; +} + +#define tor_passwd_free(pw) \ + FREE_AND_NULL(struct passwd, tor_passwd_free_, (pw)) + +/** Helper: free one of our cached 'struct passwd' values. */ +static void +tor_passwd_free_(struct passwd *pw) +{ + if (!pw) + return; + + tor_free(pw->pw_name); + tor_free(pw->pw_dir); + tor_free(pw); +} + +/** Wrapper around getpwnam() that caches result. Used so that we don't need + * to give the sandbox access to /etc/passwd. + * + * The following fields alone will definitely be copied in the output: pw_uid, + * pw_gid, pw_name, pw_dir. Other fields are not present in cached values. + * + * When called with a NULL argument, this function clears storage associated + * with static variables it uses. + **/ +const struct passwd * +tor_getpwnam(const char *username) +{ + struct passwd *pw; + + if (username == NULL) { + tor_passwd_free(passwd_cached); + passwd_cached = NULL; + return NULL; + } + + if ((pw = getpwnam(username))) { + tor_passwd_free(passwd_cached); + passwd_cached = tor_passwd_dup(pw); + log_info(LD_GENERAL, "Caching new entry %s for %s", + passwd_cached->pw_name, username); + return pw; + } + + /* Lookup failed */ + if (! passwd_cached || ! passwd_cached->pw_name) + return NULL; + + if (! strcmp(username, passwd_cached->pw_name)) + return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky + + return NULL; +} + +/** Wrapper around getpwnam() that can use cached result from + * tor_getpwnam(). Used so that we don't need to give the sandbox access to + * /etc/passwd. + * + * The following fields alone will definitely be copied in the output: pw_uid, + * pw_gid, pw_name, pw_dir. Other fields are not present in cached values. + */ +const struct passwd * +tor_getpwuid(uid_t uid) +{ + struct passwd *pw; + + if ((pw = getpwuid(uid))) { + return pw; + } + + /* Lookup failed */ + if (! passwd_cached) + return NULL; + + if (uid == passwd_cached->pw_uid) + return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky + + return NULL; +} + +/** Allocate and return a string containing the home directory for the + * user <b>username</b>. Only works on posix-like systems. */ +char * +get_user_homedir(const char *username) +{ + const struct passwd *pw; + tor_assert(username); + + if (!(pw = tor_getpwnam(username))) { + log_err(LD_CONFIG,"User \"%s\" not found.", username); + return NULL; + } + return tor_strdup(pw->pw_dir); +} +#endif /* !defined(_WIN32) */ diff --git a/src/lib/fs/userdb.h b/src/lib/fs/userdb.h new file mode 100644 index 0000000000..31c891ede8 --- /dev/null +++ b/src/lib/fs/userdb.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_USERDB_H +#define TOR_USERDB_H + +#include "orconfig.h" + +#ifndef _WIN32 +#include <sys/types.h> + +struct passwd; +const struct passwd *tor_getpwnam(const char *username); +const struct passwd *tor_getpwuid(uid_t uid); +char *get_user_homedir(const char *username); +#endif + +#endif diff --git a/src/lib/fs/winlib.c b/src/lib/fs/winlib.c new file mode 100644 index 0000000000..7a88a841a6 --- /dev/null +++ b/src/lib/fs/winlib.c @@ -0,0 +1,21 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifdef _WIN32 +#include "lib/fs/winlib.h" + +HANDLE +load_windows_system_library(const TCHAR *library_name) +{ + TCHAR path[MAX_PATH]; + unsigned n; + n = GetSystemDirectory(path, MAX_PATH); + if (n == 0 || n + _tcslen(library_name) + 2 >= MAX_PATH) + return 0; + _tcscat(path, TEXT("\\")); + _tcscat(path, library_name); + return LoadLibrary(path); +} +#endif /* defined(_WIN32) */ diff --git a/src/lib/fs/winlib.h b/src/lib/fs/winlib.h new file mode 100644 index 0000000000..f53f046451 --- /dev/null +++ b/src/lib/fs/winlib.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_WINLIB_H +#define TOR_WINLIB_H + +#ifdef _WIN32 +#include <windows.h> +#include <tchar.h> + +HANDLE load_windows_system_library(const TCHAR *library_name); +#endif + +#endif diff --git a/src/lib/include.libdonna.am b/src/lib/include.libdonna.am new file mode 100644 index 0000000000..5b92dc58a0 --- /dev/null +++ b/src/lib/include.libdonna.am @@ -0,0 +1,24 @@ +src_lib_libcurve25519_donna_a_CFLAGS= + +if BUILD_CURVE25519_DONNA +src_lib_libcurve25519_donna_a_SOURCES=\ + src/ext/curve25519_donna/curve25519-donna.c +# See bug 13538 -- this code is known to have signed overflow issues. +src_lib_libcurve25519_donna_a_CFLAGS+=\ + @F_OMIT_FRAME_POINTER@ @CFLAGS_CONSTTIME@ +noinst_LIBRARIES+=src/lib/libcurve25519_donna.a +LIBDONNA=src/lib/libcurve25519_donna.a +else +if BUILD_CURVE25519_DONNA_C64 +src_lib_libcurve25519_donna_a_CFLAGS+=@CFLAGS_CONSTTIME@ +src_lib_libcurve25519_donna_a_SOURCES=\ + src/ext/curve25519_donna/curve25519-donna-c64.c +noinst_LIBRARIES+=src/lib/libcurve25519_donna.a +LIBDONNA=src/lib/libcurve25519_donna.a +else +LIBDONNA= +endif +endif + +LIBDONNA += $(LIBED25519_REF10) +LIBDONNA += $(LIBED25519_DONNA) diff --git a/src/lib/intmath/.may_include b/src/lib/intmath/.may_include new file mode 100644 index 0000000000..d96c112220 --- /dev/null +++ b/src/lib/intmath/.may_include @@ -0,0 +1,4 @@ +orconfig.h +lib/cc/*.h +lib/err/*.h +lib/intmath/*.h diff --git a/src/lib/intmath/addsub.c b/src/lib/intmath/addsub.c new file mode 100644 index 0000000000..816c5a2bd7 --- /dev/null +++ b/src/lib/intmath/addsub.c @@ -0,0 +1,20 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/intmath/addsub.h" +#include "lib/cc/compat_compiler.h" + +/* Helper: safely add two uint32_t's, capping at UINT32_MAX rather + * than overflow */ +uint32_t +tor_add_u32_nowrap(uint32_t a, uint32_t b) +{ + /* a+b > UINT32_MAX check, without overflow */ + if (PREDICT_UNLIKELY(a > UINT32_MAX - b)) { + return UINT32_MAX; + } else { + return a+b; + } +} diff --git a/src/lib/intmath/addsub.h b/src/lib/intmath/addsub.h new file mode 100644 index 0000000000..5277adfa49 --- /dev/null +++ b/src/lib/intmath/addsub.h @@ -0,0 +1,13 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_INTMATH_ADDSUB_H +#define TOR_INTMATH_ADDSUB_H + +#include "lib/cc/torint.h" + +uint32_t tor_add_u32_nowrap(uint32_t a, uint32_t b); + +#endif /* !defined(TOR_INTMATH_MULDIV_H) */ diff --git a/src/lib/intmath/bits.c b/src/lib/intmath/bits.c new file mode 100644 index 0000000000..85d901f71b --- /dev/null +++ b/src/lib/intmath/bits.c @@ -0,0 +1,88 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/intmath/bits.h" + +/** Returns floor(log2(u64)). If u64 is 0, (incorrectly) returns 0. */ +int +tor_log2(uint64_t u64) +{ + int r = 0; + if (u64 >= (U64_LITERAL(1)<<32)) { + u64 >>= 32; + r = 32; + } + if (u64 >= (U64_LITERAL(1)<<16)) { + u64 >>= 16; + r += 16; + } + if (u64 >= (U64_LITERAL(1)<<8)) { + u64 >>= 8; + r += 8; + } + if (u64 >= (U64_LITERAL(1)<<4)) { + u64 >>= 4; + r += 4; + } + if (u64 >= (U64_LITERAL(1)<<2)) { + u64 >>= 2; + r += 2; + } + if (u64 >= (U64_LITERAL(1)<<1)) { + // u64 >>= 1; // not using this any more. + r += 1; + } + return r; +} + +/** Return the power of 2 in range [1,UINT64_MAX] closest to <b>u64</b>. If + * there are two powers of 2 equally close, round down. */ +uint64_t +round_to_power_of_2(uint64_t u64) +{ + int lg2; + uint64_t low; + uint64_t high; + if (u64 == 0) + return 1; + + lg2 = tor_log2(u64); + low = U64_LITERAL(1) << lg2; + + if (lg2 == 63) + return low; + + high = U64_LITERAL(1) << (lg2+1); + if (high - u64 < u64 - low) + return high; + else + return low; +} + +/** Return the number of bits set in <b>v</b>. */ +int +n_bits_set_u8(uint8_t v) +{ + static const int nybble_table[] = { + 0, /* 0000 */ + 1, /* 0001 */ + 1, /* 0010 */ + 2, /* 0011 */ + 1, /* 0100 */ + 2, /* 0101 */ + 2, /* 0110 */ + 3, /* 0111 */ + 1, /* 1000 */ + 2, /* 1001 */ + 2, /* 1010 */ + 3, /* 1011 */ + 2, /* 1100 */ + 3, /* 1101 */ + 3, /* 1110 */ + 4, /* 1111 */ + }; + + return nybble_table[v & 15] + nybble_table[v>>4]; +} diff --git a/src/lib/intmath/bits.h b/src/lib/intmath/bits.h new file mode 100644 index 0000000000..70f855089c --- /dev/null +++ b/src/lib/intmath/bits.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_INTMATH_BITS_H +#define TOR_INTMATH_BITS_H + +#include "lib/cc/torint.h" +#include "lib/cc/compat_compiler.h" + +int tor_log2(uint64_t u64) ATTR_CONST; +uint64_t round_to_power_of_2(uint64_t u64); +int n_bits_set_u8(uint8_t v); + +#endif /* !defined(TOR_INTMATH_BITS_H) */ diff --git a/src/lib/intmath/cmp.h b/src/lib/intmath/cmp.h new file mode 100644 index 0000000000..627e5d18b4 --- /dev/null +++ b/src/lib/intmath/cmp.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_INTMATH_CMP_H +#define TOR_INTMATH_CMP_H + +/** Macros for MIN/MAX. Never use these when the arguments could have + * side-effects. + * {With GCC extensions we could probably define a safer MIN/MAX. But + * depending on that safety would be dangerous, since not every platform + * has it.} + **/ +#ifndef MAX +#define MAX(a,b) ( ((a)<(b)) ? (b) : (a) ) +#endif +#ifndef MIN +#define MIN(a,b) ( ((a)>(b)) ? (b) : (a) ) +#endif + +/* Return <b>v</b> if it's between <b>min</b> and <b>max</b>. Otherwise + * return <b>min</b> if <b>v</b> is smaller than <b>min</b>, or <b>max</b> if + * <b>b</b> is larger than <b>max</b>. + * + * Requires that <b>min</b> is no more than <b>max</b>. May evaluate any of + * its arguments more than once! */ +#define CLAMP(min,v,max) \ + ( ((v) < (min)) ? (min) : \ + ((v) > (max)) ? (max) : \ + (v) ) + +#endif /* !defined(TOR_INTMATH_CMP_H) */ diff --git a/src/lib/intmath/include.am b/src/lib/intmath/include.am new file mode 100644 index 0000000000..45ee3bd53b --- /dev/null +++ b/src/lib/intmath/include.am @@ -0,0 +1,25 @@ + +noinst_LIBRARIES += src/lib/libtor-intmath.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-intmath-testing.a +endif + +src_lib_libtor_intmath_a_SOURCES = \ + src/lib/intmath/addsub.c \ + src/lib/intmath/bits.c \ + src/lib/intmath/muldiv.c \ + src/lib/intmath/weakrng.c + +src_lib_libtor_intmath_testing_a_SOURCES = \ + $(src_lib_libtor_intmath_a_SOURCES) +src_lib_libtor_intmath_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_intmath_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/intmath/addsub.h \ + src/lib/intmath/cmp.h \ + src/lib/intmath/bits.h \ + src/lib/intmath/logic.h \ + src/lib/intmath/muldiv.h \ + src/lib/intmath/weakrng.h diff --git a/src/lib/intmath/logic.h b/src/lib/intmath/logic.h new file mode 100644 index 0000000000..0510a621dc --- /dev/null +++ b/src/lib/intmath/logic.h @@ -0,0 +1,14 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef HAVE_TOR_LOGIC_H +#define HAVE_TOR_LOGIC_H + +/** Macro: true if two values have the same boolean value. */ +#define bool_eq(a,b) (!(a)==!(b)) +/** Macro: true if two values have different boolean values. */ +#define bool_neq(a,b) (!(a)!=!(b)) + +#endif diff --git a/src/lib/intmath/muldiv.c b/src/lib/intmath/muldiv.c new file mode 100644 index 0000000000..3e627b237a --- /dev/null +++ b/src/lib/intmath/muldiv.c @@ -0,0 +1,75 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/intmath/muldiv.h" +#include "lib/err/torerr.h" + +#include <stdlib.h> + +/** Return the lowest x such that x is at least <b>number</b>, and x modulo + * <b>divisor</b> == 0. If no such x can be expressed as an unsigned, return + * UINT_MAX. Asserts if divisor is zero. */ +unsigned +round_to_next_multiple_of(unsigned number, unsigned divisor) +{ + raw_assert(divisor > 0); + if (UINT_MAX - divisor + 1 < number) + return UINT_MAX; + number += divisor - 1; + number -= number % divisor; + return number; +} + +/** Return the lowest x such that x is at least <b>number</b>, and x modulo + * <b>divisor</b> == 0. If no such x can be expressed as a uint32_t, return + * UINT32_MAX. Asserts if divisor is zero. */ +uint32_t +round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor) +{ + raw_assert(divisor > 0); + if (UINT32_MAX - divisor + 1 < number) + return UINT32_MAX; + + number += divisor - 1; + number -= number % divisor; + return number; +} + +/** Return the lowest x such that x is at least <b>number</b>, and x modulo + * <b>divisor</b> == 0. If no such x can be expressed as a uint64_t, return + * UINT64_MAX. Asserts if divisor is zero. */ +uint64_t +round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor) +{ + raw_assert(divisor > 0); + if (UINT64_MAX - divisor + 1 < number) + return UINT64_MAX; + number += divisor - 1; + number -= number % divisor; + return number; +} + +/* Helper: return greatest common divisor of a,b */ +static uint64_t +gcd64(uint64_t a, uint64_t b) +{ + while (b) { + uint64_t t = b; + b = a % b; + a = t; + } + return a; +} + +/* Given a fraction *<b>numer</b> / *<b>denom</b>, simplify it. + * Requires that the denominator is greater than 0. */ +void +simplify_fraction64(uint64_t *numer, uint64_t *denom) +{ + raw_assert(denom); + uint64_t gcd = gcd64(*numer, *denom); + *numer /= gcd; + *denom /= gcd; +} diff --git a/src/lib/intmath/muldiv.h b/src/lib/intmath/muldiv.h new file mode 100644 index 0000000000..de76d9eb68 --- /dev/null +++ b/src/lib/intmath/muldiv.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_INTMATH_MULDIV_H +#define TOR_INTMATH_MULDIV_H + +#include "lib/cc/torint.h" + +unsigned round_to_next_multiple_of(unsigned number, unsigned divisor); +uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor); +uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor); + +void simplify_fraction64(uint64_t *numer, uint64_t *denom); + +/* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b> + * and positive <b>b</b>. Works on integer types only. Not defined if a+(b-1) + * can overflow. */ +#define CEIL_DIV(a,b) (((a)+((b)-1))/(b)) + +#endif /* !defined(TOR_INTMATH_MULDIV_H) */ diff --git a/src/lib/intmath/weakrng.c b/src/lib/intmath/weakrng.c new file mode 100644 index 0000000000..2ecab97cc1 --- /dev/null +++ b/src/lib/intmath/weakrng.c @@ -0,0 +1,51 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/intmath/weakrng.h" +#include "lib/err/torerr.h" + +#include <stdlib.h> + +/** Initialize the insecure RNG <b>rng</b> from a seed value <b>seed</b>. */ +void +tor_init_weak_random(tor_weak_rng_t *rng, unsigned seed) +{ + rng->state = (uint32_t)(seed & 0x7fffffff); +} + +/** Return a randomly chosen value in the range 0..TOR_WEAK_RANDOM_MAX based + * on the RNG state of <b>rng</b>. This entropy will not be cryptographically + * strong; do not rely on it for anything an adversary should not be able to + * predict. */ +int32_t +tor_weak_random(tor_weak_rng_t *rng) +{ + /* Here's a linear congruential generator. OpenBSD and glibc use these + * parameters; they aren't too bad, and should have maximal period over the + * range 0..INT32_MAX. We don't want to use the platform rand() or random(), + * since some platforms have bad weak RNGs that only return values in the + * range 0..INT16_MAX, which just isn't enough. */ + rng->state = (rng->state * 1103515245 + 12345) & 0x7fffffff; + return (int32_t) rng->state; +} + +/** Return a random number in the range [0 , <b>top</b>). {That is, the range + * of integers i such that 0 <= i < top.} Chooses uniformly. Requires that + * top is greater than 0. This randomness is not cryptographically strong; do + * not rely on it for anything an adversary should not be able to predict. */ +int32_t +tor_weak_random_range(tor_weak_rng_t *rng, int32_t top) +{ + /* We don't want to just do tor_weak_random() % top, since random() is often + * implemented with an LCG whose modulus is a power of 2, and those are + * cyclic in their low-order bits. */ + int divisor, result; + raw_assert(top > 0); + divisor = TOR_WEAK_RANDOM_MAX / top; + do { + result = (int32_t)(tor_weak_random(rng) / divisor); + } while (result >= top); + return result; +} diff --git a/src/lib/intmath/weakrng.h b/src/lib/intmath/weakrng.h new file mode 100644 index 0000000000..e5a88b30fe --- /dev/null +++ b/src/lib/intmath/weakrng.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_WEAKRNG_H +#define TOR_WEAKRNG_H + +#include "lib/cc/torint.h" + +/* ===== Insecure rng */ +typedef struct tor_weak_rng_t { + uint32_t state; +} tor_weak_rng_t; + +#define TOR_WEAK_RNG_INIT {383745623} +#define TOR_WEAK_RANDOM_MAX (INT_MAX) +void tor_init_weak_random(tor_weak_rng_t *weak_rng, unsigned seed); +int32_t tor_weak_random(tor_weak_rng_t *weak_rng); +int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top); +/** Randomly return true according to <b>rng</b> with probability 1 in + * <b>n</b> */ +#define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n))) + +#endif diff --git a/src/lib/lock/.may_include b/src/lib/lock/.may_include new file mode 100644 index 0000000000..9522e3af49 --- /dev/null +++ b/src/lib/lock/.may_include @@ -0,0 +1,5 @@ +orconfig.h +lib/cc/*.h +lib/err/*.h +lib/lock/*.h +lib/malloc/*.h diff --git a/src/lib/lock/compat_mutex.c b/src/lib/lock/compat_mutex.c new file mode 100644 index 0000000000..e0f6224a83 --- /dev/null +++ b/src/lib/lock/compat_mutex.c @@ -0,0 +1,34 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/lock/compat_mutex.h" +#include "lib/malloc/util_malloc.h" + +/** Return a newly allocated, ready-for-use mutex. */ +tor_mutex_t * +tor_mutex_new(void) +{ + tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); + tor_mutex_init(m); + return m; +} +/** Return a newly allocated, ready-for-use mutex. This one might be + * non-recursive, if that's faster. */ +tor_mutex_t * +tor_mutex_new_nonrecursive(void) +{ + tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); + tor_mutex_init_nonrecursive(m); + return m; +} +/** Release all storage and system resources held by <b>m</b>. */ +void +tor_mutex_free_(tor_mutex_t *m) +{ + if (!m) + return; + tor_mutex_uninit(m); + tor_free(m); +} diff --git a/src/lib/lock/compat_mutex.h b/src/lib/lock/compat_mutex.h new file mode 100644 index 0000000000..92978086ac --- /dev/null +++ b/src/lib/lock/compat_mutex.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_COMPAT_MUTEX_H +#define TOR_COMPAT_MUTEX_H + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/malloc/util_malloc.h" + +#if defined(HAVE_PTHREAD_H) && !defined(_WIN32) +#include <pthread.h> +#endif + +#if defined(_WIN32) +#include <windows.h> +#endif + +#if defined(_WIN32) +#define USE_WIN32_THREADS +#elif defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_CREATE) +#define USE_PTHREADS +#else +#error "No threading system was found" +#endif /* defined(_WIN32) || ... */ + +/* Because we use threads instead of processes on most platforms (Windows, + * Linux, etc), we need locking for them. On platforms with poor thread + * support or broken gethostbyname_r, these functions are no-ops. */ + +/** A generic lock structure for multithreaded builds. */ +typedef struct tor_mutex_t { +#if defined(USE_WIN32_THREADS) + /** Windows-only: on windows, we implement locks with CRITICAL_SECTIONS. */ + CRITICAL_SECTION mutex; +#elif defined(USE_PTHREADS) + /** Pthreads-only: with pthreads, we implement locks with + * pthread_mutex_t. */ + pthread_mutex_t mutex; +#else + /** No-threads only: Dummy variable so that tor_mutex_t takes up space. */ + int _unused; +#endif /* defined(USE_WIN32_MUTEX) || ... */ +} tor_mutex_t; + +tor_mutex_t *tor_mutex_new(void); +tor_mutex_t *tor_mutex_new_nonrecursive(void); +void tor_mutex_init(tor_mutex_t *m); +void tor_mutex_init_nonrecursive(tor_mutex_t *m); +void tor_mutex_acquire(tor_mutex_t *m); +void tor_mutex_release(tor_mutex_t *m); +void tor_mutex_free_(tor_mutex_t *m); +#define tor_mutex_free(m) FREE_AND_NULL(tor_mutex_t, tor_mutex_free_, (m)) +void tor_mutex_uninit(tor_mutex_t *m); + +void tor_locking_init(void); + +#endif /* !defined(TOR_COMPAT_MUTEX_H) */ diff --git a/src/lib/lock/compat_mutex_pthreads.c b/src/lib/lock/compat_mutex_pthreads.c new file mode 100644 index 0000000000..390da4fb81 --- /dev/null +++ b/src/lib/lock/compat_mutex_pthreads.c @@ -0,0 +1,97 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/lock/compat_mutex.h" +#include "lib/cc/compat_compiler.h" +#include "lib/err/torerr.h" + +/** A mutex attribute that we're going to use to tell pthreads that we want + * "recursive" mutexes (i.e., once we can re-lock if we're already holding + * them.) */ +static pthread_mutexattr_t attr_recursive; +static int attr_initialized = 0; + +void +tor_locking_init(void) +{ + if (!attr_initialized) { + pthread_mutexattr_init(&attr_recursive); + pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE); + attr_initialized = 1; + } +} + +/** Initialize <b>mutex</b> so it can be locked. Every mutex must be set + * up with tor_mutex_init() or tor_mutex_new(); not both. */ +void +tor_mutex_init(tor_mutex_t *mutex) +{ + if (PREDICT_UNLIKELY(!attr_initialized)) + tor_locking_init(); // LCOV_EXCL_LINE + const int err = pthread_mutex_init(&mutex->mutex, &attr_recursive); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error creating a mutex."); + // LCOV_EXCL_STOP + } +} + +/** As tor_mutex_init, but initialize a mutex suitable that may be + * non-recursive, if the OS supports that. */ +void +tor_mutex_init_nonrecursive(tor_mutex_t *mutex) +{ + int err; + if (!attr_initialized) + tor_locking_init(); // LCOV_EXCL_LINE + err = pthread_mutex_init(&mutex->mutex, NULL); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error creating a mutex."); + // LCOV_EXCL_STOP + } +} + +/** Wait until <b>m</b> is free, then acquire it. */ +void +tor_mutex_acquire(tor_mutex_t *m) +{ + int err; + raw_assert(m); + err = pthread_mutex_lock(&m->mutex); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error locking a mutex."); + // LCOV_EXCL_STOP + } +} +/** Release the lock <b>m</b> so another thread can have it. */ +void +tor_mutex_release(tor_mutex_t *m) +{ + int err; + raw_assert(m); + err = pthread_mutex_unlock(&m->mutex); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error unlocking a mutex."); + // LCOV_EXCL_STOP + } +} +/** Clean up the mutex <b>m</b> so that it no longer uses any system + * resources. Does not free <b>m</b>. This function must only be called on + * mutexes from tor_mutex_init(). */ +void +tor_mutex_uninit(tor_mutex_t *m) +{ + int err; + raw_assert(m); + err = pthread_mutex_destroy(&m->mutex); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error destroying a mutex."); + // LCOV_EXCL_STOP + } +} diff --git a/src/lib/lock/compat_mutex_winthreads.c b/src/lib/lock/compat_mutex_winthreads.c new file mode 100644 index 0000000000..32be288c7f --- /dev/null +++ b/src/lib/lock/compat_mutex_winthreads.c @@ -0,0 +1,40 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/lock/compat_mutex.h" +#include "lib/err/torerr.h" + +void +tor_locking_init(void) +{ +} + +void +tor_mutex_init(tor_mutex_t *m) +{ + InitializeCriticalSection(&m->mutex); +} +void +tor_mutex_init_nonrecursive(tor_mutex_t *m) +{ + InitializeCriticalSection(&m->mutex); +} + +void +tor_mutex_uninit(tor_mutex_t *m) +{ + DeleteCriticalSection(&m->mutex); +} +void +tor_mutex_acquire(tor_mutex_t *m) +{ + raw_assert(m); + EnterCriticalSection(&m->mutex); +} +void +tor_mutex_release(tor_mutex_t *m) +{ + LeaveCriticalSection(&m->mutex); +} diff --git a/src/lib/lock/include.am b/src/lib/lock/include.am new file mode 100644 index 0000000000..4e6f444347 --- /dev/null +++ b/src/lib/lock/include.am @@ -0,0 +1,24 @@ + +noinst_LIBRARIES += src/lib/libtor-lock.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-lock-testing.a +endif + +src_lib_libtor_lock_a_SOURCES = \ + src/lib/lock/compat_mutex.c + +if THREADS_PTHREADS +src_lib_libtor_lock_a_SOURCES += src/lib/lock/compat_mutex_pthreads.c +endif +if THREADS_WIN32 +src_lib_libtor_lock_a_SOURCES += src/lib/lock/compat_mutex_winthreads.c +endif + +src_lib_libtor_lock_testing_a_SOURCES = \ + $(src_lib_libtor_lock_a_SOURCES) +src_lib_libtor_lock_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_lock_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/lock/compat_mutex.h diff --git a/src/lib/log/.may_include b/src/lib/log/.may_include new file mode 100644 index 0000000000..852173aab3 --- /dev/null +++ b/src/lib/log/.may_include @@ -0,0 +1,15 @@ +orconfig.h + +lib/cc/*.h +lib/smartlist_core/*.h +lib/err/*.h +lib/fdio/*.h +lib/intmath/*.h +lib/lock/*.h +lib/log/*.h +lib/malloc/*.h +lib/string/*.h +lib/testsupport/*.h +lib/wallclock/*.h + +micro-revision.i
\ No newline at end of file diff --git a/src/lib/log/escape.c b/src/lib/log/escape.c new file mode 100644 index 0000000000..7561710309 --- /dev/null +++ b/src/lib/log/escape.c @@ -0,0 +1,132 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/log/escape.h" +#include "lib/log/util_bug.h" +#include "lib/string/compat_ctype.h" +#include "lib/string/printf.h" +#include "lib/malloc/util_malloc.h" + +/** Allocate and return a new string representing the contents of <b>s</b>, + * surrounded by quotes and using standard C escapes. + * + * Generally, we use this for logging values that come in over the network to + * keep them from tricking users, and for sending certain values to the + * controller. + * + * We trust values from the resolver, OS, configuration file, and command line + * to not be maliciously ill-formed. We validate incoming routerdescs and + * SOCKS requests and addresses from BEGIN cells as they're parsed; + * afterwards, we trust them as non-malicious. + */ +char * +esc_for_log(const char *s) +{ + const char *cp; + char *result, *outp; + size_t len = 3; + if (!s) { + return tor_strdup("(null)"); + } + + for (cp = s; *cp; ++cp) { + switch (*cp) { + case '\\': + case '\"': + case '\'': + case '\r': + case '\n': + case '\t': + len += 2; + break; + default: + if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) + ++len; + else + len += 4; + break; + } + } + + tor_assert(len <= SSIZE_MAX); + + result = outp = tor_malloc(len); + *outp++ = '\"'; + for (cp = s; *cp; ++cp) { + /* This assertion should always succeed, since we will write at least + * one char here, and two chars for closing quote and nul later */ + tor_assert((outp-result) < (ssize_t)len-2); + switch (*cp) { + case '\\': + case '\"': + case '\'': + *outp++ = '\\'; + *outp++ = *cp; + break; + case '\n': + *outp++ = '\\'; + *outp++ = 'n'; + break; + case '\t': + *outp++ = '\\'; + *outp++ = 't'; + break; + case '\r': + *outp++ = '\\'; + *outp++ = 'r'; + break; + default: + if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) { + *outp++ = *cp; + } else { + tor_assert((outp-result) < (ssize_t)len-4); + tor_snprintf(outp, 5, "\\%03o", (int)(uint8_t) *cp); + outp += 4; + } + break; + } + } + + tor_assert((outp-result) <= (ssize_t)len-2); + *outp++ = '\"'; + *outp++ = 0; + + return result; +} + +/** Similar to esc_for_log. Allocate and return a new string representing + * the first n characters in <b>chars</b>, surround by quotes and using + * standard C escapes. If a NUL character is encountered in <b>chars</b>, + * the resulting string will be terminated there. + */ +char * +esc_for_log_len(const char *chars, size_t n) +{ + char *string = tor_strndup(chars, n); + char *string_escaped = esc_for_log(string); + tor_free(string); + return string_escaped; +} + +/** Allocate and return a new string representing the contents of <b>s</b>, + * surrounded by quotes and using standard C escapes. + * + * THIS FUNCTION IS NOT REENTRANT. Don't call it from outside the main + * thread. Also, each call invalidates the last-returned value, so don't + * try log_warn(LD_GENERAL, "%s %s", escaped(a), escaped(b)); + */ +const char * +escaped(const char *s) +{ + static char *escaped_val_ = NULL; + tor_free(escaped_val_); + + if (s) + escaped_val_ = esc_for_log(s); + else + escaped_val_ = NULL; + + return escaped_val_; +} diff --git a/src/lib/log/escape.h b/src/lib/log/escape.h new file mode 100644 index 0000000000..5d2e79d6c2 --- /dev/null +++ b/src/lib/log/escape.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_ESCAPE_H +#define TOR_ESCAPE_H + +#include "orconfig.h" +#include "lib/cc/compat_compiler.h" +#include <stddef.h> + +char *esc_for_log(const char *string) ATTR_MALLOC; +char *esc_for_log_len(const char *chars, size_t n) ATTR_MALLOC; +const char *escaped(const char *string); + +#endif /* !defined(TOR_TORLOG_H) */ diff --git a/src/lib/log/include.am b/src/lib/log/include.am new file mode 100644 index 0000000000..f0491b3863 --- /dev/null +++ b/src/lib/log/include.am @@ -0,0 +1,31 @@ + +noinst_LIBRARIES += src/lib/libtor-log.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-log-testing.a +endif + +src_lib_libtor_log_a_SOURCES = \ + src/lib/log/escape.c \ + src/lib/log/ratelim.c \ + src/lib/log/torlog.c \ + src/lib/log/util_bug.c + +if WIN32 +src_lib_libtor_log_a_SOURCES += src/lib/log/win32err.c +endif + +src_lib_libtor_log_testing_a_SOURCES = \ + $(src_lib_libtor_log_a_SOURCES) +src_lib_libtor_log_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_log_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +src/lib/log/torlog.$(OBJEXT) \ + src/lib/log/src_lib_libtor_log_testing_a-torlog.$(OBJEXT): micro-revision.i + +noinst_HEADERS += \ + src/lib/log/escape.h \ + src/lib/log/ratelim.h \ + src/lib/log/torlog.h \ + src/lib/log/util_bug.h \ + src/lib/log/win32err.h diff --git a/src/lib/log/ratelim.c b/src/lib/log/ratelim.c new file mode 100644 index 0000000000..677c499110 --- /dev/null +++ b/src/lib/log/ratelim.c @@ -0,0 +1,55 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/log/ratelim.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/printf.h" + +/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number + * of calls to rate_limit_is_ready (including this one!) since the last time + * rate_limit_is_ready returned nonzero. Otherwise return 0. + * If the call number hits <b>RATELIM_TOOMANY</b> limit, drop a warning + * about this event and stop counting. */ +static int +rate_limit_is_ready(ratelim_t *lim, time_t now) +{ + if (lim->rate + lim->last_allowed <= now) { + int res = lim->n_calls_since_last_time + 1; + lim->last_allowed = now; + lim->n_calls_since_last_time = 0; + return res; + } else { + if (lim->n_calls_since_last_time <= RATELIM_TOOMANY) { + ++lim->n_calls_since_last_time; + } + + return 0; + } +} + +/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return a newly + * allocated string indicating how many messages were suppressed, suitable to + * append to a log message. Otherwise return NULL. */ +char * +rate_limit_log(ratelim_t *lim, time_t now) +{ + int n; + if ((n = rate_limit_is_ready(lim, now))) { + if (n == 1) { + return tor_strdup(""); + } else { + char *cp=NULL; + const char *opt_over = (n >= RATELIM_TOOMANY) ? "over " : ""; + /* XXXX this is not exactly correct: the messages could have occurred + * any time between the old value of lim->allowed and now. */ + tor_asprintf(&cp, + " [%s%d similar message(s) suppressed in last %d seconds]", + opt_over, n-1, lim->rate); + return cp; + } + } else { + return NULL; + } +} diff --git a/src/lib/log/ratelim.h b/src/lib/log/ratelim.h new file mode 100644 index 0000000000..4ee6c5fed4 --- /dev/null +++ b/src/lib/log/ratelim.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_RATELIM_H +#define TOR_RATELIM_H + +#include <time.h> + +/* Rate-limiter */ + +/** A ratelim_t remembers how often an event is occurring, and how often + * it's allowed to occur. Typical usage is something like: + * + <pre> + if (possibly_very_frequent_event()) { + const int INTERVAL = 300; + static ratelim_t warning_limit = RATELIM_INIT(INTERVAL); + char *m; + if ((m = rate_limit_log(&warning_limit, approx_time()))) { + log_warn(LD_GENERAL, "The event occurred!%s", m); + tor_free(m); + } + } + </pre> + + As a convenience wrapper for logging, you can replace the above with: + <pre> + if (possibly_very_frequent_event()) { + static ratelim_t warning_limit = RATELIM_INIT(300); + log_fn_ratelim(&warning_limit, LOG_WARN, LD_GENERAL, + "The event occurred!"); + } + </pre> + */ +typedef struct ratelim_t { + int rate; + time_t last_allowed; + int n_calls_since_last_time; +} ratelim_t; + +#define RATELIM_INIT(r) { (r), 0, 0 } +#define RATELIM_TOOMANY (16*1000*1000) + +char *rate_limit_log(ratelim_t *lim, time_t now); + +#endif diff --git a/src/common/log.c b/src/lib/log/torlog.c index ebd50f62d3..1c9f33790d 100644 --- a/src/common/log.c +++ b/src/lib/log/torlog.c @@ -1,18 +1,17 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file log.c + * \file torlog.c * \brief Functions to send messages to log files or the console. **/ #include "orconfig.h" #include <stdarg.h> -#include <assert.h> -// #include <stdio.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef HAVE_SYS_TIME_H @@ -30,11 +29,25 @@ #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif -#include "compat.h" -#include "util.h" + #define LOG_PRIVATE -#include "torlog.h" -#include "container.h" +#include "lib/log/torlog.h" +#include "lib/log/ratelim.h" +#include "lib/lock/compat_mutex.h" +#include "lib/smartlist_core/smartlist_core.h" +#include "lib/smartlist_core/smartlist_foreach.h" +#include "lib/smartlist_core/smartlist_split.h" +#include "lib/err/torerr.h" +#include "lib/intmath/bits.h" +#include "lib/string/compat_string.h" +#include "lib/string/printf.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/util_string.h" +#include "lib/wallclock/tor_gettimeofday.h" +#include "lib/wallclock/approx_time.h" +#include "lib/wallclock/tm_cvt.h" +#include "lib/fdio/fdio.h" + #ifdef HAVE_ANDROID_LOG_H #include <android/log.h> #endif // HAVE_ANDROID_LOG_H. @@ -50,8 +63,6 @@ #define TRUNCATED_STR_LEN 14 /** @} */ -#define raw_assert(x) assert(x) // assert OK - /** Defining compile-time constants for Tor log levels (used by the Rust * log wrapper at src/rust/tor_log) */ const int LOG_WARN_ = LOG_WARN; @@ -89,9 +100,9 @@ sev_to_string(int severity) case LOG_NOTICE: return "notice"; case LOG_WARN: return "warn"; case LOG_ERR: return "err"; - default: /* Call assert, not tor_assert, since tor_assert - * calls log on failure. */ - raw_assert(0); return "UNKNOWN"; // LCOV_EXCL_LINE + default: /* Call assert, not tor_assert, since tor_assert + * calls log on failure. */ + raw_assert_unreached(); return "UNKNOWN"; // LCOV_EXCL_LINE } } @@ -195,12 +206,12 @@ static int pretty_fn_has_parens = 0; /** Lock the log_mutex to prevent others from changing the logfile_t list */ #define LOCK_LOGS() STMT_BEGIN \ - tor_assert(log_mutex_initialized); \ + raw_assert(log_mutex_initialized); \ tor_mutex_acquire(&log_mutex); \ STMT_END /** Unlock the log_mutex */ #define UNLOCK_LOGS() STMT_BEGIN \ - tor_assert(log_mutex_initialized); \ + raw_assert(log_mutex_initialized); \ tor_mutex_release(&log_mutex); \ STMT_END @@ -268,6 +279,7 @@ void set_log_time_granularity(int granularity_msec) { log_time_granularity = granularity_msec; + tor_log_sigsafe_err_set_granularity(granularity_msec); } /** Helper: Write the standard prefix for log lines to a @@ -292,7 +304,8 @@ log_prefix_(char *buf, size_t buf_len, int severity) ms -= ((int)now.tv_usec / 1000) % log_time_granularity; } - n = strftime(buf, buf_len, "%b %d %H:%M:%S", tor_localtime_r(&t, &tm)); + n = strftime(buf, buf_len, "%b %d %H:%M:%S", + tor_localtime_r_msg(&t, &tm, NULL)); r = tor_snprintf(buf+n, buf_len-n, ".%.3i [%s] ", ms, sev_to_string(severity)); @@ -335,7 +348,7 @@ log_tor_version(logfile_t *lf, int reset) tor_snprintf(buf+n, sizeof(buf)-n, "Tor %s opening %slog file.\n", VERSION, is_new?"new ":""); } - if (write_all(lf->fd, buf, strlen(buf), 0) < 0) /* error */ + if (write_all_to_fd_minimal(lf->fd, buf, strlen(buf)) < 0) /* error */ return -1; /* failed */ return 0; } @@ -549,7 +562,7 @@ logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len, lf->callback(severity, domain, msg_after_prefix); } } else { - if (write_all(lf->fd, buf, msg_len, 0) < 0) { /* error */ + if (write_all_to_fd_minimal(lf->fd, buf, msg_len) < 0) { /* error */ /* don't log the error! mark this log entry to be blown away, and * continue. */ lf->seems_dead = 1; @@ -572,7 +585,7 @@ logv,(int severity, log_domain_mask_t domain, const char *funcname, char *end_of_prefix=NULL; int callbacks_deferred = 0; - /* Call assert, not tor_assert, since tor_assert calls log on failure. */ + /* Call assert, not raw_assert, since raw_assert calls log on failure. */ raw_assert(format); /* check that severity is sane. Overrunning the masks array leads to * interesting and hard to diagnose effects */ @@ -634,71 +647,6 @@ tor_log(int severity, log_domain_mask_t domain, const char *format, ...) va_end(ap); } -/** Maximum number of fds that will get notifications if we crash */ -#define MAX_SIGSAFE_FDS 8 -/** Array of fds to log crash-style warnings to. */ -static int sigsafe_log_fds[MAX_SIGSAFE_FDS] = { STDERR_FILENO }; -/** The number of elements used in sigsafe_log_fds */ -static int n_sigsafe_log_fds = 1; - -/** Write <b>s</b> to each element of sigsafe_log_fds. Return 0 on success, -1 - * on failure. */ -static int -tor_log_err_sigsafe_write(const char *s) -{ - int i; - ssize_t r; - size_t len = strlen(s); - int err = 0; - for (i=0; i < n_sigsafe_log_fds; ++i) { - r = write(sigsafe_log_fds[i], s, len); - err += (r != (ssize_t)len); - } - return err ? -1 : 0; -} - -/** Given a list of string arguments ending with a NULL, writes them - * to our logs and to stderr (if possible). This function is safe to call - * from within a signal handler. */ -void -tor_log_err_sigsafe(const char *m, ...) -{ - va_list ap; - const char *x; - char timebuf[33]; - time_t now = time(NULL); - - if (!m) - return; - if (log_time_granularity >= 2000) { - int g = log_time_granularity / 1000; - now -= now % g; - } - timebuf[0] = now < 0 ? '-' : ' '; - if (now < 0) now = -now; - timebuf[1] = '\0'; - format_dec_number_sigsafe(now, timebuf+1, sizeof(timebuf)-1); - tor_log_err_sigsafe_write("\n==========================================" - "================== T="); - tor_log_err_sigsafe_write(timebuf); - tor_log_err_sigsafe_write("\n"); - tor_log_err_sigsafe_write(m); - va_start(ap, m); - while ((x = va_arg(ap, const char*))) { - tor_log_err_sigsafe_write(x); - } - va_end(ap); -} - -/** Set *<b>out</b> to a pointer to an array of the fds to log errors to from - * inside a signal handler. Return the number of elements in the array. */ -int -tor_log_get_sigsafe_err_fds(const int **out) -{ - *out = sigsafe_log_fds; - return n_sigsafe_log_fds; -} - /** Helper function; return true iff the <b>n</b>-element array <b>array</b> * contains <b>item</b>. */ static int @@ -720,11 +668,14 @@ tor_log_update_sigsafe_err_fds(void) const logfile_t *lf; int found_real_stderr = 0; + int fds[TOR_SIGSAFE_LOG_MAX_FDS]; + int n_fds; + LOCK_LOGS(); /* Reserve the first one for stderr. This is safe because when we daemonize, * we dup2 /dev/null to stderr, */ - sigsafe_log_fds[0] = STDERR_FILENO; - n_sigsafe_log_fds = 1; + fds[0] = STDERR_FILENO; + n_fds = 1; for (lf = logfiles; lf; lf = lf->next) { /* Don't try callback to the control port, or syslogs: We can't @@ -738,22 +689,24 @@ tor_log_update_sigsafe_err_fds(void) if (lf->fd == STDERR_FILENO) found_real_stderr = 1; /* Avoid duplicates */ - if (int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, lf->fd)) + if (int_array_contains(fds, n_fds, lf->fd)) continue; - sigsafe_log_fds[n_sigsafe_log_fds++] = lf->fd; - if (n_sigsafe_log_fds == MAX_SIGSAFE_FDS) + fds[n_fds++] = lf->fd; + if (n_fds == TOR_SIGSAFE_LOG_MAX_FDS) break; } } if (!found_real_stderr && - int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, STDOUT_FILENO)) { + int_array_contains(fds, n_fds, STDOUT_FILENO)) { /* Don't use a virtual stderr when we're also logging to stdout. */ - raw_assert(n_sigsafe_log_fds >= 2); /* Don't tor_assert inside log fns */ - sigsafe_log_fds[0] = sigsafe_log_fds[--n_sigsafe_log_fds]; + raw_assert(n_fds >= 2); /* Don't raw_assert inside log fns */ + fds[0] = fds[--n_fds]; } UNLOCK_LOGS(); + + tor_log_set_sigsafe_err_fds(fds, n_fds); } /** Add to <b>out</b> a copy of every currently configured log file name. Used @@ -762,7 +715,7 @@ void tor_log_get_logfile_names(smartlist_t *out) { logfile_t *lf; - tor_assert(out); + raw_assert(out); LOCK_LOGS(); @@ -875,8 +828,8 @@ delete_log(logfile_t *victim) logfiles = victim->next; else { for (tmpl = logfiles; tmpl && tmpl->next != victim; tmpl=tmpl->next) ; -// tor_assert(tmpl); -// tor_assert(tmpl->next == victim); +// raw_assert(tmpl); +// raw_assert(tmpl->next == victim); if (!tmpl) return; tmpl->next = victim->next; @@ -910,9 +863,9 @@ set_log_severity_config(int loglevelMin, int loglevelMax, log_severity_list_t *severity_out) { int i; - tor_assert(loglevelMin >= loglevelMax); - tor_assert(loglevelMin >= LOG_ERR && loglevelMin <= LOG_DEBUG); - tor_assert(loglevelMax >= LOG_ERR && loglevelMax <= LOG_DEBUG); + raw_assert(loglevelMin >= loglevelMax); + raw_assert(loglevelMin >= LOG_ERR && loglevelMin <= LOG_DEBUG); + raw_assert(loglevelMax >= LOG_ERR && loglevelMax <= LOG_DEBUG); memset(severity_out, 0, sizeof(log_severity_list_t)); for (i = loglevelMin; i >= loglevelMax; --i) { severity_out->masks[SEVERITY_MASK_IDX(i)] = ~0u; @@ -1182,20 +1135,17 @@ mark_logs_temp(void) } /** - * Add a log handler to send messages to <b>filename</b>. If opening the - * logfile fails, -1 is returned and errno is set appropriately (by open(2)). + * Add a log handler to send messages to <b>filename</b> via <b>fd</b>. If + * opening the logfile failed, -1 is returned and errno is set appropriately + * (by open(2)). Takes ownership of fd. */ int -add_file_log(const log_severity_list_t *severity, const char *filename, - const int truncate_log) +add_file_log(const log_severity_list_t *severity, + const char *filename, + int fd) { - int fd; logfile_t *lf; - int open_flags = O_WRONLY|O_CREAT; - open_flags |= truncate_log ? O_TRUNC : O_APPEND; - - fd = tor_open_cloexec(filename, open_flags, 0640); if (fd<0) return -1; if (tor_fd_seekend(fd)<0) { @@ -1536,4 +1486,3 @@ truncate_logs(void) } } } - diff --git a/src/common/torlog.h b/src/lib/log/torlog.h index de389883c0..c24b638191 100644 --- a/src/common/torlog.h +++ b/src/lib/log/torlog.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,10 @@ #ifndef TOR_TORLOG_H -#include "compat.h" -#include "testsupport.h" +#include <stdarg.h> +#include "lib/cc/torint.h" +#include "lib/cc/compat_compiler.h" +#include "lib/testsupport/testsupport.h" #ifdef HAVE_SYSLOG_H #include <syslog.h> @@ -143,8 +145,10 @@ void set_log_severity_config(int minSeverity, int maxSeverity, log_severity_list_t *severity_out); void add_stream_log(const log_severity_list_t *severity, const char *name, int fd); -int add_file_log(const log_severity_list_t *severity, const char *filename, - const int truncate); +int add_file_log(const log_severity_list_t *severity, + const char *filename, + int fd); + #ifdef HAVE_SYSLOG_H int add_syslog_log(const log_severity_list_t *severity, const char* syslog_identity_tag); @@ -175,8 +179,6 @@ void truncate_logs(void); void tor_log(int severity, log_domain_mask_t domain, const char *format, ...) CHECK_PRINTF(3,4); -void tor_log_err_sigsafe(const char *m, ...); -int tor_log_get_sigsafe_err_fds(const int **out); void tor_log_update_sigsafe_err_fds(void); struct smartlist_t; @@ -272,4 +274,3 @@ MOCK_DECL(STATIC void, logv, (int severity, log_domain_mask_t domain, # define TOR_TORLOG_H #endif /* !defined(TOR_TORLOG_H) */ - diff --git a/src/common/util_bug.c b/src/lib/log/util_bug.c index 126e843866..78af08f022 100644 --- a/src/common/util_bug.c +++ b/src/lib/log/util_bug.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,10 +8,17 @@ **/ #include "orconfig.h" -#include "util_bug.h" -#include "torlog.h" -#include "backtrace.h" -#include "container.h" +#include "lib/log/util_bug.h" +#include "lib/log/torlog.h" +#include "lib/err/backtrace.h" +#ifdef TOR_UNIT_TESTS +#include "lib/smartlist_core/smartlist_core.h" +#include "lib/smartlist_core/smartlist_foreach.h" +#endif +#include "lib/malloc/util_malloc.h" +#include "lib/string/printf.h" + +#include <string.h> #ifdef __COVERITY__ int bug_macro_deadcode_dummy__ = 0; @@ -117,3 +124,28 @@ tor_bug_occurred_(const char *fname, unsigned int line, #endif } +#ifdef _WIN32 +/** Take a filename and return a pointer to its final element. This + * function is called on __FILE__ to fix a MSVC nit where __FILE__ + * contains the full path to the file. This is bad, because it + * confuses users to find the home directory of the person who + * compiled the binary in their warning messages. + */ +const char * +tor_fix_source_file(const char *fname) +{ + const char *cp1, *cp2, *r; + cp1 = strrchr(fname, '/'); + cp2 = strrchr(fname, '\\'); + if (cp1 && cp2) { + r = (cp1<cp2)?(cp2+1):(cp1+1); + } else if (cp1) { + r = cp1+1; + } else if (cp2) { + r = cp2+1; + } else { + r = fname; + } + return r; +} +#endif /* defined(_WIN32) */ diff --git a/src/common/util_bug.h b/src/lib/log/util_bug.h index be549fde07..a0753c807b 100644 --- a/src/common/util_bug.h +++ b/src/lib/log/util_bug.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -37,8 +37,9 @@ #define TOR_UTIL_BUG_H #include "orconfig.h" -#include "compat.h" -#include "testsupport.h" +#include "lib/cc/compat_compiler.h" +#include "lib/log/torlog.h" +#include "lib/testsupport/testsupport.h" /* Replace assert() with a variant that sends failures to the log before * calling assert() normally. @@ -191,6 +192,14 @@ void tor_bug_occurred_(const char *fname, unsigned int line, const char *func, const char *expr, int once); +#ifdef _WIN32 +#define SHORT_FILE__ (tor_fix_source_file(__FILE__)) +const char *tor_fix_source_file(const char *fname); +#else +#define SHORT_FILE__ (__FILE__) +#define tor_fix_source_file(s) (s) +#endif /* defined(_WIN32) */ + #ifdef TOR_UNIT_TESTS void tor_capture_bugs_(int n); void tor_end_capture_bugs_(void); @@ -199,4 +208,3 @@ void tor_set_failed_assertion_callback(void (*fn)(void)); #endif /* defined(TOR_UNIT_TESTS) */ #endif /* !defined(TOR_UTIL_BUG_H) */ - diff --git a/src/lib/log/win32err.c b/src/lib/log/win32err.c new file mode 100644 index 0000000000..4586c23c84 --- /dev/null +++ b/src/lib/log/win32err.c @@ -0,0 +1,56 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifdef _WIN32 +#include "orconfig.h" +#include "lib/log/win32err.h" +#include "lib/malloc/util_malloc.h" + +#include <tchar.h> +#include <windows.h> + +/** Return a newly allocated string describing the windows system error code + * <b>err</b>. Note that error codes are different from errno. Error codes + * come from GetLastError() when a winapi call fails. errno is set only when + * ANSI functions fail. Whee. */ +char * +format_win32_error(DWORD err) +{ + TCHAR *str = NULL; + char *result; + DWORD n; + + /* Somebody once decided that this interface was better than strerror(). */ + n = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, + MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), + (LPVOID)&str, + 0, NULL); + + if (str && n) { +#ifdef UNICODE + size_t len; + if (n > 128*1024) + len = (128 * 1024) * 2 + 1; /* This shouldn't be possible, but let's + * make sure. */ + else + len = n * 2 + 1; + result = tor_malloc(len); + wcstombs(result,str,len); + result[len-1] = '\0'; +#else /* !(defined(UNICODE)) */ + result = tor_strdup(str); +#endif /* defined(UNICODE) */ + } else { + result = tor_strdup("<unformattable error>"); + } + if (str) { + LocalFree(str); /* LocalFree != free() */ + } + return result; +} +#endif /* defined(_WIN32) */ diff --git a/src/lib/log/win32err.h b/src/lib/log/win32err.h new file mode 100644 index 0000000000..61d3af57dd --- /dev/null +++ b/src/lib/log/win32err.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_WIN32ERR_H +#define TOR_WIN32ERR_H + +#include "orconfig.h" + +/* Platform-specific helpers. */ +#ifdef _WIN32 +#include <windef.h> +char *format_win32_error(DWORD err); +#endif + +#endif diff --git a/src/lib/malloc/.may_include b/src/lib/malloc/.may_include new file mode 100644 index 0000000000..cc62bb1013 --- /dev/null +++ b/src/lib/malloc/.may_include @@ -0,0 +1,6 @@ +orconfig.h + +lib/cc/*.h +lib/err/*.h +lib/malloc/*.h +lib/testsupport/testsupport.h diff --git a/src/lib/malloc/include.am b/src/lib/malloc/include.am new file mode 100644 index 0000000000..b4c5cae54d --- /dev/null +++ b/src/lib/malloc/include.am @@ -0,0 +1,17 @@ + +noinst_LIBRARIES += src/lib/libtor-malloc.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-malloc-testing.a +endif + +src_lib_libtor_malloc_a_SOURCES = \ + src/lib/malloc/util_malloc.c + +src_lib_libtor_malloc_testing_a_SOURCES = \ + $(src_lib_libtor_malloc_a_SOURCES) +src_lib_libtor_malloc_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_malloc_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/malloc/util_malloc.h diff --git a/src/lib/malloc/util_malloc.c b/src/lib/malloc/util_malloc.c new file mode 100644 index 0000000000..f3b0e50c70 --- /dev/null +++ b/src/lib/malloc/util_malloc.c @@ -0,0 +1,230 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file util_malloc.c + * \brief Wrappers for C malloc code, and replacements for items that + * may be missing. + **/ + +#include "orconfig.h" + +#include <stdlib.h> +#include <string.h> + +#include "lib/testsupport/testsupport.h" +#define UTIL_MALLOC_PRIVATE +#include "lib/malloc/util_malloc.h" +#include "lib/cc/torint.h" +#include "lib/err/torerr.h" + +#ifdef __clang_analyzer__ +#undef MALLOC_ZERO_WORKS +#endif + +/** Allocate a chunk of <b>size</b> bytes of memory, and return a pointer to + * result. On error, log and terminate the process. (Same as malloc(size), + * but never returns NULL.) + */ +void * +tor_malloc_(size_t size) +{ + void *result; + + raw_assert(size < SIZE_T_CEILING); + +#ifndef MALLOC_ZERO_WORKS + /* Some libc mallocs don't work when size==0. Override them. */ + if (size==0) { + size=1; + } +#endif /* !defined(MALLOC_ZERO_WORKS) */ + + result = raw_malloc(size); + + if (PREDICT_UNLIKELY(result == NULL)) { + /* LCOV_EXCL_START */ + /* If these functions die within a worker process, they won't call + * spawn_exit, but that's ok, since the parent will run out of memory soon + * anyway. */ + raw_assert_unreached_msg("Out of memory on malloc(). Dying."); + /* LCOV_EXCL_STOP */ + } + return result; +} + +/** Allocate a chunk of <b>size</b> bytes of memory, fill the memory with + * zero bytes, and return a pointer to the result. Log and terminate + * the process on error. (Same as calloc(size,1), but never returns NULL.) + */ +void * +tor_malloc_zero_(size_t size) +{ + /* You may ask yourself, "wouldn't it be smart to use calloc instead of + * malloc+memset? Perhaps libc's calloc knows some nifty optimization trick + * we don't!" Indeed it does, but its optimizations are only a big win when + * we're allocating something very big (it knows if it just got the memory + * from the OS in a pre-zeroed state). We don't want to use tor_malloc_zero + * for big stuff, so we don't bother with calloc. */ + void *result = tor_malloc_(size); + memset(result, 0, size); + return result; +} + +/* The square root of SIZE_MAX + 1. If a is less than this, and b is less + * than this, then a*b is less than SIZE_MAX. (For example, if size_t is + * 32 bits, then SIZE_MAX is 0xffffffff and this value is 0x10000. If a and + * b are less than this, then their product is at most (65535*65535) == + * 0xfffe0001. */ +#define SQRT_SIZE_MAX_P1 (((size_t)1) << (sizeof(size_t)*4)) + +/** Return non-zero if and only if the product of the arguments is exact, + * and cannot overflow. */ +STATIC int +size_mul_check(const size_t x, const size_t y) +{ + /* This first check is equivalent to + (x < SQRT_SIZE_MAX_P1 && y < SQRT_SIZE_MAX_P1) + + Rationale: if either one of x or y is >= SQRT_SIZE_MAX_P1, then it + will have some bit set in its most significant half. + */ + return ((x|y) < SQRT_SIZE_MAX_P1 || + y == 0 || + x <= SIZE_MAX / y); +} + +/** Allocate a chunk of <b>nmemb</b>*<b>size</b> bytes of memory, fill + * the memory with zero bytes, and return a pointer to the result. + * Log and terminate the process on error. (Same as + * calloc(<b>nmemb</b>,<b>size</b>), but never returns NULL.) + * The second argument (<b>size</b>) should preferably be non-zero + * and a compile-time constant. + */ +void * +tor_calloc_(size_t nmemb, size_t size) +{ + raw_assert(size_mul_check(nmemb, size)); + return tor_malloc_zero_((nmemb * size)); +} + +/** Change the size of the memory block pointed to by <b>ptr</b> to <b>size</b> + * bytes long; return the new memory block. On error, log and + * terminate. (Like realloc(ptr,size), but never returns NULL.) + */ +void * +tor_realloc_(void *ptr, size_t size) +{ + void *result; + + raw_assert(size < SIZE_T_CEILING); + +#ifndef MALLOC_ZERO_WORKS + /* Some libc mallocs don't work when size==0. Override them. */ + if (size==0) { + size=1; + } +#endif /* !defined(MALLOC_ZERO_WORKS) */ + + result = raw_realloc(ptr, size); + + if (PREDICT_UNLIKELY(result == NULL)) { + /* LCOV_EXCL_START */ + raw_assert_unreached_msg("Out of memory on realloc(). Dying."); + /* LCOV_EXCL_STOP */ + } + return result; +} + +/** + * Try to realloc <b>ptr</b> so that it takes up sz1 * sz2 bytes. Check for + * overflow. Unlike other allocation functions, return NULL on overflow. + */ +void * +tor_reallocarray_(void *ptr, size_t sz1, size_t sz2) +{ + /* XXXX we can make this return 0, but we would need to check all the + * reallocarray users. */ + raw_assert(size_mul_check(sz1, sz2)); + + return tor_realloc(ptr, (sz1 * sz2)); +} + +/** Return a newly allocated copy of the NUL-terminated string s. On + * error, log and terminate. (Like strdup(s), but never returns + * NULL.) + */ +char * +tor_strdup_(const char *s) +{ + char *duplicate; + raw_assert(s); + + duplicate = raw_strdup(s); + + if (PREDICT_UNLIKELY(duplicate == NULL)) { + /* LCOV_EXCL_START */ + raw_assert_unreached_msg("Out of memory on strdup(). Dying."); + /* LCOV_EXCL_STOP */ + } + return duplicate; +} + +/** Allocate and return a new string containing the first <b>n</b> + * characters of <b>s</b>. If <b>s</b> is longer than <b>n</b> + * characters, only the first <b>n</b> are copied. The result is + * always NUL-terminated. (Like strndup(s,n), but never returns + * NULL.) + */ +char * +tor_strndup_(const char *s, size_t n) +{ + char *duplicate; + raw_assert(s); + raw_assert(n < SIZE_T_CEILING); + duplicate = tor_malloc_((n+1)); + /* Performance note: Ordinarily we prefer strlcpy to strncpy. But + * this function gets called a whole lot, and platform strncpy is + * much faster than strlcpy when strlen(s) is much longer than n. + */ + strncpy(duplicate, s, n); + duplicate[n]='\0'; + return duplicate; +} + +/** Allocate a chunk of <b>len</b> bytes, with the same contents as the + * <b>len</b> bytes starting at <b>mem</b>. */ +void * +tor_memdup_(const void *mem, size_t len) +{ + char *duplicate; + raw_assert(len < SIZE_T_CEILING); + raw_assert(mem); + duplicate = tor_malloc_(len); + memcpy(duplicate, mem, len); + return duplicate; +} + +/** As tor_memdup(), but add an extra 0 byte at the end of the resulting + * memory. */ +void * +tor_memdup_nulterm_(const void *mem, size_t len) +{ + char *duplicate; + raw_assert(len < SIZE_T_CEILING+1); + raw_assert(mem); + duplicate = tor_malloc_(len+1); + memcpy(duplicate, mem, len); + duplicate[len] = '\0'; + return duplicate; +} + +/** Helper for places that need to take a function pointer to the right + * spelling of "free()". */ +void +tor_free_(void *mem) +{ + tor_free(mem); +} diff --git a/src/lib/malloc/util_malloc.h b/src/lib/malloc/util_malloc.h new file mode 100644 index 0000000000..88ecc04530 --- /dev/null +++ b/src/lib/malloc/util_malloc.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file util_malloc.h + * \brief Headers for util_malloc.c + **/ + +#ifndef TOR_UTIL_MALLOC_H +#define TOR_UTIL_MALLOC_H + +#include <stddef.h> +#include <stdlib.h> +#include "lib/cc/compat_compiler.h" + +/* Memory management */ +void *tor_malloc_(size_t size) ATTR_MALLOC; +void *tor_malloc_zero_(size_t size) ATTR_MALLOC; +void *tor_calloc_(size_t nmemb, size_t size) ATTR_MALLOC; +void *tor_realloc_(void *ptr, size_t size); +void *tor_reallocarray_(void *ptr, size_t size1, size_t size2); +char *tor_strdup_(const char *s) ATTR_MALLOC ATTR_NONNULL((1)); +char *tor_strndup_(const char *s, size_t n) + ATTR_MALLOC ATTR_NONNULL((1)); +void *tor_memdup_(const void *mem, size_t len) + ATTR_MALLOC ATTR_NONNULL((1)); +void *tor_memdup_nulterm_(const void *mem, size_t len) + ATTR_MALLOC ATTR_NONNULL((1)); +void tor_free_(void *mem); + +/** Release memory allocated by tor_malloc, tor_realloc, tor_strdup, + * etc. Unlike the free() function, the tor_free() macro sets the + * pointer value to NULL after freeing it. + * + * This is a macro. If you need a function pointer to release memory from + * tor_malloc(), use tor_free_(). + * + * Note that this macro takes the address of the pointer it is going to + * free and clear. If that pointer is stored with a nonstandard + * alignment (eg because of a "packed" pragma) it is not correct to use + * tor_free(). + */ +#ifdef __GNUC__ +#define tor_free(p) STMT_BEGIN \ + typeof(&(p)) tor_free__tmpvar = &(p); \ + raw_free(*tor_free__tmpvar); \ + *tor_free__tmpvar=NULL; \ + STMT_END +#else +#define tor_free(p) STMT_BEGIN \ + raw_free(p); \ + (p)=NULL; \ + STMT_END +#endif + +#define tor_malloc(size) tor_malloc_(size) +#define tor_malloc_zero(size) tor_malloc_zero_(size) +#define tor_calloc(nmemb,size) tor_calloc_(nmemb, size) +#define tor_realloc(ptr, size) tor_realloc_(ptr, size) +#define tor_reallocarray(ptr, sz1, sz2) \ + tor_reallocarray_((ptr), (sz1), (sz2)) +#define tor_strdup(s) tor_strdup_(s) +#define tor_strndup(s, n) tor_strndup_(s, n) +#define tor_memdup(s, n) tor_memdup_(s, n) +#define tor_memdup_nulterm(s, n) tor_memdup_nulterm_(s, n) + +/* Aliases for the underlying system malloc/realloc/free. Only use + * them to indicate "I really want the underlying system function, I know + * what I'm doing." */ +#define raw_malloc malloc +#define raw_realloc realloc +#define raw_free free +#define raw_strdup strdup + +/* Helper macro: free a variable of type 'typename' using freefn, and + * set the variable to NULL. + */ +#define FREE_AND_NULL(typename, freefn, var) \ + do { \ + /* only evaluate (var) once. */ \ + typename **tmp__free__ptr ## freefn = &(var); \ + freefn(*tmp__free__ptr ## freefn); \ + (*tmp__free__ptr ## freefn) = NULL; \ + } while (0) + +#ifdef UTIL_MALLOC_PRIVATE +STATIC int size_mul_check(const size_t x, const size_t y); +#endif + +#endif /* !defined(TOR_UTIL_MALLOC_H) */ diff --git a/src/lib/math/.may_include b/src/lib/math/.may_include new file mode 100644 index 0000000000..1fd26864dc --- /dev/null +++ b/src/lib/math/.may_include @@ -0,0 +1,5 @@ +orconfig.h + +lib/cc/*.h +lib/log/*.h +lib/math/*.h diff --git a/src/lib/math/fp.c b/src/lib/math/fp.c new file mode 100644 index 0000000000..d1c4428251 --- /dev/null +++ b/src/lib/math/fp.c @@ -0,0 +1,113 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/math/fp.h" + +#include <math.h> + +/** + * Returns the natural logarithm of d base e. We defined this wrapper here so + * to avoid conflicts with old versions of tor_log(), which were named log(). + */ +double +tor_mathlog(double d) +{ + return log(d); +} + +/** Return the long integer closest to <b>d</b>. We define this wrapper + * here so that not all users of math.h need to use the right incantations + * to get the c99 functions. */ +long +tor_lround(double d) +{ +#if defined(HAVE_LROUND) + return lround(d); +#elif defined(HAVE_RINT) + return (long)rint(d); +#else + return (long)(d > 0 ? d + 0.5 : ceil(d - 0.5)); +#endif /* defined(HAVE_LROUND) || ... */ +} + +/** Return the 64-bit integer closest to d. We define this wrapper here so + * that not all users of math.h need to use the right incantations to get the + * c99 functions. */ +int64_t +tor_llround(double d) +{ +#if defined(HAVE_LLROUND) + return (int64_t)llround(d); +#elif defined(HAVE_RINT) + return (int64_t)rint(d); +#else + return (int64_t)(d > 0 ? d + 0.5 : ceil(d - 0.5)); +#endif /* defined(HAVE_LLROUND) || ... */ +} + +/** Cast a given double value to a int64_t. Return 0 if number is NaN. + * Returns either INT64_MIN or INT64_MAX if number is outside of the int64_t + * range. */ +int64_t +clamp_double_to_int64(double number) +{ + int exponent; + +#if defined(MINGW_ANY) && GCC_VERSION >= 409 +/* + Mingw's math.h uses gcc's __builtin_choose_expr() facility to declare + isnan, isfinite, and signbit. But as implemented in at least some + versions of gcc, __builtin_choose_expr() can generate type warnings + even from branches that are not taken. So, suppress those warnings. +*/ +#define PROBLEMATIC_FLOAT_CONVERSION_WARNING +DISABLE_GCC_WARNING(float-conversion) +#endif /* defined(MINGW_ANY) && GCC_VERSION >= 409 */ + +/* + With clang 4.0 we apparently run into "double promotion" warnings here, + since clang thinks we're promoting a double to a long double. + */ +#if defined(__clang__) +#if __has_warning("-Wdouble-promotion") +#define PROBLEMATIC_DOUBLE_PROMOTION_WARNING +DISABLE_GCC_WARNING(double-promotion) +#endif +#endif /* defined(__clang__) */ + + /* NaN is a special case that can't be used with the logic below. */ + if (isnan(number)) { + return 0; + } + + /* Time to validate if result can overflows a int64_t value. Fun with + * float! Find that exponent exp such that + * number == x * 2^exp + * for some x with abs(x) in [0.5, 1.0). Note that this implies that the + * magnitude of number is strictly less than 2^exp. + * + * If number is infinite, the call to frexp is legal but the contents of + * are exponent unspecified. */ + frexp(number, &exponent); + + /* If the magnitude of number is strictly less than 2^63, the truncated + * version of number is guaranteed to be representable. The only + * representable integer for which this is not the case is INT64_MIN, but + * it is covered by the logic below. */ + if (isfinite(number) && exponent <= 63) { + return (int64_t)number; + } + + /* Handle infinities and finite numbers with magnitude >= 2^63. */ + return signbit(number) ? INT64_MIN : INT64_MAX; + +#ifdef PROBLEMATIC_DOUBLE_PROMOTION_WARNING +ENABLE_GCC_WARNING(double-promotion) +#endif +#ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING +ENABLE_GCC_WARNING(float-conversion) +#endif +} diff --git a/src/lib/math/fp.h b/src/lib/math/fp.h new file mode 100644 index 0000000000..b35c18a1c7 --- /dev/null +++ b/src/lib/math/fp.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_FP_H +#define TOR_FP_H + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" + +double tor_mathlog(double d) ATTR_CONST; +long tor_lround(double d) ATTR_CONST; +int64_t tor_llround(double d) ATTR_CONST; +int64_t clamp_double_to_int64(double number); + +#endif diff --git a/src/lib/math/include.am b/src/lib/math/include.am new file mode 100644 index 0000000000..b088b3f3cc --- /dev/null +++ b/src/lib/math/include.am @@ -0,0 +1,20 @@ + +noinst_LIBRARIES += src/lib/libtor-math.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-math-testing.a +endif + +src_lib_libtor_math_a_SOURCES = \ + src/lib/math/fp.c \ + src/lib/math/laplace.c + + +src_lib_libtor_math_testing_a_SOURCES = \ + $(src_lib_libtor_math_a_SOURCES) +src_lib_libtor_math_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_math_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/math/fp.h \ + src/lib/math/laplace.h diff --git a/src/lib/math/laplace.c b/src/lib/math/laplace.c new file mode 100644 index 0000000000..8e45a1fb33 --- /dev/null +++ b/src/lib/math/laplace.c @@ -0,0 +1,67 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/math/laplace.h" +#include "lib/math/fp.h" + +#include "lib/log/util_bug.h" + +#include <math.h> +#include <stdlib.h> + +/** Transform a random value <b>p</b> from the uniform distribution in + * [0.0, 1.0[ into a Laplace distributed value with location parameter + * <b>mu</b> and scale parameter <b>b</b>. Truncate the final result + * to be an integer in [INT64_MIN, INT64_MAX]. */ +int64_t +sample_laplace_distribution(double mu, double b, double p) +{ + double result; + tor_assert(p >= 0.0 && p < 1.0); + + /* This is the "inverse cumulative distribution function" from: + * http://en.wikipedia.org/wiki/Laplace_distribution */ + if (p <= 0.0) { + /* Avoid taking log(0.0) == -INFINITY, as some processors or compiler + * options can cause the program to trap. */ + return INT64_MIN; + } + + result = mu - b * (p > 0.5 ? 1.0 : -1.0) + * tor_mathlog(1.0 - 2.0 * fabs(p - 0.5)); + + return clamp_double_to_int64(result); +} + +/** Add random noise between INT64_MIN and INT64_MAX coming from a Laplace + * distribution with mu = 0 and b = <b>delta_f</b>/<b>epsilon</b> to + * <b>signal</b> based on the provided <b>random</b> value in [0.0, 1.0[. + * The epsilon value must be between ]0.0, 1.0]. delta_f must be greater + * than 0. */ +int64_t +add_laplace_noise(int64_t signal_, double random_, double delta_f, + double epsilon) +{ + int64_t noise; + + /* epsilon MUST be between ]0.0, 1.0] */ + tor_assert(epsilon > 0.0 && epsilon <= 1.0); + /* delta_f MUST be greater than 0. */ + tor_assert(delta_f > 0.0); + + /* Just add noise, no further signal */ + noise = sample_laplace_distribution(0.0, + delta_f / epsilon, + random_); + + /* Clip (signal + noise) to [INT64_MIN, INT64_MAX] */ + if (noise > 0 && INT64_MAX - noise < signal_) + return INT64_MAX; + else if (noise < 0 && INT64_MIN - noise > signal_) + return INT64_MIN; + else + return signal_ + noise; +} diff --git a/src/lib/math/laplace.h b/src/lib/math/laplace.h new file mode 100644 index 0000000000..b22862e64a --- /dev/null +++ b/src/lib/math/laplace.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_LAPLACE_H +#define TOR_LAPLACE_H + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" + +int64_t sample_laplace_distribution(double mu, double b, double p); +int64_t add_laplace_noise(int64_t signal, double random, double delta_f, + double epsilon); + +#endif diff --git a/src/lib/memarea/.may_include b/src/lib/memarea/.may_include new file mode 100644 index 0000000000..c55722284f --- /dev/null +++ b/src/lib/memarea/.may_include @@ -0,0 +1,6 @@ +orconfig.h +lib/arch/*.h +lib/cc/*.h +lib/log/*.h +lib/malloc/*.h +lib/memarea/*.h diff --git a/src/lib/memarea/include.am b/src/lib/memarea/include.am new file mode 100644 index 0000000000..94343dcead --- /dev/null +++ b/src/lib/memarea/include.am @@ -0,0 +1,17 @@ + +noinst_LIBRARIES += src/lib/libtor-memarea.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-memarea-testing.a +endif + +src_lib_libtor_memarea_a_SOURCES = \ + src/lib/memarea/memarea.c + +src_lib_libtor_memarea_testing_a_SOURCES = \ + $(src_lib_libtor_memarea_a_SOURCES) +src_lib_libtor_memarea_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_memarea_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/memarea/memarea.h diff --git a/src/common/memarea.c b/src/lib/memarea/memarea.c index 68c1625fe4..7fe3825723 100644 --- a/src/common/memarea.c +++ b/src/lib/memarea/memarea.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2017, The Tor Project, Inc. */ +/* Copyright (c) 2008-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** \file memarea.c @@ -7,13 +7,16 @@ */ #include "orconfig.h" -#include <stddef.h> +#include "lib/memarea/memarea.h" + #include <stdlib.h> -#include "memarea.h" -#include "util.h" -#include "compat.h" -#include "torlog.h" -#include "container.h" +#include <string.h> + +#include "lib/cc/torint.h" +#include "lib/arch/bytes.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" #ifndef DISABLE_MEMORY_SENTINELS @@ -395,4 +398,3 @@ memarea_assert_ok(memarea_t *area) } #endif /* !defined(DISABLE_MEMORY_SENTINELS) */ - diff --git a/src/common/memarea.h b/src/lib/memarea/memarea.h index 5207e8a5bd..e52f5a1be7 100644 --- a/src/common/memarea.h +++ b/src/lib/memarea/memarea.h @@ -1,10 +1,12 @@ -/* Copyright (c) 2008-2017, The Tor Project, Inc. */ +/* Copyright (c) 2008-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Tor dependencies */ #ifndef TOR_MEMAREA_H #define TOR_MEMAREA_H +#include <stddef.h> + typedef struct memarea_t memarea_t; memarea_t *memarea_new(void); @@ -26,4 +28,3 @@ void memarea_get_stats(memarea_t *area, void memarea_assert_ok(memarea_t *area); #endif /* !defined(TOR_MEMAREA_H) */ - diff --git a/src/lib/meminfo/.may_include b/src/lib/meminfo/.may_include new file mode 100644 index 0000000000..9e4d25fd6a --- /dev/null +++ b/src/lib/meminfo/.may_include @@ -0,0 +1,8 @@ +orconfig.h + +lib/cc/*.h +lib/fs/*.h +lib/log/*.h +lib/malloc/*.h +lib/meminfo/*.h +lib/testsupport/*.h diff --git a/src/lib/meminfo/include.am b/src/lib/meminfo/include.am new file mode 100644 index 0000000000..d1fdde6313 --- /dev/null +++ b/src/lib/meminfo/include.am @@ -0,0 +1,17 @@ + +noinst_LIBRARIES += src/lib/libtor-meminfo.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-meminfo-testing.a +endif + +src_lib_libtor_meminfo_a_SOURCES = \ + src/lib/meminfo/meminfo.c + +src_lib_libtor_meminfo_testing_a_SOURCES = \ + $(src_lib_libtor_meminfo_a_SOURCES) +src_lib_libtor_meminfo_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_meminfo_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/meminfo/meminfo.h diff --git a/src/lib/meminfo/meminfo.c b/src/lib/meminfo/meminfo.c new file mode 100644 index 0000000000..34b4ad3b5d --- /dev/null +++ b/src/lib/meminfo/meminfo.c @@ -0,0 +1,173 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/meminfo/meminfo.h" + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" +#include "lib/fs/files.h" +#include "lib/log/torlog.h" +#include "lib/malloc/util_malloc.h" + +#ifdef HAVE_SYS_SYSCTL_H +#include <sys/sysctl.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef _WIN32 +#include <windows.h> +#endif +#include <string.h> + +DISABLE_GCC_WARNING(aggregate-return) +/** Call the platform malloc info function, and dump the results to the log at + * level <b>severity</b>. If no such function exists, do nothing. */ +void +tor_log_mallinfo(int severity) +{ +#ifdef HAVE_MALLINFO + struct mallinfo mi; + memset(&mi, 0, sizeof(mi)); + mi = mallinfo(); + tor_log(severity, LD_MM, + "mallinfo() said: arena=%d, ordblks=%d, smblks=%d, hblks=%d, " + "hblkhd=%d, usmblks=%d, fsmblks=%d, uordblks=%d, fordblks=%d, " + "keepcost=%d", + mi.arena, mi.ordblks, mi.smblks, mi.hblks, + mi.hblkhd, mi.usmblks, mi.fsmblks, mi.uordblks, mi.fordblks, + mi.keepcost); +#else /* !(defined(HAVE_MALLINFO)) */ + (void)severity; +#endif /* defined(HAVE_MALLINFO) */ +} +ENABLE_GCC_WARNING(aggregate-return) + +#if defined(HW_PHYSMEM64) +/* This appears to be an OpenBSD thing */ +#define INT64_HW_MEM HW_PHYSMEM64 +#elif defined(HW_MEMSIZE) +/* OSX defines this one */ +#define INT64_HW_MEM HW_MEMSIZE +#endif /* defined(HW_PHYSMEM64) || ... */ + +/** + * Helper: try to detect the total system memory, and return it. On failure, + * return 0. + */ +static uint64_t +get_total_system_memory_impl(void) +{ +#if defined(__linux__) + /* On linux, sysctl is deprecated. Because proc is so awesome that you + * shouldn't _want_ to write portable code, I guess? */ + unsigned long long result=0; + int fd = -1; + char *s = NULL; + const char *cp; + size_t file_size=0; + if (-1 == (fd = tor_open_cloexec("/proc/meminfo",O_RDONLY,0))) + return 0; + s = read_file_to_str_until_eof(fd, 65536, &file_size); + if (!s) + goto err; + cp = strstr(s, "MemTotal:"); + if (!cp) + goto err; + /* Use the system sscanf so that space will match a wider number of space */ + if (sscanf(cp, "MemTotal: %llu kB\n", &result) != 1) + goto err; + + close(fd); + tor_free(s); + return result * 1024; + + /* LCOV_EXCL_START Can't reach this unless proc is broken. */ + err: + tor_free(s); + close(fd); + return 0; + /* LCOV_EXCL_STOP */ +#elif defined (_WIN32) + /* Windows has MEMORYSTATUSEX; pretty straightforward. */ + MEMORYSTATUSEX ms; + memset(&ms, 0, sizeof(ms)); + ms.dwLength = sizeof(ms); + if (! GlobalMemoryStatusEx(&ms)) + return 0; + + return ms.ullTotalPhys; + +#elif defined(HAVE_SYSCTL) && defined(INT64_HW_MEM) + /* On many systems, HW_PYHSMEM is clipped to 32 bits; let's use a better + * variant if we know about it. */ + uint64_t memsize = 0; + size_t len = sizeof(memsize); + int mib[2] = {CTL_HW, INT64_HW_MEM}; + if (sysctl(mib,2,&memsize,&len,NULL,0)) + return 0; + + return memsize; + +#elif defined(HAVE_SYSCTL) && defined(HW_PHYSMEM) + /* On some systems (like FreeBSD I hope) you can use a size_t with + * HW_PHYSMEM. */ + size_t memsize=0; + size_t len = sizeof(memsize); + int mib[2] = {CTL_HW, HW_USERMEM}; + if (sysctl(mib,2,&memsize,&len,NULL,0)) + return 0; + + return memsize; + +#else + /* I have no clue. */ + return 0; +#endif /* defined(__linux__) || ... */ +} + +/** + * Try to find out how much physical memory the system has. On success, + * return 0 and set *<b>mem_out</b> to that value. On failure, return -1. + */ +MOCK_IMPL(int, +get_total_system_memory, (size_t *mem_out)) +{ + static size_t mem_cached=0; + uint64_t m = get_total_system_memory_impl(); + if (0 == m) { + /* LCOV_EXCL_START -- can't make this happen without mocking. */ + /* We couldn't find our memory total */ + if (0 == mem_cached) { + /* We have no cached value either */ + *mem_out = 0; + return -1; + } + + *mem_out = mem_cached; + return 0; + /* LCOV_EXCL_STOP */ + } + +#if SIZE_MAX != UINT64_MAX + if (m > SIZE_MAX) { + /* I think this could happen if we're a 32-bit Tor running on a 64-bit + * system: we could have more system memory than would fit in a + * size_t. */ + m = SIZE_MAX; + } +#endif /* SIZE_MAX != UINT64_MAX */ + + *mem_out = mem_cached = (size_t) m; + + return 0; +} diff --git a/src/lib/meminfo/meminfo.h b/src/lib/meminfo/meminfo.h new file mode 100644 index 0000000000..a970e992f0 --- /dev/null +++ b/src/lib/meminfo/meminfo.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_MEMINFO_H +#define TOR_MEMINFO_H + +#include "lib/testsupport/testsupport.h" +#include <stddef.h> + +void tor_log_mallinfo(int severity); +MOCK_DECL(int, get_total_system_memory, (size_t *mem_out)); + +#endif diff --git a/src/lib/net/.may_include b/src/lib/net/.may_include new file mode 100644 index 0000000000..1458dad990 --- /dev/null +++ b/src/lib/net/.may_include @@ -0,0 +1,14 @@ +orconfig.h +siphash.h +ht.h + +lib/cc/*.h +lib/container/*.h +lib/ctime/*.h +lib/err/*.h +lib/lock/*.h +lib/log/*.h +lib/net/*.h +lib/string/*.h +lib/testsupport/*.h +lib/malloc/*.h
\ No newline at end of file diff --git a/src/common/address.c b/src/lib/net/address.c index a32df99107..10e38871ee 100644 --- a/src/common/address.c +++ b/src/lib/net/address.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -35,13 +35,22 @@ #include <iphlpapi.h> #endif /* defined(_WIN32) */ -#include "compat.h" -#include "util.h" -#include "util_format.h" -#include "address.h" -#include "torlog.h" -#include "container.h" -#include "sandbox.h" +#include "lib/net/address.h" +#include "lib/net/socket.h" +#include "lib/net/resolve.h" +#include "lib/container/smartlist.h" +#include "lib/ctime/di_ops.h" +#include "lib/log/torlog.h" +#include "lib/log/escape.h" +#include "lib/malloc/util_malloc.h" +#include "lib/net/ipv4.h" +#include "lib/string/compat_ctype.h" +#include "lib/string/compat_string.h" +#include "lib/string/parse_int.h" +#include "lib/string/printf.h" +#include "lib/string/util_string.h" + +#include "siphash.h" #ifdef HAVE_SYS_TIME_H #include <sys/time.h> @@ -52,9 +61,6 @@ #ifdef HAVE_ERRNO_H #include <errno.h> #endif -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif @@ -83,7 +89,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <assert.h> /* tor_addr_is_null() and maybe other functions rely on AF_UNSPEC being 0 to * work correctly. Bail out here if we've found a platform where AF_UNSPEC @@ -1474,14 +1479,7 @@ ip_adapter_addresses_to_smartlist(const IP_ADAPTER_ADDRESSES *addresses) STATIC smartlist_t * get_interface_addresses_win32(int severity, sa_family_t family) { - - /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a - "GetAdaptersInfo", but that's deprecated; let's just try - GetAdaptersAddresses and fall back to connect+getsockname. - */ - HANDLE lib = load_windows_system_library(TEXT("iphlpapi.dll")); smartlist_t *result = NULL; - GetAdaptersAddresses_fn_t fn; ULONG size, res; IP_ADAPTER_ADDRESSES *addresses = NULL; @@ -1491,27 +1489,16 @@ get_interface_addresses_win32(int severity, sa_family_t family) GAA_FLAG_SKIP_MULTICAST | \ GAA_FLAG_SKIP_DNS_SERVER) - if (!lib) { - log_fn(severity, LD_NET, "Unable to load iphlpapi.dll"); - goto done; - } - - if (!(fn = (GetAdaptersAddresses_fn_t) - GetProcAddress(lib, "GetAdaptersAddresses"))) { - log_fn(severity, LD_NET, "Unable to obtain pointer to " - "GetAdaptersAddresses"); - goto done; - } - /* Guess how much space we need. */ size = 15*1024; addresses = tor_malloc(size); - res = fn(family, FLAGS, NULL, addresses, &size); + /* Exists in windows XP and later. */ + res = GetAdaptersAddresses(family, FLAGS, NULL, addresses, &size); if (res == ERROR_BUFFER_OVERFLOW) { /* we didn't guess that we needed enough space; try again */ tor_free(addresses); addresses = tor_malloc(size); - res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size); + res = GetAdaptersAddresses(AF_UNSPEC, FLAGS, NULL, addresses, &size); } if (res != NO_ERROR) { log_fn(severity, LD_NET, "GetAdaptersAddresses failed (result: %lu)", res); @@ -1521,8 +1508,6 @@ get_interface_addresses_win32(int severity, sa_family_t family) result = ip_adapter_addresses_to_smartlist(addresses); done: - if (lib) - FreeLibrary(lib); tor_free(addresses); return result; } @@ -2087,22 +2072,6 @@ parse_port_range(const char *port, uint16_t *port_min_out, return 0; } -/** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual), - * write it as a string into the <b>buf_len</b>-byte buffer in - * <b>buf</b>. Returns a non-negative integer on success. - * Returns -1 on failure. - */ -int -tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len) -{ - uint32_t a = ntohl(in->s_addr); - return tor_snprintf(buf, buf_len, "%d.%d.%d.%d", - (int)(uint8_t)((a>>24)&0xff), - (int)(uint8_t)((a>>16)&0xff), - (int)(uint8_t)((a>>8 )&0xff), - (int)(uint8_t)((a )&0xff)); -} - /** Given a host-order <b>addr</b>, call tor_inet_ntop() on it * and return a strdup of the resulting address. */ @@ -2171,3 +2140,117 @@ tor_addr_port_eq(const tor_addr_port_t *a, return tor_addr_eq(&a->addr, &b->addr) && a->port == b->port; } +/** Return true if <b>string</b> represents a valid IPv4 adddress in + * 'a.b.c.d' form. + */ +int +string_is_valid_ipv4_address(const char *string) +{ + struct in_addr addr; + + return (tor_inet_pton(AF_INET,string,&addr) == 1); +} + +/** Return true if <b>string</b> represents a valid IPv6 address in + * a form that inet_pton() can parse. + */ +int +string_is_valid_ipv6_address(const char *string) +{ + struct in6_addr addr; + + return (tor_inet_pton(AF_INET6,string,&addr) == 1); +} + +/** Return true iff <b>string</b> is a valid destination address, + * i.e. either a DNS hostname or IPv4/IPv6 address string. + */ +int +string_is_valid_dest(const char *string) +{ + char *tmp = NULL; + int retval; + size_t len; + + if (string == NULL) + return 0; + + len = strlen(string); + + if (len == 0) + return 0; + + if (string[0] == '[' && string[len - 1] == ']') + string = tmp = tor_strndup(string + 1, len - 2); + + retval = string_is_valid_ipv4_address(string) || + string_is_valid_ipv6_address(string) || + string_is_valid_nonrfc_hostname(string); + + tor_free(tmp); + + return retval; +} + +/** Return true iff <b>string</b> matches a pattern of DNS names + * that we allow Tor clients to connect to. + * + * Note: This allows certain technically invalid characters ('_') to cope + * with misconfigured zones that have been encountered in the wild. + */ +int +string_is_valid_nonrfc_hostname(const char *string) +{ + int result = 1; + int has_trailing_dot; + char *last_label; + smartlist_t *components; + + if (!string || strlen(string) == 0) + return 0; + + if (string_is_valid_ipv4_address(string)) + return 0; + + components = smartlist_new(); + + smartlist_split_string(components,string,".",0,0); + + if (BUG(smartlist_len(components) == 0)) + return 0; // LCOV_EXCL_LINE should be impossible given the earlier checks. + + /* Allow a single terminating '.' used rarely to indicate domains + * are FQDNs rather than relative. */ + last_label = (char *)smartlist_get(components, + smartlist_len(components) - 1); + has_trailing_dot = (last_label[0] == '\0'); + if (has_trailing_dot) { + smartlist_pop_last(components); + tor_free(last_label); + last_label = NULL; + } + + SMARTLIST_FOREACH_BEGIN(components, char *, c) { + if ((c[0] == '-') || (*c == '_')) { + result = 0; + break; + } + + do { + result = (TOR_ISALNUM(*c) || (*c == '-') || (*c == '_')); + c++; + } while (result && *c); + + if (result == 0) { + break; + } + } SMARTLIST_FOREACH_END(c); + + SMARTLIST_FOREACH_BEGIN(components, char *, c) { + tor_free(c); + } SMARTLIST_FOREACH_END(c); + + smartlist_free(components); + + return result; +} diff --git a/src/common/address.h b/src/lib/net/address.h index c9d9543dee..f8ea573c30 100644 --- a/src/common/address.h +++ b/src/lib/net/address.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,11 +11,22 @@ #ifndef TOR_ADDRESS_H #define TOR_ADDRESS_H -//#include <sys/sockio.h> #include "orconfig.h" -#include "torint.h" -#include "compat.h" -#include "container.h" +#include "lib/cc/torint.h" +#include "lib/log/util_bug.h" +#include "lib/net/ipv6.h" +#include "lib/net/nettypes.h" + +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef _WIN32 +#include <winsock2.h> +#include <windows.h> +#endif + +#include <stddef.h> +#include <stdlib.h> #ifdef ADDRESS_PRIVATE @@ -73,6 +84,9 @@ typedef struct tor_addr_port_t #define TOR_ADDR_NULL {AF_UNSPEC, {0}} +/* XXXX To do: extract all of the functions here that can possibly invoke + * XXXX resolver, and make sure they have distinctive names. */ + static inline const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a); static inline const struct in6_addr *tor_addr_to_in6_assert( const tor_addr_t *a); @@ -206,10 +220,11 @@ const char * fmt_addr32(uint32_t addr); MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)); -void interface_address6_list_free_(smartlist_t * addrs);// XXXX +struct smartlist_t; +void interface_address6_list_free_(struct smartlist_t * addrs);// XXXX #define interface_address6_list_free(addrs) \ - FREE_AND_NULL(smartlist_t, interface_address6_list_free_, (addrs)) -MOCK_DECL(smartlist_t *,get_interface_address6_list,(int severity, + FREE_AND_NULL(struct smartlist_t, interface_address6_list_free_, (addrs)) +MOCK_DECL(struct smartlist_t *,get_interface_address6_list,(int severity, sa_family_t family, int include_internal)); @@ -320,9 +335,6 @@ int addr_port_lookup(int severity, const char *addrport, char **address, int parse_port_range(const char *port, uint16_t *port_min_out, uint16_t *port_max_out); int addr_mask_get_bits(uint32_t mask); -/** Length of a buffer to allocate to hold the results of tor_inet_ntoa.*/ -#define INET_NTOA_BUF_LEN 16 -int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len); char *tor_dup_ip(uint32_t addr) ATTR_MALLOC; MOCK_DECL(int,get_interface_address,(int severity, uint32_t *addr)); #define interface_address_list_free(lst)\ @@ -335,7 +347,7 @@ MOCK_DECL(int,get_interface_address,(int severity, uint32_t *addr)); * Returns NULL on failure. * Use free_interface_address_list to free the returned list. */ -static inline smartlist_t * +static inline struct smartlist_t * get_interface_address_list(int severity, int include_internal) { return get_interface_address6_list(severity, AF_INET, include_internal); @@ -345,35 +357,39 @@ tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port); int tor_addr_port_eq(const tor_addr_port_t *a, const tor_addr_port_t *b); +int string_is_valid_dest(const char *string); +int string_is_valid_nonrfc_hostname(const char *string); +int string_is_valid_ipv4_address(const char *string); +int string_is_valid_ipv6_address(const char *string); + #ifdef ADDRESS_PRIVATE -MOCK_DECL(smartlist_t *,get_interface_addresses_raw,(int severity, +MOCK_DECL(struct smartlist_t *,get_interface_addresses_raw,(int severity, sa_family_t family)); MOCK_DECL(int,get_interface_address6_via_udp_socket_hack,(int severity, sa_family_t family, tor_addr_t *addr)); #ifdef HAVE_IFADDRS_TO_SMARTLIST -STATIC smartlist_t *ifaddrs_to_smartlist(const struct ifaddrs *ifa, +STATIC struct smartlist_t *ifaddrs_to_smartlist(const struct ifaddrs *ifa, sa_family_t family); -STATIC smartlist_t *get_interface_addresses_ifaddrs(int severity, +STATIC struct smartlist_t *get_interface_addresses_ifaddrs(int severity, sa_family_t family); #endif /* defined(HAVE_IFADDRS_TO_SMARTLIST) */ #ifdef HAVE_IP_ADAPTER_TO_SMARTLIST -STATIC smartlist_t *ip_adapter_addresses_to_smartlist( +STATIC struct smartlist_t *ip_adapter_addresses_to_smartlist( const IP_ADAPTER_ADDRESSES *addresses); -STATIC smartlist_t *get_interface_addresses_win32(int severity, +STATIC struct smartlist_t *get_interface_addresses_win32(int severity, sa_family_t family); #endif /* defined(HAVE_IP_ADAPTER_TO_SMARTLIST) */ #ifdef HAVE_IFCONF_TO_SMARTLIST -STATIC smartlist_t *ifreq_to_smartlist(char *ifr, +STATIC struct smartlist_t *ifreq_to_smartlist(char *ifr, size_t buflen); -STATIC smartlist_t *get_interface_addresses_ioctl(int severity, +STATIC struct smartlist_t *get_interface_addresses_ioctl(int severity, sa_family_t family); #endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */ #endif /* defined(ADDRESS_PRIVATE) */ #endif /* !defined(TOR_ADDRESS_H) */ - diff --git a/src/common/compat_threads.c b/src/lib/net/alertsock.c index 3171c4b2f2..c6ea1551f8 100644 --- a/src/common/compat_threads.c +++ b/src/lib/net/alertsock.c @@ -1,23 +1,12 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -/** - * \file compat_threads.c - * - * \brief Cross-platform threading and inter-thread communication logic. - * (Platform-specific parts are written in the other compat_*threads - * modules.) - */ - #include "orconfig.h" -#include <stdlib.h> -#include "compat.h" -#include "compat_threads.h" - -#include "util.h" -#include "torlog.h" +#include "lib/net/alertsock.h" +#include "lib/net/socket.h" +#include "lib/log/util_bug.h" #ifdef HAVE_SYS_EVENTFD_H #include <sys/eventfd.h> @@ -28,70 +17,12 @@ #ifdef HAVE_UNISTD_H #include <unistd.h> #endif - -/** Return a newly allocated, ready-for-use mutex. */ -tor_mutex_t * -tor_mutex_new(void) -{ - tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); - tor_mutex_init(m); - return m; -} -/** Return a newly allocated, ready-for-use mutex. This one might be - * non-recursive, if that's faster. */ -tor_mutex_t * -tor_mutex_new_nonrecursive(void) -{ - tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); - tor_mutex_init_nonrecursive(m); - return m; -} -/** Release all storage and system resources held by <b>m</b>. */ -void -tor_mutex_free_(tor_mutex_t *m) -{ - if (!m) - return; - tor_mutex_uninit(m); - tor_free(m); -} - -/** Allocate and return a new condition variable. */ -tor_cond_t * -tor_cond_new(void) -{ - tor_cond_t *cond = tor_malloc(sizeof(tor_cond_t)); - if (BUG(tor_cond_init(cond)<0)) - tor_free(cond); // LCOV_EXCL_LINE - return cond; -} - -/** Free all storage held in <b>c</b>. */ -void -tor_cond_free_(tor_cond_t *c) -{ - if (!c) - return; - tor_cond_uninit(c); - tor_free(c); -} - -/** Identity of the "main" thread */ -static unsigned long main_thread_id = -1; - -/** Start considering the current thread to be the 'main thread'. This has - * no effect on anything besides in_main_thread(). */ -void -set_main_thread(void) -{ - main_thread_id = tor_get_thread_id(); -} -/** Return true iff called from the main thread. */ -int -in_main_thread(void) -{ - return main_thread_id == tor_get_thread_id(); -} +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef _WIN32 +#include <winsock2.h> +#endif #if defined(HAVE_EVENTFD) || defined(HAVE_PIPE) /* As write(), but retry on EINTR, and return the negative error code on @@ -351,57 +282,3 @@ alert_sockets_close(alert_sockets_t *socks) } socks->read_fd = socks->write_fd = -1; } - -#ifndef HAVE_STDATOMIC_H -/** Initialize a new atomic counter with the value 0 */ -void -atomic_counter_init(atomic_counter_t *counter) -{ - memset(counter, 0, sizeof(*counter)); - tor_mutex_init_nonrecursive(&counter->mutex); -} -/** Clean up all resources held by an atomic counter. */ -void -atomic_counter_destroy(atomic_counter_t *counter) -{ - tor_mutex_uninit(&counter->mutex); - memset(counter, 0, sizeof(*counter)); -} -/** Add a value to an atomic counter. */ -void -atomic_counter_add(atomic_counter_t *counter, size_t add) -{ - tor_mutex_acquire(&counter->mutex); - counter->val += add; - tor_mutex_release(&counter->mutex); -} -/** Subtract a value from an atomic counter. */ -void -atomic_counter_sub(atomic_counter_t *counter, size_t sub) -{ - // this relies on unsigned overflow, but that's fine. - atomic_counter_add(counter, -sub); -} -/** Return the current value of an atomic counter */ -size_t -atomic_counter_get(atomic_counter_t *counter) -{ - size_t val; - tor_mutex_acquire(&counter->mutex); - val = counter->val; - tor_mutex_release(&counter->mutex); - return val; -} -/** Replace the value of an atomic counter; return the old one. */ -size_t -atomic_counter_exchange(atomic_counter_t *counter, size_t newval) -{ - size_t oldval; - tor_mutex_acquire(&counter->mutex); - oldval = counter->val; - counter->val = newval; - tor_mutex_release(&counter->mutex); - return oldval; -} -#endif /* !defined(HAVE_STDATOMIC_H) */ - diff --git a/src/lib/net/alertsock.h b/src/lib/net/alertsock.h new file mode 100644 index 0000000000..026a15cad0 --- /dev/null +++ b/src/lib/net/alertsock.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_ALERTSOCK_H +#define TOR_ALERTSOCK_H + +#include "orconfig.h" +#include "lib/net/nettypes.h" +#include "lib/cc/torint.h" + +/** Helper type used to manage waking up the main thread while it's in + * the libevent main loop. Used by the work queue code. */ +typedef struct alert_sockets_t { + /* XXXX This structure needs a better name. */ + /** Socket that the main thread should listen for EV_READ events on. + * Note that this socket may be a regular fd on a non-Windows platform. + */ + tor_socket_t read_fd; + /** Socket to use when alerting the main thread. */ + tor_socket_t write_fd; + /** Function to alert the main thread */ + int (*alert_fn)(tor_socket_t write_fd); + /** Function to make the main thread no longer alerted. */ + int (*drain_fn)(tor_socket_t read_fd); +} alert_sockets_t; + +/* Flags to disable one or more alert_sockets backends. */ +#define ASOCKS_NOEVENTFD2 (1u<<0) +#define ASOCKS_NOEVENTFD (1u<<1) +#define ASOCKS_NOPIPE2 (1u<<2) +#define ASOCKS_NOPIPE (1u<<3) +#define ASOCKS_NOSOCKETPAIR (1u<<4) + +int alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags); +void alert_sockets_close(alert_sockets_t *socks); + +#endif diff --git a/src/lib/net/buffers_net.c b/src/lib/net/buffers_net.c new file mode 100644 index 0000000000..edc9954f22 --- /dev/null +++ b/src/lib/net/buffers_net.c @@ -0,0 +1,197 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define BUFFERS_PRIVATE +#include "lib/net/buffers_net.h" +#include "lib/container/buffers.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/net/nettypes.h" + +#ifdef _WIN32 +#include <winsock2.h> +#endif + +#include <stdlib.h> + +#ifdef PARANOIA +/** Helper: If PARANOIA is defined, assert that the buffer in local variable + * <b>buf</b> is well-formed. */ +#define check() STMT_BEGIN buf_assert_ok(buf); STMT_END +#else +#define check() STMT_NIL +#endif /* defined(PARANOIA) */ + +/** Read up to <b>at_most</b> bytes from the socket <b>fd</b> into + * <b>chunk</b> (which must be on <b>buf</b>). If we get an EOF, set + * *<b>reached_eof</b> to 1. Return -1 on error, 0 on eof or blocking, + * and the number of bytes read otherwise. */ +static inline int +read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most, + int *reached_eof, int *socket_error) +{ + ssize_t read_result; + if (at_most > CHUNK_REMAINING_CAPACITY(chunk)) + at_most = CHUNK_REMAINING_CAPACITY(chunk); + read_result = tor_socket_recv(fd, CHUNK_WRITE_PTR(chunk), at_most, 0); + + if (read_result < 0) { + int e = tor_socket_errno(fd); + if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ +#ifdef _WIN32 + if (e == WSAENOBUFS) + log_warn(LD_NET,"recv() failed: WSAENOBUFS. Not enough ram?"); +#endif + *socket_error = e; + return -1; + } + return 0; /* would block. */ + } else if (read_result == 0) { + log_debug(LD_NET,"Encountered eof on fd %d", (int)fd); + *reached_eof = 1; + return 0; + } else { /* actually got bytes. */ + buf->datalen += read_result; + chunk->datalen += read_result; + log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result, + (int)buf->datalen); + tor_assert(read_result < INT_MAX); + return (int)read_result; + } +} + +/** Read from socket <b>s</b>, writing onto end of <b>buf</b>. Read at most + * <b>at_most</b> bytes, growing the buffer as necessary. If recv() returns 0 + * (because of EOF), set *<b>reached_eof</b> to 1 and return 0. Return -1 on + * error; else return the number of bytes read. + */ +/* XXXX indicate "read blocked" somehow? */ +int +buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most, + int *reached_eof, + int *socket_error) +{ + /* XXXX It's stupid to overload the return values for these functions: + * "error status" and "number of bytes read" are not mutually exclusive. + */ + int r = 0; + size_t total_read = 0; + + check(); + tor_assert(reached_eof); + tor_assert(SOCKET_OK(s)); + + if (BUG(buf->datalen >= INT_MAX)) + return -1; + if (BUG(buf->datalen >= INT_MAX - at_most)) + return -1; + + while (at_most > total_read) { + size_t readlen = at_most - total_read; + chunk_t *chunk; + if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) { + chunk = buf_add_chunk_with_capacity(buf, at_most, 1); + if (readlen > chunk->memlen) + readlen = chunk->memlen; + } else { + size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail); + chunk = buf->tail; + if (cap < readlen) + readlen = cap; + } + + r = read_to_chunk(buf, chunk, s, readlen, reached_eof, socket_error); + check(); + if (r < 0) + return r; /* Error */ + tor_assert(total_read+r < INT_MAX); + total_read += r; + if ((size_t)r < readlen) { /* eof, block, or no more to read. */ + break; + } + } + return (int)total_read; +} + +/** Helper for buf_flush_to_socket(): try to write <b>sz</b> bytes from chunk + * <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. On success, deduct + * the bytes written from *<b>buf_flushlen</b>. Return the number of bytes + * written on success, 0 on blocking, -1 on failure. + */ +static inline int +flush_chunk(tor_socket_t s, buf_t *buf, chunk_t *chunk, size_t sz, + size_t *buf_flushlen) +{ + ssize_t write_result; + + if (sz > chunk->datalen) + sz = chunk->datalen; + write_result = tor_socket_send(s, chunk->data, sz, 0); + + if (write_result < 0) { + int e = tor_socket_errno(s); + if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ +#ifdef _WIN32 + if (e == WSAENOBUFS) + log_warn(LD_NET,"write() failed: WSAENOBUFS. Not enough ram?"); +#endif + return -1; + } + log_debug(LD_NET,"write() would block, returning."); + return 0; + } else { + *buf_flushlen -= write_result; + buf_drain(buf, write_result); + tor_assert(write_result < INT_MAX); + return (int)write_result; + } +} + +/** Write data from <b>buf</b> to the socket <b>s</b>. Write at most + * <b>sz</b> bytes, decrement *<b>buf_flushlen</b> by + * the number of bytes actually written, and remove the written bytes + * from the buffer. Return the number of bytes written on success, + * -1 on failure. Return 0 if write() would block. + */ +int +buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz, + size_t *buf_flushlen) +{ + /* XXXX It's stupid to overload the return values for these functions: + * "error status" and "number of bytes flushed" are not mutually exclusive. + */ + int r; + size_t flushed = 0; + tor_assert(buf_flushlen); + tor_assert(SOCKET_OK(s)); + if (BUG(*buf_flushlen > buf->datalen)) { + *buf_flushlen = buf->datalen; + } + if (BUG(sz > *buf_flushlen)) { + sz = *buf_flushlen; + } + + check(); + while (sz) { + size_t flushlen0; + tor_assert(buf->head); + if (buf->head->datalen >= sz) + flushlen0 = sz; + else + flushlen0 = buf->head->datalen; + + r = flush_chunk(s, buf, buf->head, flushlen0, buf_flushlen); + check(); + if (r < 0) + return r; + flushed += r; + sz -= r; + if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */ + break; + } + tor_assert(flushed < INT_MAX); + return (int)flushed; +} diff --git a/src/lib/net/buffers_net.h b/src/lib/net/buffers_net.h new file mode 100644 index 0000000000..d03b61376e --- /dev/null +++ b/src/lib/net/buffers_net.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file buffers.h + * \brief Header file for buffers.c. + **/ + +#ifndef TOR_BUFFERS_NET_H +#define TOR_BUFFERS_NET_H + +#include <stddef.h> +#include "lib/net/socket.h" + +struct buf_t; +int buf_read_from_socket(struct buf_t *buf, tor_socket_t s, size_t at_most, + int *reached_eof, + int *socket_error); + +int buf_flush_to_socket(struct buf_t *buf, tor_socket_t s, size_t sz, + size_t *buf_flushlen); + +#endif /* !defined(TOR_BUFFERS_H) */ diff --git a/src/lib/net/gethostname.c b/src/lib/net/gethostname.c new file mode 100644 index 0000000000..b6cc9b8e5f --- /dev/null +++ b/src/lib/net/gethostname.c @@ -0,0 +1,25 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/net/gethostname.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef _WIN32 +#include <winsock2.h> +#endif + +/** Get name of current host and write it to <b>name</b> array, whose + * length is specified by <b>namelen</b> argument. Return 0 upon + * successful completion; otherwise return return -1. (Currently, + * this function is merely a mockable wrapper for POSIX gethostname().) + */ +MOCK_IMPL(int, +tor_gethostname,(char *name, size_t namelen)) +{ + return gethostname(name,namelen); +} diff --git a/src/lib/net/gethostname.h b/src/lib/net/gethostname.h new file mode 100644 index 0000000000..d83c5fe096 --- /dev/null +++ b/src/lib/net/gethostname.h @@ -0,0 +1,14 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_GETHOSTNAME_H +#define TOR_GETHOSTNAME_H + +#include "lib/testsupport/testsupport.h" +#include <stddef.h> + +MOCK_DECL(int,tor_gethostname,(char *name, size_t namelen)); + +#endif diff --git a/src/lib/net/include.am b/src/lib/net/include.am new file mode 100644 index 0000000000..a375ac8ad5 --- /dev/null +++ b/src/lib/net/include.am @@ -0,0 +1,32 @@ + +noinst_LIBRARIES += src/lib/libtor-net.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-net-testing.a +endif + +src_lib_libtor_net_a_SOURCES = \ + src/lib/net/address.c \ + src/lib/net/alertsock.c \ + src/lib/net/buffers_net.c \ + src/lib/net/gethostname.c \ + src/lib/net/ipv4.c \ + src/lib/net/ipv6.c \ + src/lib/net/resolve.c \ + src/lib/net/socket.c + +src_lib_libtor_net_testing_a_SOURCES = \ + $(src_lib_libtor_net_a_SOURCES) +src_lib_libtor_net_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_net_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/net/address.h \ + src/lib/net/alertsock.h \ + src/lib/net/buffers_net.h \ + src/lib/net/gethostname.h \ + src/lib/net/ipv4.h \ + src/lib/net/ipv6.h \ + src/lib/net/nettypes.h \ + src/lib/net/resolve.h \ + src/lib/net/socket.h diff --git a/src/lib/net/ipv4.c b/src/lib/net/ipv4.c new file mode 100644 index 0000000000..18e69761e2 --- /dev/null +++ b/src/lib/net/ipv4.c @@ -0,0 +1,52 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/net/ipv4.h" +#include "lib/string/printf.h" +#include "lib/string/scanf.h" + +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef _WIN32 +#include <winsock2.h> +#endif + +/** Set *addr to the IP address (in dotted-quad notation) stored in *str. + * Return 1 on success, 0 if *str is badly formatted. + * (Like inet_aton(str,addr), but works on Windows and Solaris.) + */ +int +tor_inet_aton(const char *str, struct in_addr* addr) +{ + unsigned a,b,c,d; + char more; + if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a,&b,&c,&d,&more) != 4) + return 0; + if (a > 255) return 0; + if (b > 255) return 0; + if (c > 255) return 0; + if (d > 255) return 0; + addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d); + return 1; +} + +/** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual), + * write it as a string into the <b>buf_len</b>-byte buffer in + * <b>buf</b>. Returns a non-negative integer on success. + * Returns -1 on failure. + */ +int +tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len) +{ + uint32_t a = ntohl(in->s_addr); + return tor_snprintf(buf, buf_len, "%d.%d.%d.%d", + (int)(uint8_t)((a>>24)&0xff), + (int)(uint8_t)((a>>16)&0xff), + (int)(uint8_t)((a>>8 )&0xff), + (int)(uint8_t)((a )&0xff)); +} diff --git a/src/lib/net/ipv4.h b/src/lib/net/ipv4.h new file mode 100644 index 0000000000..1ccc729970 --- /dev/null +++ b/src/lib/net/ipv4.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_IPV4_H +#define TOR_IPV4_H + +#include <stddef.h> + +struct in_addr; +int tor_inet_aton(const char *str, struct in_addr *addr); +/** Length of a buffer to allocate to hold the results of tor_inet_ntoa.*/ +#define INET_NTOA_BUF_LEN 16 +int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len); + +#endif diff --git a/src/lib/net/ipv6.c b/src/lib/net/ipv6.c new file mode 100644 index 0000000000..35d7ddb901 --- /dev/null +++ b/src/lib/net/ipv6.c @@ -0,0 +1,221 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/net/ipv6.h" +#include "lib/net/ipv4.h" +#include "lib/string/util_string.h" +#include "lib/string/compat_string.h" +#include "lib/string/compat_ctype.h" +#include "lib/string/printf.h" +#include "lib/string/scanf.h" +#include "lib/log/util_bug.h" + +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#include <stdlib.h> +#include <string.h> + +/** Given <b>af</b>==AF_INET and <b>src</b> a struct in_addr, or + * <b>af</b>==AF_INET6 and <b>src</b> a struct in6_addr, try to format the + * address and store it in the <b>len</b>-byte buffer <b>dst</b>. Returns + * <b>dst</b> on success, NULL on failure. + * + * (Like inet_ntop(af,src,dst,len), but works on platforms that don't have it: + * Tor sometimes needs to format ipv6 addresses even on platforms without ipv6 + * support.) */ +const char * +tor_inet_ntop(int af, const void *src, char *dst, size_t len) +{ + if (af == AF_INET) { + if (tor_inet_ntoa(src, dst, len) < 0) + return NULL; + else + return dst; + } else if (af == AF_INET6) { + const struct in6_addr *addr = src; + char buf[64], *cp; + int longestGapLen = 0, longestGapPos = -1, i, + curGapPos = -1, curGapLen = 0; + uint16_t words[8]; + for (i = 0; i < 8; ++i) { + words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1]; + } + if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && + words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) || + (words[5] == 0xffff))) { + /* This is an IPv4 address. */ + if (words[5] == 0) { + tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d", + addr->s6_addr[12], addr->s6_addr[13], + addr->s6_addr[14], addr->s6_addr[15]); + } else { + tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5], + addr->s6_addr[12], addr->s6_addr[13], + addr->s6_addr[14], addr->s6_addr[15]); + } + if ((strlen(buf) + 1) > len) /* +1 for \0 */ + return NULL; + strlcpy(dst, buf, len); + return dst; + } + i = 0; + while (i < 8) { + if (words[i] == 0) { + curGapPos = i++; + curGapLen = 1; + while (i<8 && words[i] == 0) { + ++i; ++curGapLen; + } + if (curGapLen > longestGapLen) { + longestGapPos = curGapPos; + longestGapLen = curGapLen; + } + } else { + ++i; + } + } + if (longestGapLen<=1) + longestGapPos = -1; + + cp = buf; + for (i = 0; i < 8; ++i) { + if (words[i] == 0 && longestGapPos == i) { + if (i == 0) + *cp++ = ':'; + *cp++ = ':'; + while (i < 8 && words[i] == 0) + ++i; + --i; /* to compensate for loop increment. */ + } else { + tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]); + cp += strlen(cp); + if (i != 7) + *cp++ = ':'; + } + } + *cp = '\0'; + if ((strlen(buf) + 1) > len) /* +1 for \0 */ + return NULL; + strlcpy(dst, buf, len); + return dst; + } else { + return NULL; + } +} + +/** Given <b>af</b>==AF_INET or <b>af</b>==AF_INET6, and a string <b>src</b> + * encoding an IPv4 address or IPv6 address correspondingly, try to parse the + * address and store the result in <b>dst</b> (which must have space for a + * struct in_addr or a struct in6_addr, as appropriate). Return 1 on success, + * 0 on a bad parse, and -1 on a bad <b>af</b>. + * + * (Like inet_pton(af,src,dst) but works on platforms that don't have it: Tor + * sometimes needs to format ipv6 addresses even on platforms without ipv6 + * support.) */ +int +tor_inet_pton(int af, const char *src, void *dst) +{ + if (af == AF_INET) { + return tor_inet_aton(src, dst); + } else if (af == AF_INET6) { + struct in6_addr *out = dst; + uint16_t words[8]; + int gapPos = -1, i, setWords=0; + const char *dot = strchr(src, '.'); + const char *eow; /* end of words. */ + memset(words, 0xf8, sizeof(words)); + if (dot == src) + return 0; + else if (!dot) + eow = src+strlen(src); + else { + unsigned byte1,byte2,byte3,byte4; + char more; + for (eow = dot-1; eow > src && TOR_ISDIGIT(*eow); --eow) + ; + if (*eow != ':') + return 0; + ++eow; + + /* We use "scanf" because some platform inet_aton()s are too lax + * about IPv4 addresses of the form "1.2.3" */ + if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c", + &byte1,&byte2,&byte3,&byte4,&more) != 4) + return 0; + + if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255) + return 0; + + words[6] = (byte1<<8) | byte2; + words[7] = (byte3<<8) | byte4; + setWords += 2; + } + + i = 0; + while (src < eow) { + if (i > 7) + return 0; + if (TOR_ISXDIGIT(*src)) { + char *next; + ssize_t len; + long r = strtol(src, &next, 16); + if (next == NULL || next == src) { + /* The 'next == src' error case can happen on versions of openbsd + * which treat "0xfoo" as an error, rather than as "0" followed by + * "xfoo". */ + return 0; + } + + len = *next == '\0' ? eow - src : next - src; + if (len > 4) + return 0; + if (len > 1 && !TOR_ISXDIGIT(src[1])) + return 0; /* 0x is not valid */ + + tor_assert(r >= 0); + tor_assert(r < 65536); + words[i++] = (uint16_t)r; + setWords++; + src = next; + if (*src != ':' && src != eow) + return 0; + ++src; + } else if (*src == ':' && i > 0 && gapPos == -1) { + gapPos = i; + ++src; + } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' && + gapPos == -1) { + gapPos = i; + src += 2; + } else { + return 0; + } + } + + if (setWords > 8 || + (setWords == 8 && gapPos != -1) || + (setWords < 8 && gapPos == -1)) + return 0; + + if (gapPos >= 0) { + int nToMove = setWords - (dot ? 2 : 0) - gapPos; + int gapLen = 8 - setWords; + tor_assert(nToMove >= 0); + memmove(&words[gapPos+gapLen], &words[gapPos], + sizeof(uint16_t)*nToMove); + memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen); + } + for (i = 0; i < 8; ++i) { + out->s6_addr[2*i ] = words[i] >> 8; + out->s6_addr[2*i+1] = words[i] & 0xff; + } + + return 1; + } else { + return -1; + } +} diff --git a/src/lib/net/ipv6.h b/src/lib/net/ipv6.h new file mode 100644 index 0000000000..0a12e046ac --- /dev/null +++ b/src/lib/net/ipv6.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_IPV6_H +#define TOR_IPV6_H + +#include "orconfig.h" +#include <stddef.h> +#ifdef HAVE_NETINET_IN6_H +#include <netinet/in6.h> +#endif +#ifdef _WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#include <windows.h> +#endif +#include "lib/cc/torint.h" + +/** Implementation of struct in6_addr for platforms that do not have it. + * Generally, these platforms are ones without IPv6 support, but we want to + * have a working in6_addr there anyway, so we can use it to parse IPv6 + * addresses. */ +#if !defined(HAVE_STRUCT_IN6_ADDR) +struct in6_addr +{ + union { + uint8_t u6_addr8[16]; + uint16_t u6_addr16[8]; + uint32_t u6_addr32[4]; + } in6_u; +#define s6_addr in6_u.u6_addr8 +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +}; +#endif /* !defined(HAVE_STRUCT_IN6_ADDR) */ + +/** @{ */ +/** Many BSD variants seem not to define these. */ +#if defined(__APPLE__) || defined(__darwin__) || \ + defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#ifndef s6_addr16 +#define s6_addr16 __u6_addr.__u6_addr16 +#endif +#ifndef s6_addr32 +#define s6_addr32 __u6_addr.__u6_addr32 +#endif +#endif /* defined(__APPLE__) || defined(__darwin__) || ... */ +/** @} */ + +#ifndef HAVE_SA_FAMILY_T +typedef uint16_t sa_family_t; +#endif + +/** @{ */ +/** Apparently, MS and Solaris don't define s6_addr16 or s6_addr32; these + * macros get you a pointer to s6_addr32 or local equivalent. */ +#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR32 +#define S6_ADDR32(x) ((uint32_t*)(x).s6_addr32) +#else +#define S6_ADDR32(x) ((uint32_t*)((char*)&(x).s6_addr)) +#endif +#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR16 +#define S6_ADDR16(x) ((uint16_t*)(x).s6_addr16) +#else +#define S6_ADDR16(x) ((uint16_t*)((char*)&(x).s6_addr)) +#endif +/** @} */ + +/** Implementation of struct sockaddr_in6 on platforms that do not have + * it. See notes on struct in6_addr. */ +#if !defined(HAVE_STRUCT_SOCKADDR_IN6) +struct sockaddr_in6 { + sa_family_t sin6_family; + uint16_t sin6_port; + // uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + // uint32_t sin6_scope_id; +}; +#endif /* !defined(HAVE_STRUCT_SOCKADDR_IN6) */ + +const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len); +int tor_inet_pton(int af, const char *src, void *dst); + +#endif diff --git a/src/lib/net/nettypes.h b/src/lib/net/nettypes.h new file mode 100644 index 0000000000..9bae70d5f8 --- /dev/null +++ b/src/lib/net/nettypes.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_NET_TYPES_H +#define TOR_NET_TYPES_H + +#include "orconfig.h" +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + +#if (SIZEOF_SOCKLEN_T == 0) +typedef int socklen_t; +#endif + +#ifdef _WIN32 +/* XXX Actually, this should arguably be SOCKET; we use intptr_t here so that + * any inadvertent checks for the socket being <= 0 or > 0 will probably + * still work. */ +#define tor_socket_t intptr_t +#define TOR_SOCKET_T_FORMAT INTPTR_T_FORMAT +#define SOCKET_OK(s) ((SOCKET)(s) != INVALID_SOCKET) +#define TOR_INVALID_SOCKET INVALID_SOCKET +#else /* !(defined(_WIN32)) */ +/** Type used for a network socket. */ +#define tor_socket_t int +#define TOR_SOCKET_T_FORMAT "%d" +/** Macro: true iff 's' is a possible value for a valid initialized socket. */ +#define SOCKET_OK(s) ((s) >= 0) +/** Error/uninitialized value for a tor_socket_t. */ +#define TOR_INVALID_SOCKET (-1) +#endif /* defined(_WIN32) */ + +#endif diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c new file mode 100644 index 0000000000..fefd5cceb7 --- /dev/null +++ b/src/lib/net/resolve.c @@ -0,0 +1,236 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/net/resolve.h" +#include "lib/net/address.h" +#include "lib/malloc/util_malloc.h" + +#include "siphash.h" +#include "ht.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif + +#include <string.h> + +/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set + * *<b>addr</b> to the proper IP address, in host byte order. Returns 0 + * on success, -1 on failure; 1 on transient failure. + * + * (This function exists because standard windows gethostbyname + * doesn't treat raw IP addresses properly.) + */ + +MOCK_IMPL(int, +tor_lookup_hostname,(const char *name, uint32_t *addr)) +{ + tor_addr_t myaddr; + int ret; + + if ((ret = tor_addr_lookup(name, AF_INET, &myaddr))) + return ret; + + if (tor_addr_family(&myaddr) == AF_INET) { + *addr = tor_addr_to_ipv4h(&myaddr); + return ret; + } + + return -1; +} + +#ifdef USE_SANDBOX_GETADDRINFO +/** True if we should only return cached values */ +static int sandbox_getaddrinfo_is_active = 0; + +/** Cache entry for getaddrinfo results; used when sandboxing is implemented + * so that we can consult the cache when the sandbox prevents us from doing + * getaddrinfo. + * + * We support only a limited range of getaddrinfo calls, where servname is null + * and hints contains only socktype=SOCK_STREAM, family in INET,INET6,UNSPEC. + */ +typedef struct cached_getaddrinfo_item_t { + HT_ENTRY(cached_getaddrinfo_item_t) node; + char *name; + int family; + /** set if no error; otherwise NULL */ + struct addrinfo *res; + /** 0 for no error; otherwise an EAI_* value */ + int err; +} cached_getaddrinfo_item_t; + +static unsigned +cached_getaddrinfo_item_hash(const cached_getaddrinfo_item_t *item) +{ + return (unsigned)siphash24g(item->name, strlen(item->name)) + item->family; +} + +static unsigned +cached_getaddrinfo_items_eq(const cached_getaddrinfo_item_t *a, + const cached_getaddrinfo_item_t *b) +{ + return (a->family == b->family) && 0 == strcmp(a->name, b->name); +} + +#define cached_getaddrinfo_item_free(item) \ + FREE_AND_NULL(cached_getaddrinfo_item_t, \ + cached_getaddrinfo_item_free_, (item)) + +static void +cached_getaddrinfo_item_free_(cached_getaddrinfo_item_t *item) +{ + if (item == NULL) + return; + + tor_free(item->name); + if (item->res) + freeaddrinfo(item->res); + tor_free(item); +} + +static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t) + getaddrinfo_cache = HT_INITIALIZER(); + +HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node, + cached_getaddrinfo_item_hash, + cached_getaddrinfo_items_eq) +HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node, + cached_getaddrinfo_item_hash, + cached_getaddrinfo_items_eq, + 0.6, tor_reallocarray_, tor_free_) + +/** If true, don't try to cache getaddrinfo results. */ +static int sandbox_getaddrinfo_cache_disabled = 0; + +/** Tell the sandbox layer not to try to cache getaddrinfo results. Used as in + * tor-resolve, when we have no intention of initializing crypto or of + * installing the sandbox.*/ +void +sandbox_disable_getaddrinfo_cache(void) +{ + sandbox_getaddrinfo_cache_disabled = 1; +} + +void +sandbox_freeaddrinfo(struct addrinfo *ai) +{ + if (sandbox_getaddrinfo_cache_disabled) + freeaddrinfo(ai); +} + +int +sandbox_getaddrinfo(const char *name, const char *servname, + const struct addrinfo *hints, + struct addrinfo **res) +{ + int err; + struct cached_getaddrinfo_item_t search, *item; + + if (sandbox_getaddrinfo_cache_disabled) { + return getaddrinfo(name, NULL, hints, res); + } + + if (servname != NULL) { + log_warn(LD_BUG, "called with non-NULL servname"); + return EAI_NONAME; + } + if (name == NULL) { + log_warn(LD_BUG, "called with NULL name"); + return EAI_NONAME; + } + + *res = NULL; + + memset(&search, 0, sizeof(search)); + search.name = (char *) name; + search.family = hints ? hints->ai_family : AF_UNSPEC; + item = HT_FIND(getaddrinfo_cache, &getaddrinfo_cache, &search); + + if (! sandbox_getaddrinfo_is_active) { + /* If the sandbox is not turned on yet, then getaddrinfo and store the + result. */ + + err = getaddrinfo(name, NULL, hints, res); + log_info(LD_NET,"(Sandbox) getaddrinfo %s.", err ? "failed" : "succeeded"); + + if (! item) { + item = tor_malloc_zero(sizeof(*item)); + item->name = tor_strdup(name); + item->family = hints ? hints->ai_family : AF_UNSPEC; + HT_INSERT(getaddrinfo_cache, &getaddrinfo_cache, item); + } + + if (item->res) { + freeaddrinfo(item->res); + item->res = NULL; + } + item->res = *res; + item->err = err; + return err; + } + + /* Otherwise, the sandbox is on. If we have an item, yield its cached + result. */ + if (item) { + *res = item->res; + return item->err; + } + + /* getting here means something went wrong */ + log_err(LD_BUG,"(Sandbox) failed to get address %s!", name); + return EAI_NONAME; +} + +int +sandbox_add_addrinfo(const char *name) +{ + struct addrinfo *res; + struct addrinfo hints; + int i; + static const int families[] = { AF_INET, AF_INET6, AF_UNSPEC }; + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + for (i = 0; i < 3; ++i) { + hints.ai_family = families[i]; + + res = NULL; + (void) sandbox_getaddrinfo(name, NULL, &hints, &res); + if (res) + sandbox_freeaddrinfo(res); + } + + return 0; +} + +void +sandbox_free_getaddrinfo_cache(void) +{ + cached_getaddrinfo_item_t **next, **item, *this; + + for (item = HT_START(getaddrinfo_cache, &getaddrinfo_cache); + item; + item = next) { + this = *item; + next = HT_NEXT_RMV(getaddrinfo_cache, &getaddrinfo_cache, item); + cached_getaddrinfo_item_free(this); + } + + HT_CLEAR(getaddrinfo_cache, &getaddrinfo_cache); +} + +void +sandbox_make_getaddrinfo_cache_active(void) +{ + sandbox_getaddrinfo_is_active = 1; +} +#endif diff --git a/src/lib/net/resolve.h b/src/lib/net/resolve.h new file mode 100644 index 0000000000..a225be87fe --- /dev/null +++ b/src/lib/net/resolve.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_RESOLVE_H +#define TOR_RESOLVE_H + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" +#ifdef _WIN32 +#include <winsock2.h> +#endif + +#if defined(HAVE_SECCOMP_H) && defined(__linux__) +#define USE_SANDBOX_GETADDRINFO +#endif + +MOCK_DECL(int,tor_lookup_hostname,(const char *name, uint32_t *addr)); + +struct addrinfo; +#ifdef USE_SANDBOX_GETADDRINFO +/** Pre-calls getaddrinfo in order to pre-record result. */ +int sandbox_add_addrinfo(const char *addr); + +// XXXX rename these. They are named as though they were sandbox-only, +// XXXX but in fact they're the only allowed entry point to getaddrinfo. +// XXXX They don't invoke the sandbox code; they only have an internal cache. +struct addrinfo; +/** Replacement for getaddrinfo(), using pre-recorded results. */ +int sandbox_getaddrinfo(const char *name, const char *servname, + const struct addrinfo *hints, + struct addrinfo **res); +void sandbox_freeaddrinfo(struct addrinfo *addrinfo); +void sandbox_free_getaddrinfo_cache(void); +void sandbox_make_getaddrinfo_cache_active(void); +#else /* !(defined(USE_SANDBOX_GETADDRINFO)) */ +#define sandbox_getaddrinfo(name, servname, hints, res) \ + getaddrinfo((name),(servname), (hints),(res)) +#define sandbox_add_addrinfo(name) \ + ((void)(name)) +#define sandbox_freeaddrinfo(addrinfo) \ + freeaddrinfo((addrinfo)) +#define sandbox_free_getaddrinfo_cache() +#endif /* defined(USE_SANDBOX_GETADDRINFO) */ + +void sandbox_disable_getaddrinfo_cache(void); + +#endif diff --git a/src/lib/net/socket.c b/src/lib/net/socket.c new file mode 100644 index 0000000000..dc3d1531ff --- /dev/null +++ b/src/lib/net/socket.c @@ -0,0 +1,824 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define SOCKET_PRIVATE +#include "lib/net/socket.h" +#include "lib/net/address.h" +#include "lib/cc/compat_compiler.h" +#include "lib/err/torerr.h" +#include "lib/lock/compat_mutex.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +#ifdef _WIN32 +#include <winsock2.h> +#include <windows.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#include <stddef.h> +#include <string.h> + +/** Called before we make any calls to network-related functions. + * (Some operating systems require their network libraries to be + * initialized.) */ +int +network_init(void) +{ +#ifdef _WIN32 + /* This silly exercise is necessary before windows will allow + * gethostbyname to work. */ + WSADATA WSAData; + int r; + r = WSAStartup(0x101,&WSAData); + if (r) { + log_warn(LD_NET,"Error initializing windows network layer: code was %d",r); + return -1; + } + if (sizeof(SOCKET) != sizeof(tor_socket_t)) { + log_warn(LD_BUG,"The tor_socket_t type does not match SOCKET in size; Tor " + "might not work. (Sizes are %d and %d respectively.)", + (int)sizeof(tor_socket_t), (int)sizeof(SOCKET)); + } + /* WSAData.iMaxSockets might show the max sockets we're allowed to use. + * We might use it to complain if we're trying to be a server but have + * too few sockets available. */ +#endif /* defined(_WIN32) */ + return 0; +} + +/* When set_max_file_sockets() is called, update this with the max file + * descriptor value so we can use it to check the limit when opening a new + * socket. Default value is what Debian sets as the default hard limit. */ +static int max_sockets = 1024; + +/** Return the maximum number of allowed sockets. */ +int +get_max_sockets(void) +{ + return max_sockets; +} + +/** Set the maximum number of allowed sockets to <b>n</b> */ +void +set_max_sockets(int n) +{ + max_sockets = n; +} + +#undef DEBUG_SOCKET_COUNTING +#ifdef DEBUG_SOCKET_COUNTING +#include "lib/container/bitarray.h" + +/** A bitarray of all fds that should be passed to tor_socket_close(). Only + * used if DEBUG_SOCKET_COUNTING is defined. */ +static bitarray_t *open_sockets = NULL; +/** The size of <b>open_sockets</b>, in bits. */ +static int max_socket = -1; +#endif /* defined(DEBUG_SOCKET_COUNTING) */ + +/** Count of number of sockets currently open. (Undercounts sockets opened by + * eventdns and libevent.) */ +static int n_sockets_open = 0; + +/** Mutex to protect open_sockets, max_socket, and n_sockets_open. */ +static tor_mutex_t *socket_accounting_mutex = NULL; + +/** Helper: acquire the socket accounting lock. */ +static inline void +socket_accounting_lock(void) +{ + if (PREDICT_UNLIKELY(!socket_accounting_mutex)) + socket_accounting_mutex = tor_mutex_new(); + tor_mutex_acquire(socket_accounting_mutex); +} + +/** Helper: release the socket accounting lock. */ +static inline void +socket_accounting_unlock(void) +{ + tor_mutex_release(socket_accounting_mutex); +} + +/** As close(), but guaranteed to work for sockets across platforms (including + * Windows, where close()ing a socket doesn't work. Returns 0 on success and + * the socket error code on failure. */ +int +tor_close_socket_simple(tor_socket_t s) +{ + int r = 0; + + /* On Windows, you have to call close() on fds returned by open(), + * and closesocket() on fds returned by socket(). On Unix, everything + * gets close()'d. We abstract this difference by always using + * tor_close_socket to close sockets, and always using close() on + * files. + */ + #if defined(_WIN32) + r = closesocket(s); + #else + r = close(s); + #endif + + if (r != 0) { + int err = tor_socket_errno(-1); + log_info(LD_NET, "Close returned an error: %s", tor_socket_strerror(err)); + return err; + } + + return r; +} + +/** As tor_close_socket_simple(), but keeps track of the number + * of open sockets. Returns 0 on success, -1 on failure. */ +MOCK_IMPL(int, +tor_close_socket,(tor_socket_t s)) +{ + int r = tor_close_socket_simple(s); + + socket_accounting_lock(); +#ifdef DEBUG_SOCKET_COUNTING + if (s > max_socket || ! bitarray_is_set(open_sockets, s)) { + log_warn(LD_BUG, "Closing a socket (%d) that wasn't returned by tor_open_" + "socket(), or that was already closed or something.", s); + } else { + tor_assert(open_sockets && s <= max_socket); + bitarray_clear(open_sockets, s); + } +#endif /* defined(DEBUG_SOCKET_COUNTING) */ + if (r == 0) { + --n_sockets_open; + } else { +#ifdef _WIN32 + if (r != WSAENOTSOCK) + --n_sockets_open; +#else + if (r != EBADF) + --n_sockets_open; // LCOV_EXCL_LINE -- EIO and EINTR too hard to force. +#endif /* defined(_WIN32) */ + r = -1; + } + + tor_assert_nonfatal(n_sockets_open >= 0); + socket_accounting_unlock(); + return r; +} + +/** @{ */ +#ifdef DEBUG_SOCKET_COUNTING +/** Helper: if DEBUG_SOCKET_COUNTING is enabled, remember that <b>s</b> is + * now an open socket. */ +static inline void +mark_socket_open(tor_socket_t s) +{ + /* XXXX This bitarray business will NOT work on windows: sockets aren't + small ints there. */ + if (s > max_socket) { + if (max_socket == -1) { + open_sockets = bitarray_init_zero(s+128); + max_socket = s+128; + } else { + open_sockets = bitarray_expand(open_sockets, max_socket, s+128); + max_socket = s+128; + } + } + if (bitarray_is_set(open_sockets, s)) { + log_warn(LD_BUG, "I thought that %d was already open, but socket() just " + "gave it to me!", s); + } + bitarray_set(open_sockets, s); +} +#else /* !(defined(DEBUG_SOCKET_COUNTING)) */ +#define mark_socket_open(s) ((void) (s)) +#endif /* defined(DEBUG_SOCKET_COUNTING) */ +/** @} */ + +/** As socket(), but counts the number of open sockets. */ +MOCK_IMPL(tor_socket_t, +tor_open_socket,(int domain, int type, int protocol)) +{ + return tor_open_socket_with_extensions(domain, type, protocol, 1, 0); +} + +/** Mockable wrapper for connect(). */ +MOCK_IMPL(tor_socket_t, +tor_connect_socket,(tor_socket_t sock, const struct sockaddr *address, + socklen_t address_len)) +{ + return connect(sock,address,address_len); +} + +/** As socket(), but creates a nonblocking socket and + * counts the number of open sockets. */ +tor_socket_t +tor_open_socket_nonblocking(int domain, int type, int protocol) +{ + return tor_open_socket_with_extensions(domain, type, protocol, 1, 1); +} + +/** As socket(), but counts the number of open sockets and handles + * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified. + * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate + * if the corresponding extension should be used.*/ +tor_socket_t +tor_open_socket_with_extensions(int domain, int type, int protocol, + int cloexec, int nonblock) +{ + tor_socket_t s; + + /* We are about to create a new file descriptor so make sure we have + * enough of them. */ + if (get_n_open_sockets() >= max_sockets - 1) { +#ifdef _WIN32 + WSASetLastError(WSAEMFILE); +#else + errno = EMFILE; +#endif + return TOR_INVALID_SOCKET; + } + +#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) + int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) | + (nonblock ? SOCK_NONBLOCK : 0); + s = socket(domain, type|ext_flags, protocol); + if (SOCKET_OK(s)) + goto socket_ok; + /* If we got an error, see if it is EINVAL. EINVAL might indicate that, + * even though we were built on a system with SOCK_CLOEXEC and SOCK_NONBLOCK + * support, we are running on one without. */ + if (errno != EINVAL) + return s; +#endif /* defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) */ + + s = socket(domain, type, protocol); + if (! SOCKET_OK(s)) + return s; + +#if defined(FD_CLOEXEC) + if (cloexec) { + if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) { + log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); + tor_close_socket_simple(s); + return TOR_INVALID_SOCKET; + } + } +#else /* !(defined(FD_CLOEXEC)) */ + (void)cloexec; +#endif /* defined(FD_CLOEXEC) */ + + if (nonblock) { + if (set_socket_nonblocking(s) == -1) { + tor_close_socket_simple(s); + return TOR_INVALID_SOCKET; + } + } + + goto socket_ok; /* So that socket_ok will not be unused. */ + + socket_ok: + tor_take_socket_ownership(s); + return s; +} + +/** + * For socket accounting: remember that we are the owner of the socket + * <b>s</b>. This will prevent us from overallocating sockets, and prevent us + * from asserting later when we close the socket <b>s</b>. + */ +void +tor_take_socket_ownership(tor_socket_t s) +{ + socket_accounting_lock(); + ++n_sockets_open; + mark_socket_open(s); + socket_accounting_unlock(); +} + +/** As accept(), but counts the number of open sockets. */ +tor_socket_t +tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len) +{ + return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 0); +} + +/** As accept(), but returns a nonblocking socket and + * counts the number of open sockets. */ +tor_socket_t +tor_accept_socket_nonblocking(tor_socket_t sockfd, struct sockaddr *addr, + socklen_t *len) +{ + return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 1); +} + +/** As accept(), but counts the number of open sockets and handles + * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified. + * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate + * if the corresponding extension should be used.*/ +tor_socket_t +tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr, + socklen_t *len, int cloexec, int nonblock) +{ + tor_socket_t s; + + /* We are about to create a new file descriptor so make sure we have + * enough of them. */ + if (get_n_open_sockets() >= max_sockets - 1) { +#ifdef _WIN32 + WSASetLastError(WSAEMFILE); +#else + errno = EMFILE; +#endif + return TOR_INVALID_SOCKET; + } + +#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) \ + && defined(SOCK_NONBLOCK) + int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) | + (nonblock ? SOCK_NONBLOCK : 0); + s = accept4(sockfd, addr, len, ext_flags); + if (SOCKET_OK(s)) + goto socket_ok; + /* If we got an error, see if it is ENOSYS. ENOSYS indicates that, + * even though we were built on a system with accept4 support, we + * are running on one without. Also, check for EINVAL, which indicates that + * we are missing SOCK_CLOEXEC/SOCK_NONBLOCK support. */ + if (errno != EINVAL && errno != ENOSYS) + return s; +#endif /* defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) ... */ + + s = accept(sockfd, addr, len); + if (!SOCKET_OK(s)) + return s; + +#if defined(FD_CLOEXEC) + if (cloexec) { + if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) { + log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno)); + tor_close_socket_simple(s); + return TOR_INVALID_SOCKET; + } + } +#else /* !(defined(FD_CLOEXEC)) */ + (void)cloexec; +#endif /* defined(FD_CLOEXEC) */ + + if (nonblock) { + if (set_socket_nonblocking(s) == -1) { + tor_close_socket_simple(s); + return TOR_INVALID_SOCKET; + } + } + + goto socket_ok; /* So that socket_ok will not be unused. */ + + socket_ok: + tor_take_socket_ownership(s); + return s; +} + +/** Return the number of sockets we currently have opened. */ +int +get_n_open_sockets(void) +{ + int n; + socket_accounting_lock(); + n = n_sockets_open; + socket_accounting_unlock(); + return n; +} + +/** + * Allocate a pair of connected sockets. (Like socketpair(family, + * type,protocol,fd), but works on systems that don't have + * socketpair.) + * + * Currently, only (AF_UNIX, SOCK_STREAM, 0) sockets are supported. + * + * Note that on systems without socketpair, this call will fail if + * localhost is inaccessible (for example, if the networking + * stack is down). And even if it succeeds, the socket pair will not + * be able to read while localhost is down later (the socket pair may + * even close, depending on OS-specific timeouts). + * + * Returns 0 on success and -errno on failure; do not rely on the value + * of errno or WSAGetLastError(). + **/ +/* It would be nicer just to set errno, but that won't work for windows. */ +int +tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) +{ +//don't use win32 socketpairs (they are always bad) +#if defined(HAVE_SOCKETPAIR) && !defined(_WIN32) + int r; + +#ifdef SOCK_CLOEXEC + r = socketpair(family, type|SOCK_CLOEXEC, protocol, fd); + if (r == 0) + goto sockets_ok; + /* If we got an error, see if it is EINVAL. EINVAL might indicate that, + * even though we were built on a system with SOCK_CLOEXEC support, we + * are running on one without. */ + if (errno != EINVAL) + return -errno; +#endif /* defined(SOCK_CLOEXEC) */ + + r = socketpair(family, type, protocol, fd); + if (r < 0) + return -errno; + +#if defined(FD_CLOEXEC) + if (SOCKET_OK(fd[0])) { + r = fcntl(fd[0], F_SETFD, FD_CLOEXEC); + if (r == -1) { + close(fd[0]); + close(fd[1]); + return -errno; + } + } + if (SOCKET_OK(fd[1])) { + r = fcntl(fd[1], F_SETFD, FD_CLOEXEC); + if (r == -1) { + close(fd[0]); + close(fd[1]); + return -errno; + } + } +#endif /* defined(FD_CLOEXEC) */ + goto sockets_ok; /* So that sockets_ok will not be unused. */ + + sockets_ok: + socket_accounting_lock(); + if (SOCKET_OK(fd[0])) { + ++n_sockets_open; + mark_socket_open(fd[0]); + } + if (SOCKET_OK(fd[1])) { + ++n_sockets_open; + mark_socket_open(fd[1]); + } + socket_accounting_unlock(); + + return 0; +#else /* !(defined(HAVE_SOCKETPAIR) && !defined(_WIN32)) */ + return tor_ersatz_socketpair(family, type, protocol, fd); +#endif /* defined(HAVE_SOCKETPAIR) && !defined(_WIN32) */ +} + +#ifdef NEED_ERSATZ_SOCKETPAIR + +static inline socklen_t +SIZEOF_SOCKADDR(int domain) +{ + switch (domain) { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + default: + return 0; + } +} + +/** + * Helper used to implement socketpair on systems that lack it, by + * making a direct connection to localhost. + */ +STATIC int +tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) +{ + /* This socketpair does not work when localhost is down. So + * it's really not the same thing at all. But it's close enough + * for now, and really, when localhost is down sometimes, we + * have other problems too. + */ + tor_socket_t listener = TOR_INVALID_SOCKET; + tor_socket_t connector = TOR_INVALID_SOCKET; + tor_socket_t acceptor = TOR_INVALID_SOCKET; + tor_addr_t listen_tor_addr; + struct sockaddr_storage connect_addr_ss, listen_addr_ss; + struct sockaddr *listen_addr = (struct sockaddr *) &listen_addr_ss; + uint16_t listen_port = 0; + tor_addr_t connect_tor_addr; + uint16_t connect_port = 0; + struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss; + socklen_t size; + int saved_errno = -1; + int ersatz_domain = AF_INET; + + memset(&connect_tor_addr, 0, sizeof(connect_tor_addr)); + memset(&connect_addr_ss, 0, sizeof(connect_addr_ss)); + memset(&listen_tor_addr, 0, sizeof(listen_tor_addr)); + memset(&listen_addr_ss, 0, sizeof(listen_addr_ss)); + + if (protocol +#ifdef AF_UNIX + || family != AF_UNIX +#endif + ) { +#ifdef _WIN32 + return -WSAEAFNOSUPPORT; +#else + return -EAFNOSUPPORT; +#endif + } + if (!fd) { + return -EINVAL; + } + + listener = tor_open_socket(ersatz_domain, type, 0); + if (!SOCKET_OK(listener)) { + int first_errno = tor_socket_errno(-1); + if (first_errno == SOCK_ERRNO(EPROTONOSUPPORT) + && ersatz_domain == AF_INET) { + /* Assume we're on an IPv6-only system */ + ersatz_domain = AF_INET6; + listener = tor_open_socket(ersatz_domain, type, 0); + if (!SOCKET_OK(listener)) { + /* Keep the previous behaviour, which was to return the IPv4 error. + * (This may be less informative on IPv6-only systems.) + * XX/teor - is there a better way to decide which errno to return? + * (I doubt we care much either way, once there is an error.) + */ + return -first_errno; + } + } + } + /* If there is no 127.0.0.1 or ::1, this will and must fail. Otherwise, we + * risk exposing a socketpair on a routable IP address. (Some BSD jails + * use a routable address for localhost. Fortunately, they have the real + * AF_UNIX socketpair.) */ + if (ersatz_domain == AF_INET) { + tor_addr_from_ipv4h(&listen_tor_addr, INADDR_LOOPBACK); + } else { + tor_addr_parse(&listen_tor_addr, "[::1]"); + } + tor_assert(tor_addr_is_loopback(&listen_tor_addr)); + size = tor_addr_to_sockaddr(&listen_tor_addr, + 0 /* kernel chooses port. */, + listen_addr, + sizeof(listen_addr_ss)); + if (bind(listener, listen_addr, size) == -1) + goto tidy_up_and_fail; + if (listen(listener, 1) == -1) + goto tidy_up_and_fail; + + connector = tor_open_socket(ersatz_domain, type, 0); + if (!SOCKET_OK(connector)) + goto tidy_up_and_fail; + /* We want to find out the port number to connect to. */ + size = sizeof(connect_addr_ss); + if (getsockname(listener, connect_addr, &size) == -1) + goto tidy_up_and_fail; + if (size != SIZEOF_SOCKADDR (connect_addr->sa_family)) + goto abort_tidy_up_and_fail; + if (connect(connector, connect_addr, size) == -1) + goto tidy_up_and_fail; + + size = sizeof(listen_addr_ss); + acceptor = tor_accept_socket(listener, listen_addr, &size); + if (!SOCKET_OK(acceptor)) + goto tidy_up_and_fail; + if (size != SIZEOF_SOCKADDR(listen_addr->sa_family)) + goto abort_tidy_up_and_fail; + /* Now check we are talking to ourself by matching port and host on the + two sockets. */ + if (getsockname(connector, connect_addr, &size) == -1) + goto tidy_up_and_fail; + /* Set *_tor_addr and *_port to the address and port that was used */ + tor_addr_from_sockaddr(&listen_tor_addr, listen_addr, &listen_port); + tor_addr_from_sockaddr(&connect_tor_addr, connect_addr, &connect_port); + if (size != SIZEOF_SOCKADDR (connect_addr->sa_family) + || tor_addr_compare(&listen_tor_addr, &connect_tor_addr, CMP_SEMANTIC) + || listen_port != connect_port) { + goto abort_tidy_up_and_fail; + } + tor_close_socket(listener); + fd[0] = connector; + fd[1] = acceptor; + + return 0; + + abort_tidy_up_and_fail: +#ifdef _WIN32 + saved_errno = WSAECONNABORTED; +#else + saved_errno = ECONNABORTED; /* I hope this is portable and appropriate. */ +#endif + tidy_up_and_fail: + if (saved_errno < 0) + saved_errno = errno; + if (SOCKET_OK(listener)) + tor_close_socket(listener); + if (SOCKET_OK(connector)) + tor_close_socket(connector); + if (SOCKET_OK(acceptor)) + tor_close_socket(acceptor); + return -saved_errno; +} + +#endif /* defined(NEED_ERSATZ_SOCKETPAIR) */ + +/** Mockable wrapper for getsockname(). */ +MOCK_IMPL(int, +tor_getsockname,(tor_socket_t sock, struct sockaddr *address, + socklen_t *address_len)) +{ + return getsockname(sock, address, address_len); +} + +/** + * Find the local address associated with the socket <b>sock</b>, and + * place it in *<b>addr_out</b>. Return 0 on success, -1 on failure. + * + * (As tor_getsockname, but instead places the result in a tor_addr_t.) */ +int +tor_addr_from_getsockname(struct tor_addr_t *addr_out, tor_socket_t sock) +{ + struct sockaddr_storage ss; + socklen_t ss_len = sizeof(ss); + memset(&ss, 0, sizeof(ss)); + + if (tor_getsockname(sock, (struct sockaddr *) &ss, &ss_len) < 0) + return -1; + + return tor_addr_from_sockaddr(addr_out, (struct sockaddr *)&ss, NULL); +} + +/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1 + * on failure. + */ +int +set_socket_nonblocking(tor_socket_t sock) +{ +#if defined(_WIN32) + unsigned long nonblocking = 1; + ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking); +#else + int flags; + + flags = fcntl(sock, F_GETFL, 0); + if (flags == -1) { + log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno)); + return -1; + } + flags |= O_NONBLOCK; + if (fcntl(sock, F_SETFL, flags) == -1) { + log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno)); + return -1; + } +#endif /* defined(_WIN32) */ + + return 0; +} + +/** Read from <b>sock</b> to <b>buf</b>, until we get <b>count</b> bytes or + * reach the end of the file. Return the number of bytes read, or -1 on + * error. Only use if fd is a blocking fd. */ +ssize_t +read_all_from_socket(tor_socket_t sock, char *buf, size_t count) +{ + size_t numread = 0; + ssize_t result; + + if (count > SIZE_T_CEILING || count > SSIZE_MAX) { + errno = EINVAL; + return -1; + } + + while (numread < count) { + result = tor_socket_recv(sock, buf+numread, count-numread, 0); + if (result<0) + return -1; + else if (result == 0) + break; + numread += result; + } + return (ssize_t)numread; +} + +/** Write <b>count</b> bytes from <b>buf</b> to <b>sock</b>. Return the number + * of bytes written, or -1 on error. Only use if fd is a blocking fd. */ +ssize_t +write_all_to_socket(tor_socket_t fd, const char *buf, size_t count) +{ + size_t written = 0; + ssize_t result; + raw_assert(count < SSIZE_MAX); + + while (written != count) { + result = tor_socket_send(fd, buf+written, count-written, 0); + if (result<0) + return -1; + written += result; + } + return (ssize_t)count; +} + +/** + * On Windows, WSAEWOULDBLOCK is not always correct: when you see it, + * you need to ask the socket for its actual errno. Also, you need to + * get your errors from WSAGetLastError, not errno. (If you supply a + * socket of -1, we check WSAGetLastError, but don't correct + * WSAEWOULDBLOCKs.) + * + * The upshot of all of this is that when a socket call fails, you + * should call tor_socket_errno <em>at most once</em> on the failing + * socket to get the error. + */ +#if defined(_WIN32) +int +tor_socket_errno(tor_socket_t sock) +{ + int optval, optvallen=sizeof(optval); + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK && SOCKET_OK(sock)) { + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval, &optvallen)) + return err; + if (optval) + return optval; + } + return err; +} +#endif /* defined(_WIN32) */ + +#if defined(_WIN32) +#define E(code, s) { code, (s " [" #code " ]") } +struct { int code; const char *msg; } windows_socket_errors[] = { + E(WSAEINTR, "Interrupted function call"), + E(WSAEACCES, "Permission denied"), + E(WSAEFAULT, "Bad address"), + E(WSAEINVAL, "Invalid argument"), + E(WSAEMFILE, "Too many open files"), + E(WSAEWOULDBLOCK, "Resource temporarily unavailable"), + E(WSAEINPROGRESS, "Operation now in progress"), + E(WSAEALREADY, "Operation already in progress"), + E(WSAENOTSOCK, "Socket operation on nonsocket"), + E(WSAEDESTADDRREQ, "Destination address required"), + E(WSAEMSGSIZE, "Message too long"), + E(WSAEPROTOTYPE, "Protocol wrong for socket"), + E(WSAENOPROTOOPT, "Bad protocol option"), + E(WSAEPROTONOSUPPORT, "Protocol not supported"), + E(WSAESOCKTNOSUPPORT, "Socket type not supported"), + /* What's the difference between NOTSUPP and NOSUPPORT? :) */ + E(WSAEOPNOTSUPP, "Operation not supported"), + E(WSAEPFNOSUPPORT, "Protocol family not supported"), + E(WSAEAFNOSUPPORT, "Address family not supported by protocol family"), + E(WSAEADDRINUSE, "Address already in use"), + E(WSAEADDRNOTAVAIL, "Cannot assign requested address"), + E(WSAENETDOWN, "Network is down"), + E(WSAENETUNREACH, "Network is unreachable"), + E(WSAENETRESET, "Network dropped connection on reset"), + E(WSAECONNABORTED, "Software caused connection abort"), + E(WSAECONNRESET, "Connection reset by peer"), + E(WSAENOBUFS, "No buffer space available"), + E(WSAEISCONN, "Socket is already connected"), + E(WSAENOTCONN, "Socket is not connected"), + E(WSAESHUTDOWN, "Cannot send after socket shutdown"), + E(WSAETIMEDOUT, "Connection timed out"), + E(WSAECONNREFUSED, "Connection refused"), + E(WSAEHOSTDOWN, "Host is down"), + E(WSAEHOSTUNREACH, "No route to host"), + E(WSAEPROCLIM, "Too many processes"), + /* Yes, some of these start with WSA, not WSAE. No, I don't know why. */ + E(WSASYSNOTREADY, "Network subsystem is unavailable"), + E(WSAVERNOTSUPPORTED, "Winsock.dll out of range"), + E(WSANOTINITIALISED, "Successful WSAStartup not yet performed"), + E(WSAEDISCON, "Graceful shutdown now in progress"), +#ifdef WSATYPE_NOT_FOUND + E(WSATYPE_NOT_FOUND, "Class type not found"), +#endif + E(WSAHOST_NOT_FOUND, "Host not found"), + E(WSATRY_AGAIN, "Nonauthoritative host not found"), + E(WSANO_RECOVERY, "This is a nonrecoverable error"), + E(WSANO_DATA, "Valid name, no data record of requested type)"), + + /* There are some more error codes whose numeric values are marked + * <b>OS dependent</b>. They start with WSA_, apparently for the same + * reason that practitioners of some craft traditions deliberately + * introduce imperfections into their baskets and rugs "to allow the + * evil spirits to escape." If we catch them, then our binaries + * might not report consistent results across versions of Windows. + * Thus, I'm going to let them all fall through. + */ + { -1, NULL }, +}; +/** There does not seem to be a strerror equivalent for Winsock errors. + * Naturally, we have to roll our own. + */ +const char * +tor_socket_strerror(int e) +{ + int i; + for (i=0; windows_socket_errors[i].code >= 0; ++i) { + if (e == windows_socket_errors[i].code) + return windows_socket_errors[i].msg; + } + return strerror(e); +} +#endif /* defined(_WIN32) */ diff --git a/src/lib/net/socket.h b/src/lib/net/socket.h new file mode 100644 index 0000000000..cb0ccbe817 --- /dev/null +++ b/src/lib/net/socket.h @@ -0,0 +1,120 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SOCKET_H +#define TOR_SOCKET_H + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/net/nettypes.h" +#include "lib/testsupport/testsupport.h" + +#include <errno.h> + +struct sockaddr; + +int tor_close_socket_simple(tor_socket_t s); +MOCK_DECL(int, tor_close_socket, (tor_socket_t s)); +void tor_take_socket_ownership(tor_socket_t s); +tor_socket_t tor_open_socket_with_extensions( + int domain, int type, int protocol, + int cloexec, int nonblock); +MOCK_DECL(tor_socket_t,tor_open_socket,(int domain, int type, int protocol)); +tor_socket_t tor_open_socket_nonblocking(int domain, int type, int protocol); +tor_socket_t tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, + socklen_t *len); +tor_socket_t tor_accept_socket_nonblocking(tor_socket_t sockfd, + struct sockaddr *addr, + socklen_t *len); +tor_socket_t tor_accept_socket_with_extensions(tor_socket_t sockfd, + struct sockaddr *addr, + socklen_t *len, + int cloexec, int nonblock); +MOCK_DECL(tor_socket_t, tor_connect_socket,(tor_socket_t socket, + const struct sockaddr *address, + socklen_t address_len)); +int get_n_open_sockets(void); + +MOCK_DECL(int,tor_getsockname,(tor_socket_t socket, struct sockaddr *address, + socklen_t *address_len)); +struct tor_addr_t; +int tor_addr_from_getsockname(struct tor_addr_t *addr_out, tor_socket_t sock); + +#define tor_socket_send(s, buf, len, flags) send(s, buf, len, flags) +#define tor_socket_recv(s, buf, len, flags) recv(s, buf, len, flags) + +int set_socket_nonblocking(tor_socket_t socket); +int tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]); +int network_init(void); + +int get_max_sockets(void); +void set_max_sockets(int); + +ssize_t write_all_to_socket(tor_socket_t fd, const char *buf, size_t count); +ssize_t read_all_from_socket(tor_socket_t fd, char *buf, size_t count); + +/* For stupid historical reasons, windows sockets have an independent + * set of errnos, and an independent way to get them. Also, you can't + * always believe WSAEWOULDBLOCK. Use the macros below to compare + * errnos against expected values, and use tor_socket_errno to find + * the actual errno after a socket operation fails. + */ +#if defined(_WIN32) +/** Expands to WSA<b>e</b> on Windows, and to <b>e</b> elsewhere. */ +#define SOCK_ERRNO(e) WSA##e +/** Return true if e is EAGAIN or the local equivalent. */ +#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == WSAEWOULDBLOCK) +/** Return true if e is EINPROGRESS or the local equivalent. */ +#define ERRNO_IS_EINPROGRESS(e) ((e) == WSAEINPROGRESS) +/** Return true if e is EINPROGRESS or the local equivalent as returned by + * a call to connect(). */ +#define ERRNO_IS_CONN_EINPROGRESS(e) \ + ((e) == WSAEINPROGRESS || (e)== WSAEINVAL || (e) == WSAEWOULDBLOCK) +/** Return true if e is EAGAIN or another error indicating that a call to + * accept() has no pending connections to return. */ +#define ERRNO_IS_ACCEPT_EAGAIN(e) ERRNO_IS_EAGAIN(e) +/** Return true if e is EMFILE or another error indicating that a call to + * accept() has failed because we're out of fds or something. */ +#define ERRNO_IS_RESOURCE_LIMIT(e) \ + ((e) == WSAEMFILE || (e) == WSAENOBUFS) +/** Return true if e is EADDRINUSE or the local equivalent. */ +#define ERRNO_IS_EADDRINUSE(e) ((e) == WSAEADDRINUSE) +/** Return true if e is EINTR or the local equivalent */ +#define ERRNO_IS_EINTR(e) ((e) == WSAEINTR || 0) +int tor_socket_errno(tor_socket_t sock); +const char *tor_socket_strerror(int e); +#else /* !(defined(_WIN32)) */ +#define SOCK_ERRNO(e) e +#if EAGAIN == EWOULDBLOCK +/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */ +#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || 0) +#else +#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == EWOULDBLOCK) +#endif /* EAGAIN == EWOULDBLOCK */ +#define ERRNO_IS_EINTR(e) ((e) == EINTR || 0) +#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS || 0) +#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS || 0) +#define ERRNO_IS_ACCEPT_EAGAIN(e) \ + (ERRNO_IS_EAGAIN(e) || (e) == ECONNABORTED) +#define ERRNO_IS_RESOURCE_LIMIT(e) \ + ((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM) +#define ERRNO_IS_EADDRINUSE(e) (((e) == EADDRINUSE) || 0) +#define tor_socket_errno(sock) (errno) +#define tor_socket_strerror(e) strerror(e) +#endif /* defined(_WIN32) */ + +#ifdef SOCKET_PRIVATE +#if !defined(HAVE_SOCKETPAIR) || defined(_WIN32) || defined(TOR_UNIT_TESTS) +#define NEED_ERSATZ_SOCKETPAIR +STATIC int tor_ersatz_socketpair(int family, int type, int protocol, + tor_socket_t fd[2]); +#endif +#endif /* defined(COMPAT_PRIVATE) */ + +#if defined(_WIN32) && !defined(SIO_IDEAL_SEND_BACKLOG_QUERY) +#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747b +#endif + +#endif diff --git a/src/lib/osinfo/.may_include b/src/lib/osinfo/.may_include new file mode 100644 index 0000000000..058f6eb89c --- /dev/null +++ b/src/lib/osinfo/.may_include @@ -0,0 +1,5 @@ +orconfig.h + +lib/osinfo/*.h +lib/string/*.h +lib/testsupport/*.h diff --git a/src/lib/osinfo/include.am b/src/lib/osinfo/include.am new file mode 100644 index 0000000000..16c5812604 --- /dev/null +++ b/src/lib/osinfo/include.am @@ -0,0 +1,17 @@ + +noinst_LIBRARIES += src/lib/libtor-osinfo.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-osinfo-testing.a +endif + +src_lib_libtor_osinfo_a_SOURCES = \ + src/lib/osinfo/uname.c + +src_lib_libtor_osinfo_testing_a_SOURCES = \ + $(src_lib_libtor_osinfo_a_SOURCES) +src_lib_libtor_osinfo_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_osinfo_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/osinfo/uname.h diff --git a/src/lib/osinfo/uname.c b/src/lib/osinfo/uname.c new file mode 100644 index 0000000000..fb5cc7c20d --- /dev/null +++ b/src/lib/osinfo/uname.c @@ -0,0 +1,110 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/osinfo/uname.h" + +#include "lib/string/compat_string.h" +#include "lib/string/printf.h" + +#ifdef HAVE_UNAME +#include <sys/utsname.h> +#endif +#ifdef _WIN32 +#include <windows.h> +#endif + +/** Hold the result of our call to <b>uname</b>. */ +static char uname_result[256]; +/** True iff uname_result is set. */ +static int uname_result_is_set = 0; + +/** Return a pointer to a description of our platform. + */ +MOCK_IMPL(const char *, +get_uname,(void)) +{ +#ifdef HAVE_UNAME + struct utsname u; +#endif + if (!uname_result_is_set) { +#ifdef HAVE_UNAME + if (uname(&u) != -1) { + /* (Linux says 0 is success, Solaris says 1 is success) */ + strlcpy(uname_result, u.sysname, sizeof(uname_result)); + } else +#endif /* defined(HAVE_UNAME) */ + { +#ifdef _WIN32 + OSVERSIONINFOEX info; + int i; + const char *plat = NULL; + static struct { + unsigned major; unsigned minor; const char *version; + } win_version_table[] = { + { 6, 2, "Windows 8" }, + { 6, 1, "Windows 7" }, + { 6, 0, "Windows Vista" }, + { 5, 2, "Windows Server 2003" }, + { 5, 1, "Windows XP" }, + { 5, 0, "Windows 2000" }, + /* { 4, 0, "Windows NT 4.0" }, */ + { 4, 90, "Windows Me" }, + { 4, 10, "Windows 98" }, + /* { 4, 0, "Windows 95" } */ + { 3, 51, "Windows NT 3.51" }, + { 0, 0, NULL } + }; + memset(&info, 0, sizeof(info)); + info.dwOSVersionInfoSize = sizeof(info); + if (! GetVersionEx((LPOSVERSIONINFO)&info)) { + strlcpy(uname_result, "Bizarre version of Windows where GetVersionEx" + " doesn't work.", sizeof(uname_result)); + uname_result_is_set = 1; + return uname_result; + } + if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) { + if (info.dwPlatformId == VER_PLATFORM_WIN32_NT) + plat = "Windows NT 4.0"; + else + plat = "Windows 95"; + } else { + for (i=0; win_version_table[i].major>0; ++i) { + if (win_version_table[i].major == info.dwMajorVersion && + win_version_table[i].minor == info.dwMinorVersion) { + plat = win_version_table[i].version; + break; + } + } + } + if (plat) { + strlcpy(uname_result, plat, sizeof(uname_result)); + } else { + if (info.dwMajorVersion > 6 || + (info.dwMajorVersion==6 && info.dwMinorVersion>2)) + tor_snprintf(uname_result, sizeof(uname_result), + "Very recent version of Windows [major=%d,minor=%d]", + (int)info.dwMajorVersion,(int)info.dwMinorVersion); + else + tor_snprintf(uname_result, sizeof(uname_result), + "Unrecognized version of Windows [major=%d,minor=%d]", + (int)info.dwMajorVersion,(int)info.dwMinorVersion); + } +#ifdef VER_NT_SERVER + if (info.wProductType == VER_NT_SERVER || + info.wProductType == VER_NT_DOMAIN_CONTROLLER) { + strlcat(uname_result, " [server]", sizeof(uname_result)); + } +#endif /* defined(VER_NT_SERVER) */ +#else /* !(defined(_WIN32)) */ + /* LCOV_EXCL_START -- can't provoke uname failure */ + strlcpy(uname_result, "Unknown platform", sizeof(uname_result)); + /* LCOV_EXCL_STOP */ +#endif /* defined(_WIN32) */ + } + uname_result_is_set = 1; + } + return uname_result; +} diff --git a/src/lib/osinfo/uname.h b/src/lib/osinfo/uname.h new file mode 100644 index 0000000000..1f0b78385f --- /dev/null +++ b/src/lib/osinfo/uname.h @@ -0,0 +1,9 @@ + +#ifndef HAVE_TOR_UNAME_H +#define HAVE_TOR_UNAME_H + +#include "lib/testsupport/testsupport.h" + +MOCK_DECL(const char *, get_uname,(void)); + +#endif diff --git a/src/lib/process/.may_include b/src/lib/process/.may_include new file mode 100644 index 0000000000..c02e7fddb2 --- /dev/null +++ b/src/lib/process/.may_include @@ -0,0 +1,16 @@ +orconfig.h + +lib/cc/*.h +lib/container/*.h +lib/ctime/*.h +lib/err/*.h +lib/fs/*.h +lib/log/*.h +lib/malloc/*.h +lib/net/*.h +lib/process/*.h +lib/string/*.h +lib/testsupport/*.h +lib/thread/*.h + +ht.h
\ No newline at end of file diff --git a/src/lib/process/daemon.c b/src/lib/process/daemon.c new file mode 100644 index 0000000000..edffb04683 --- /dev/null +++ b/src/lib/process/daemon.c @@ -0,0 +1,159 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/process/daemon.h" + +#ifndef _WIN32 + +#include "lib/fs/files.h" +#include "lib/log/torlog.h" +#include "lib/thread/threads.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +/* Based on code contributed by christian grothoff */ +/** True iff we've called start_daemon(). */ +static int start_daemon_called = 0; +/** True iff we've called finish_daemon(). */ +static int finish_daemon_called = 0; +/** Socketpair used to communicate between parent and child process while + * daemonizing. */ +static int daemon_filedes[2]; +/** Start putting the process into daemon mode: fork and drop all resources + * except standard fds. The parent process never returns, but stays around + * until finish_daemon is called. (Note: it's safe to call this more + * than once: calls after the first are ignored.) + */ +void +start_daemon(void) +{ + pid_t pid; + + if (start_daemon_called) + return; + start_daemon_called = 1; + + if (pipe(daemon_filedes)) { + /* LCOV_EXCL_START */ + log_err(LD_GENERAL,"pipe failed; exiting. Error was %s", strerror(errno)); + exit(1); // exit ok: during daemonize, pipe failed. + /* LCOV_EXCL_STOP */ + } + pid = fork(); + if (pid < 0) { + /* LCOV_EXCL_START */ + log_err(LD_GENERAL,"fork failed. Exiting."); + exit(1); // exit ok: during daemonize, fork failed + /* LCOV_EXCL_STOP */ + } + if (pid) { /* Parent */ + int ok; + char c; + + close(daemon_filedes[1]); /* we only read */ + ok = -1; + while (0 < read(daemon_filedes[0], &c, sizeof(char))) { + if (c == '.') + ok = 1; + } + fflush(stdout); + if (ok == 1) + exit(0); // exit ok: during daemonize, daemonizing. + else + exit(1); /* child reported error. exit ok: daemonize failed. */ + } else { /* Child */ + close(daemon_filedes[0]); /* we only write */ + + (void) setsid(); /* Detach from controlling terminal */ + /* + * Fork one more time, so the parent (the session group leader) can exit. + * This means that we, as a non-session group leader, can never regain a + * controlling terminal. This part is recommended by Stevens's + * _Advanced Programming in the Unix Environment_. + */ + if (fork() != 0) { + exit(0); // exit ok: during daemonize, fork failed (2) + } + set_main_thread(); /* We are now the main thread. */ + + return; + } +} + +/** Finish putting the process into daemon mode: drop standard fds, and tell + * the parent process to exit. (Note: it's safe to call this more than once: + * calls after the first are ignored. Calls start_daemon first if it hasn't + * been called already.) + */ +void +finish_daemon(const char *desired_cwd) +{ + int nullfd; + char c = '.'; + if (finish_daemon_called) + return; + if (!start_daemon_called) + start_daemon(); + finish_daemon_called = 1; + + if (!desired_cwd) + desired_cwd = "/"; + /* Don't hold the wrong FS mounted */ + if (chdir(desired_cwd) < 0) { + log_err(LD_GENERAL,"chdir to \"%s\" failed. Exiting.",desired_cwd); + exit(1); // exit ok: during daemonize, chdir failed. + } + + nullfd = tor_open_cloexec("/dev/null", O_RDWR, 0); + if (nullfd < 0) { + /* LCOV_EXCL_START */ + log_err(LD_GENERAL,"/dev/null can't be opened. Exiting."); + exit(1); // exit ok: during daemonize, couldn't open /dev/null + /* LCOV_EXCL_STOP */ + } + /* close fds linking to invoking terminal, but + * close usual incoming fds, but redirect them somewhere + * useful so the fds don't get reallocated elsewhere. + */ + if (dup2(nullfd,0) < 0 || + dup2(nullfd,1) < 0 || + dup2(nullfd,2) < 0) { + /* LCOV_EXCL_START */ + log_err(LD_GENERAL,"dup2 failed. Exiting."); + exit(1); // exit ok: during daemonize, dup2 failed. + /* LCOV_EXCL_STOP */ + } + if (nullfd > 2) + close(nullfd); + /* signal success */ + if (write(daemon_filedes[1], &c, sizeof(char)) != sizeof(char)) { + log_err(LD_GENERAL,"write failed. Exiting."); + } + close(daemon_filedes[1]); +} +#else /* !(!defined(_WIN32)) */ +/* defined(_WIN32) */ +void +start_daemon(void) +{ +} +void +finish_daemon(const char *cp) +{ + (void)cp; +} +#endif /* !defined(_WIN32) */ diff --git a/src/lib/process/daemon.h b/src/lib/process/daemon.h new file mode 100644 index 0000000000..48a65b22e6 --- /dev/null +++ b/src/lib/process/daemon.h @@ -0,0 +1,12 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_DAEMON_H +#define TOR_DAEMON_H + +void start_daemon(void); +void finish_daemon(const char *desired_cwd); + +#endif diff --git a/src/lib/process/env.c b/src/lib/process/env.c new file mode 100644 index 0000000000..731f609ac1 --- /dev/null +++ b/src/lib/process/env.c @@ -0,0 +1,219 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/process/env.h" + +#include "lib/malloc/util_malloc.h" +#include "lib/ctime/di_ops.h" +#include "lib/container/smartlist.h" +#include "lib/log/util_bug.h" +#include "lib/log/torlog.h" +#include "lib/malloc/util_malloc.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_CRT_EXTERNS_H +/* For _NSGetEnviron on macOS */ +#include <crt_externs.h> +#endif + +#ifndef HAVE__NSGETENVIRON +#ifndef HAVE_EXTERN_ENVIRON_DECLARED +/* Some platforms declare environ under some circumstances, others don't. */ +#ifndef RUNNING_DOXYGEN +extern char **environ; +#endif +#endif /* !defined(HAVE_EXTERN_ENVIRON_DECLARED) */ +#endif /* !defined(HAVE__NSGETENVIRON) */ + +/** Return the current environment. This is a portable replacement for + * 'environ'. */ +char ** +get_environment(void) +{ +#ifdef HAVE__NSGETENVIRON + /* This is for compatibility between OSX versions. Otherwise (for example) + * when we do a mostly-static build on OSX 10.7, the resulting binary won't + * work on OSX 10.6. */ + return *_NSGetEnviron(); +#else /* !(defined(HAVE__NSGETENVIRON)) */ + return environ; +#endif /* defined(HAVE__NSGETENVIRON) */ +} + +/** Helper: return the number of characters in <b>s</b> preceding the first + * occurrence of <b>ch</b>. If <b>ch</b> does not occur in <b>s</b>, return + * the length of <b>s</b>. Should be equivalent to strspn(s, "ch"). */ +static inline size_t +str_num_before(const char *s, char ch) +{ + const char *cp = strchr(s, ch); + if (cp) + return cp - s; + else + return strlen(s); +} + +/** Return non-zero iff getenv would consider <b>s1</b> and <b>s2</b> + * to have the same name as strings in a process's environment. */ +int +environment_variable_names_equal(const char *s1, const char *s2) +{ + size_t s1_name_len = str_num_before(s1, '='); + size_t s2_name_len = str_num_before(s2, '='); + + return (s1_name_len == s2_name_len && + tor_memeq(s1, s2, s1_name_len)); +} + +/** Free <b>env</b> (assuming it was produced by + * process_environment_make). */ +void +process_environment_free_(process_environment_t *env) +{ + if (env == NULL) return; + + /* As both an optimization hack to reduce consing on Unixoid systems + * and a nice way to ensure that some otherwise-Windows-specific + * code will always get tested before changes to it get merged, the + * strings which env->unixoid_environment_block points to are packed + * into env->windows_environment_block. */ + tor_free(env->unixoid_environment_block); + tor_free(env->windows_environment_block); + + tor_free(env); +} + +/** Make a process_environment_t containing the environment variables + * specified in <b>env_vars</b> (as C strings of the form + * "NAME=VALUE"). */ +process_environment_t * +process_environment_make(struct smartlist_t *env_vars) +{ + process_environment_t *env = tor_malloc_zero(sizeof(process_environment_t)); + int n_env_vars = smartlist_len(env_vars); + int i; + size_t total_env_length; + smartlist_t *env_vars_sorted; + + tor_assert(n_env_vars + 1 != 0); + env->unixoid_environment_block = tor_calloc(n_env_vars + 1, sizeof(char *)); + /* env->unixoid_environment_block is already NULL-terminated, + * because we assume that NULL == 0 (and check that during compilation). */ + + total_env_length = 1; /* terminating NUL of terminating empty string */ + for (i = 0; i < n_env_vars; ++i) { + const char *s = smartlist_get(env_vars, (int)i); + size_t slen = strlen(s); + + tor_assert(slen + 1 != 0); + tor_assert(slen + 1 < SIZE_MAX - total_env_length); + total_env_length += slen + 1; + } + + env->windows_environment_block = tor_malloc_zero(total_env_length); + /* env->windows_environment_block is already + * (NUL-terminated-empty-string)-terminated. */ + + /* Some versions of Windows supposedly require that environment + * blocks be sorted. Or maybe some Windows programs (or their + * runtime libraries) fail to look up strings in non-sorted + * environment blocks. + * + * Also, sorting strings makes it easy to find duplicate environment + * variables and environment-variable strings without an '=' on all + * OSes, and they can cause badness. Let's complain about those. */ + env_vars_sorted = smartlist_new(); + smartlist_add_all(env_vars_sorted, env_vars); + smartlist_sort_strings(env_vars_sorted); + + /* Now copy the strings into the environment blocks. */ + { + char *cp = env->windows_environment_block; + const char *prev_env_var = NULL; + + for (i = 0; i < n_env_vars; ++i) { + const char *s = smartlist_get(env_vars_sorted, (int)i); + size_t slen = strlen(s); + size_t s_name_len = str_num_before(s, '='); + + if (s_name_len == slen) { + log_warn(LD_GENERAL, + "Preparing an environment containing a variable " + "without a value: %s", + s); + } + if (prev_env_var != NULL && + environment_variable_names_equal(s, prev_env_var)) { + log_warn(LD_GENERAL, + "Preparing an environment containing two variables " + "with the same name: %s and %s", + prev_env_var, s); + } + + prev_env_var = s; + + /* Actually copy the string into the environment. */ + memcpy(cp, s, slen+1); + env->unixoid_environment_block[i] = cp; + cp += slen+1; + } + + tor_assert(cp == env->windows_environment_block + total_env_length - 1); + } + + smartlist_free(env_vars_sorted); + + return env; +} + +/** Return a newly allocated smartlist containing every variable in + * this process's environment, as a NUL-terminated string of the form + * "NAME=VALUE". Note that on some/many/most/all OSes, the parent + * process can put strings not of that form in our environment; + * callers should try to not get crashed by that. + * + * The returned strings are heap-allocated, and must be freed by the + * caller. */ +struct smartlist_t * +get_current_process_environment_variables(void) +{ + smartlist_t *sl = smartlist_new(); + + char **environ_tmp; /* Not const char ** ? Really? */ + for (environ_tmp = get_environment(); *environ_tmp; ++environ_tmp) { + smartlist_add_strdup(sl, *environ_tmp); + } + + return sl; +} + +/** For each string s in <b>env_vars</b> such that + * environment_variable_names_equal(s, <b>new_var</b>), remove it; if + * <b>free_p</b> is non-zero, call <b>free_old</b>(s). If + * <b>new_var</b> contains '=', insert it into <b>env_vars</b>. */ +void +set_environment_variable_in_smartlist(struct smartlist_t *env_vars, + const char *new_var, + void (*free_old)(void*), + int free_p) +{ + SMARTLIST_FOREACH_BEGIN(env_vars, const char *, s) { + if (environment_variable_names_equal(s, new_var)) { + SMARTLIST_DEL_CURRENT(env_vars, s); + if (free_p) { + free_old((void *)s); + } + } + } SMARTLIST_FOREACH_END(s); + + if (strchr(new_var, '=') != NULL) { + smartlist_add(env_vars, (void *)new_var); + } +} diff --git a/src/lib/process/env.h b/src/lib/process/env.h new file mode 100644 index 0000000000..f22599355d --- /dev/null +++ b/src/lib/process/env.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_ENV_H +#define TOR_ENV_H + +char **get_environment(void); + +struct smartlist_t; + +int environment_variable_names_equal(const char *s1, const char *s2); + +/* DOCDOC process_environment_t */ +typedef struct process_environment_t { + /** A pointer to a sorted empty-string-terminated sequence of + * NUL-terminated strings of the form "NAME=VALUE". */ + char *windows_environment_block; + /** A pointer to a NULL-terminated array of pointers to + * NUL-terminated strings of the form "NAME=VALUE". */ + char **unixoid_environment_block; +} process_environment_t; + +process_environment_t *process_environment_make(struct smartlist_t *env_vars); +void process_environment_free_(process_environment_t *env); +#define process_environment_free(env) \ + FREE_AND_NULL(process_environment_t, process_environment_free_, (env)) + +struct smartlist_t *get_current_process_environment_variables(void); + +void set_environment_variable_in_smartlist(struct smartlist_t *env_vars, + const char *new_var, + void (*free_old)(void*), + int free_p); +#endif diff --git a/src/lib/process/include.am b/src/lib/process/include.am new file mode 100644 index 0000000000..c6cc3a6699 --- /dev/null +++ b/src/lib/process/include.am @@ -0,0 +1,29 @@ + +noinst_LIBRARIES += src/lib/libtor-process.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-process-testing.a +endif + +src_lib_libtor_process_a_SOURCES = \ + src/lib/process/daemon.c \ + src/lib/process/env.c \ + src/lib/process/pidfile.c \ + src/lib/process/restrict.c \ + src/lib/process/setuid.c \ + src/lib/process/subprocess.c \ + src/lib/process/waitpid.c + +src_lib_libtor_process_testing_a_SOURCES = \ + $(src_lib_libtor_process_a_SOURCES) +src_lib_libtor_process_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_process_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/process/daemon.h \ + src/lib/process/env.h \ + src/lib/process/pidfile.h \ + src/lib/process/restrict.h \ + src/lib/process/setuid.h \ + src/lib/process/subprocess.h \ + src/lib/process/waitpid.h diff --git a/src/lib/process/pidfile.c b/src/lib/process/pidfile.c new file mode 100644 index 0000000000..f016f21697 --- /dev/null +++ b/src/lib/process/pidfile.c @@ -0,0 +1,47 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/process/pidfile.h" + +#include "lib/log/torlog.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <errno.h> +#include <stdio.h> +#include <string.h> + +/** Write the current process ID, followed by NL, into <b>filename</b>. + * Return 0 on success, -1 on failure. + */ +int +write_pidfile(const char *filename) +{ + FILE *pidfile; + + if ((pidfile = fopen(filename, "w")) == NULL) { + log_warn(LD_FS, "Unable to open \"%s\" for writing: %s", filename, + strerror(errno)); + return -1; + } else { +#ifdef _WIN32 + int pid = (int)_getpid(); +#else + int pid = (int)getpid(); +#endif + int rv = 0; + if (fprintf(pidfile, "%d\n", pid) < 0) + rv = -1; + if (fclose(pidfile) < 0) + rv = -1; + return rv; + } +} diff --git a/src/lib/process/pidfile.h b/src/lib/process/pidfile.h new file mode 100644 index 0000000000..c85cd1905e --- /dev/null +++ b/src/lib/process/pidfile.h @@ -0,0 +1,11 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_PIDFILE_H +#define TOR_PIDFILE_H + +int write_pidfile(const char *filename); + +#endif diff --git a/src/lib/process/restrict.c b/src/lib/process/restrict.c new file mode 100644 index 0000000000..bb44cc3d15 --- /dev/null +++ b/src/lib/process/restrict.c @@ -0,0 +1,280 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/process/restrict.h" +#include "lib/intmath/cmp.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/net/socket.h" + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +/* We only use the linux prctl for now. There is no Win32 support; this may + * also work on various BSD systems and Mac OS X - send testing feedback! + * + * On recent Gnu/Linux kernels it is possible to create a system-wide policy + * that will prevent non-root processes from attaching to other processes + * unless they are the parent process; thus gdb can attach to programs that + * they execute but they cannot attach to other processes running as the same + * user. The system wide policy may be set with the sysctl + * kernel.yama.ptrace_scope or by inspecting + * /proc/sys/kernel/yama/ptrace_scope and it is 1 by default on Ubuntu 11.04. + * + * This ptrace scope will be ignored on Gnu/Linux for users with + * CAP_SYS_PTRACE and so it is very likely that root will still be able to + * attach to the Tor process. + */ +/** Attempt to disable debugger attachment: return 1 on success, -1 on + * failure, and 0 if we don't know how to try on this platform. */ +int +tor_disable_debugger_attach(void) +{ + int r = -1; + log_debug(LD_CONFIG, + "Attemping to disable debugger attachment to Tor for " + "unprivileged users."); +#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) \ + && defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) +#define TRIED_TO_DISABLE + r = prctl(PR_SET_DUMPABLE, 0); +#elif defined(__APPLE__) && defined(PT_DENY_ATTACH) +#define TRIED_TO_ATTACH + r = ptrace(PT_DENY_ATTACH, 0, 0, 0); +#endif /* defined(__linux__) && defined(HAVE_SYS_PRCTL_H) ... || ... */ + + // XXX: TODO - Mac OS X has dtrace and this may be disabled. + // XXX: TODO - Windows probably has something similar +#ifdef TRIED_TO_DISABLE + if (r == 0) { + log_debug(LD_CONFIG,"Debugger attachment disabled for " + "unprivileged users."); + return 1; + } else { + log_warn(LD_CONFIG, "Unable to disable debugger attaching: %s", + strerror(errno)); + } +#endif /* defined(TRIED_TO_DISABLE) */ +#undef TRIED_TO_DISABLE + return r; +} + +#if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK) +#define HAVE_UNIX_MLOCKALL +#endif + +#ifdef HAVE_UNIX_MLOCKALL +/** Attempt to raise the current and max rlimit to infinity for our process. + * This only needs to be done once and can probably only be done when we have + * not already dropped privileges. + */ +static int +tor_set_max_memlock(void) +{ + /* Future consideration for Windows is probably SetProcessWorkingSetSize + * This is similar to setting the memory rlimit of RLIMIT_MEMLOCK + * http://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx + */ + + struct rlimit limit; + + /* RLIM_INFINITY is -1 on some platforms. */ + limit.rlim_cur = RLIM_INFINITY; + limit.rlim_max = RLIM_INFINITY; + + if (setrlimit(RLIMIT_MEMLOCK, &limit) == -1) { + if (errno == EPERM) { + log_warn(LD_GENERAL, "You appear to lack permissions to change memory " + "limits. Are you root?"); + } + log_warn(LD_GENERAL, "Unable to raise RLIMIT_MEMLOCK: %s", + strerror(errno)); + return -1; + } + + return 0; +} +#endif /* defined(HAVE_UNIX_MLOCKALL) */ + +/** Attempt to lock all current and all future memory pages. + * This should only be called once and while we're privileged. + * Like mlockall() we return 0 when we're successful and -1 when we're not. + * Unlike mlockall() we return 1 if we've already attempted to lock memory. + */ +int +tor_mlockall(void) +{ + static int memory_lock_attempted = 0; + + if (memory_lock_attempted) { + return 1; + } + + memory_lock_attempted = 1; + + /* + * Future consideration for Windows may be VirtualLock + * VirtualLock appears to implement mlock() but not mlockall() + * + * http://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx + */ + +#ifdef HAVE_UNIX_MLOCKALL + if (tor_set_max_memlock() == 0) { + log_debug(LD_GENERAL, "RLIMIT_MEMLOCK is now set to RLIM_INFINITY."); + } + + if (mlockall(MCL_CURRENT|MCL_FUTURE) == 0) { + log_info(LD_GENERAL, "Insecure OS paging is effectively disabled."); + return 0; + } else { + if (errno == ENOSYS) { + /* Apple - it's 2009! I'm looking at you. Grrr. */ + log_notice(LD_GENERAL, "It appears that mlockall() is not available on " + "your platform."); + } else if (errno == EPERM) { + log_notice(LD_GENERAL, "It appears that you lack the permissions to " + "lock memory. Are you root?"); + } + log_notice(LD_GENERAL, "Unable to lock all current and future memory " + "pages: %s", strerror(errno)); + return -1; + } +#else /* !(defined(HAVE_UNIX_MLOCKALL)) */ + log_warn(LD_GENERAL, "Unable to lock memory pages. mlockall() unsupported?"); + return -1; +#endif /* defined(HAVE_UNIX_MLOCKALL) */ +} + +/** Number of extra file descriptors to keep in reserve beyond those that we + * tell Tor it's allowed to use. */ +#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */ + +/** Learn the maximum allowed number of file descriptors, and tell the + * system we want to use up to that number. (Some systems have a low soft + * limit, and let us set it higher.) We compute this by finding the largest + * number that we can use. + * + * If the limit is below the reserved file descriptor value (ULIMIT_BUFFER), + * return -1 and <b>max_out</b> is untouched. + * + * If we can't find a number greater than or equal to <b>limit</b>, then we + * fail by returning -1 and <b>max_out</b> is untouched. + * + * If we are unable to set the limit value because of setrlimit() failing, + * return 0 and <b>max_out</b> is set to the current maximum value returned + * by getrlimit(). + * + * Otherwise, return 0 and store the maximum we found inside <b>max_out</b> + * and set <b>max_sockets</b> with that value as well.*/ +int +set_max_file_descriptors(rlim_t limit, int *max_out) +{ + if (limit < ULIMIT_BUFFER) { + log_warn(LD_CONFIG, + "ConnLimit must be at least %d. Failing.", ULIMIT_BUFFER); + return -1; + } + + /* Define some maximum connections values for systems where we cannot + * automatically determine a limit. Re Cygwin, see + * http://archives.seul.org/or/talk/Aug-2006/msg00210.html + * For an iPhone, 9999 should work. For Windows and all other unknown + * systems we use 15000 as the default. */ +#ifndef HAVE_GETRLIMIT +#if defined(CYGWIN) || defined(__CYGWIN__) + const char *platform = "Cygwin"; + const unsigned long MAX_CONNECTIONS = 3200; +#elif defined(_WIN32) + const char *platform = "Windows"; + const unsigned long MAX_CONNECTIONS = 15000; +#else + const char *platform = "unknown platforms with no getrlimit()"; + const unsigned long MAX_CONNECTIONS = 15000; +#endif /* defined(CYGWIN) || defined(__CYGWIN__) || ... */ + log_fn(LOG_INFO, LD_NET, + "This platform is missing getrlimit(). Proceeding."); + if (limit > MAX_CONNECTIONS) { + log_warn(LD_CONFIG, + "We do not support more than %lu file descriptors " + "on %s. Tried to raise to %lu.", + (unsigned long)MAX_CONNECTIONS, platform, (unsigned long)limit); + return -1; + } + limit = MAX_CONNECTIONS; +#else /* !(!defined(HAVE_GETRLIMIT)) */ + struct rlimit rlim; + + if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { + log_warn(LD_NET, "Could not get maximum number of file descriptors: %s", + strerror(errno)); + return -1; + } + if (rlim.rlim_max < limit) { + log_warn(LD_CONFIG,"We need %lu file descriptors available, and we're " + "limited to %lu. Please change your ulimit -n.", + (unsigned long)limit, (unsigned long)rlim.rlim_max); + return -1; + } + + if (rlim.rlim_max > rlim.rlim_cur) { + log_info(LD_NET,"Raising max file descriptors from %lu to %lu.", + (unsigned long)rlim.rlim_cur, (unsigned long)rlim.rlim_max); + } + /* Set the current limit value so if the attempt to set the limit to the + * max fails at least we'll have a valid value of maximum sockets. */ + *max_out = (int)rlim.rlim_cur - ULIMIT_BUFFER; + set_max_sockets(*max_out); + rlim.rlim_cur = rlim.rlim_max; + + if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { + int couldnt_set = 1; + const int setrlimit_errno = errno; +#ifdef OPEN_MAX + uint64_t try_limit = OPEN_MAX - ULIMIT_BUFFER; + if (errno == EINVAL && try_limit < (uint64_t) rlim.rlim_cur) { + /* On some platforms, OPEN_MAX is the real limit, and getrlimit() is + * full of nasty lies. I'm looking at you, OSX 10.5.... */ + rlim.rlim_cur = MIN((rlim_t) try_limit, rlim.rlim_cur); + if (setrlimit(RLIMIT_NOFILE, &rlim) == 0) { + if (rlim.rlim_cur < (rlim_t)limit) { + log_warn(LD_CONFIG, "We are limited to %lu file descriptors by " + "OPEN_MAX (%lu), and ConnLimit is %lu. Changing " + "ConnLimit; sorry.", + (unsigned long)try_limit, (unsigned long)OPEN_MAX, + (unsigned long)limit); + } else { + log_info(LD_CONFIG, "Dropped connection limit to %lu based on " + "OPEN_MAX (%lu); Apparently, %lu was too high and rlimit " + "lied to us.", + (unsigned long)try_limit, (unsigned long)OPEN_MAX, + (unsigned long)rlim.rlim_max); + } + couldnt_set = 0; + } + } +#endif /* defined(OPEN_MAX) */ + if (couldnt_set) { + log_warn(LD_CONFIG,"Couldn't set maximum number of file descriptors: %s", + strerror(setrlimit_errno)); + } + } + /* leave some overhead for logs, etc, */ + limit = rlim.rlim_cur; +#endif /* !defined(HAVE_GETRLIMIT) */ + + if (limit > INT_MAX) + limit = INT_MAX; + tor_assert(max_out); + *max_out = (int)limit - ULIMIT_BUFFER; + set_max_sockets(*max_out); + + return 0; +} diff --git a/src/lib/process/restrict.h b/src/lib/process/restrict.h new file mode 100644 index 0000000000..c7f76f8233 --- /dev/null +++ b/src/lib/process/restrict.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file waitpid.h + * \brief Headers for waitpid.c + **/ + +#ifndef TOR_RESTRICT_H +#define TOR_RESTRICT_H + +#include "orconfig.h" +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif + +int tor_disable_debugger_attach(void); +int tor_mlockall(void); + +#if !defined(HAVE_RLIM_T) +typedef unsigned long rlim_t; +#endif +int set_max_file_descriptors(rlim_t limit, int *max_out); + +#endif /* !defined(TOR_RESTRICT_H) */ diff --git a/src/lib/process/setuid.c b/src/lib/process/setuid.c new file mode 100644 index 0000000000..fa1cdc0f3f --- /dev/null +++ b/src/lib/process/setuid.c @@ -0,0 +1,381 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/process/setuid.h" + +#if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_CAP_SET_PROC) +#define HAVE_LINUX_CAPABILITIES +#endif + +#include "lib/container/smartlist.h" +#include "lib/fs/userdb.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_GRP_H +#include <grp.h> +#endif +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif +#ifdef HAVE_SYS_CAPABILITY_H +#include <sys/capability.h> +#endif +#ifdef HAVE_SYS_PRCTL_H +#include <sys/prctl.h> +#endif + +#include <errno.h> +#include <string.h> + +#ifndef _WIN32 +/** Log details of current user and group credentials. Return 0 on + * success. Logs and return -1 on failure. + */ +static int +log_credential_status(void) +{ +/** Log level to use when describing non-error UID/GID status. */ +#define CREDENTIAL_LOG_LEVEL LOG_INFO + /* Real, effective and saved UIDs */ + uid_t ruid, euid, suid; + /* Read, effective and saved GIDs */ + gid_t rgid, egid, sgid; + /* Supplementary groups */ + gid_t *sup_gids = NULL; + int sup_gids_size; + /* Number of supplementary groups */ + int ngids; + + /* log UIDs */ +#ifdef HAVE_GETRESUID + if (getresuid(&ruid, &euid, &suid) != 0 ) { + log_warn(LD_GENERAL, "Error getting changed UIDs: %s", strerror(errno)); + return -1; + } else { + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, + "UID is %u (real), %u (effective), %u (saved)", + (unsigned)ruid, (unsigned)euid, (unsigned)suid); + } +#else /* !(defined(HAVE_GETRESUID)) */ + /* getresuid is not present on MacOS X, so we can't get the saved (E)UID */ + ruid = getuid(); + euid = geteuid(); + (void)suid; + + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, + "UID is %u (real), %u (effective), unknown (saved)", + (unsigned)ruid, (unsigned)euid); +#endif /* defined(HAVE_GETRESUID) */ + + /* log GIDs */ +#ifdef HAVE_GETRESGID + if (getresgid(&rgid, &egid, &sgid) != 0 ) { + log_warn(LD_GENERAL, "Error getting changed GIDs: %s", strerror(errno)); + return -1; + } else { + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, + "GID is %u (real), %u (effective), %u (saved)", + (unsigned)rgid, (unsigned)egid, (unsigned)sgid); + } +#else /* !(defined(HAVE_GETRESGID)) */ + /* getresgid is not present on MacOS X, so we can't get the saved (E)GID */ + rgid = getgid(); + egid = getegid(); + (void)sgid; + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, + "GID is %u (real), %u (effective), unknown (saved)", + (unsigned)rgid, (unsigned)egid); +#endif /* defined(HAVE_GETRESGID) */ + + /* log supplementary groups */ + sup_gids_size = 64; + sup_gids = tor_calloc(64, sizeof(gid_t)); + while ((ngids = getgroups(sup_gids_size, sup_gids)) < 0 && + errno == EINVAL && + sup_gids_size < NGROUPS_MAX) { + sup_gids_size *= 2; + sup_gids = tor_reallocarray(sup_gids, sizeof(gid_t), sup_gids_size); + } + + if (ngids < 0) { + log_warn(LD_GENERAL, "Error getting supplementary GIDs: %s", + strerror(errno)); + tor_free(sup_gids); + return -1; + } else { + int i, retval = 0; + char *s = NULL; + smartlist_t *elts = smartlist_new(); + + for (i = 0; i<ngids; i++) { + smartlist_add_asprintf(elts, "%u", (unsigned)sup_gids[i]); + } + + s = smartlist_join_strings(elts, " ", 0, NULL); + + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Supplementary groups are: %s",s); + + tor_free(s); + SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); + smartlist_free(elts); + tor_free(sup_gids); + + return retval; + } + + return 0; +} +#endif /* !defined(_WIN32) */ + +/** Return true iff we were compiled with capability support, and capabilities + * seem to work. **/ +int +have_capability_support(void) +{ +#ifdef HAVE_LINUX_CAPABILITIES + cap_t caps = cap_get_proc(); + if (caps == NULL) + return 0; + cap_free(caps); + return 1; +#else /* !(defined(HAVE_LINUX_CAPABILITIES)) */ + return 0; +#endif /* defined(HAVE_LINUX_CAPABILITIES) */ +} + +#ifdef HAVE_LINUX_CAPABILITIES +/** Helper. Drop all capabilities but a small set, and set PR_KEEPCAPS as + * appropriate. + * + * If pre_setuid, retain only CAP_NET_BIND_SERVICE, CAP_SETUID, and + * CAP_SETGID, and use PR_KEEPCAPS to ensure that capabilities persist across + * setuid(). + * + * If not pre_setuid, retain only CAP_NET_BIND_SERVICE, and disable + * PR_KEEPCAPS. + * + * Return 0 on success, and -1 on failure. + */ +static int +drop_capabilities(int pre_setuid) +{ + /* We keep these three capabilities, and these only, as we setuid. + * After we setuid, we drop all but the first. */ + const cap_value_t caplist[] = { + CAP_NET_BIND_SERVICE, CAP_SETUID, CAP_SETGID + }; + const char *where = pre_setuid ? "pre-setuid" : "post-setuid"; + const int n_effective = pre_setuid ? 3 : 1; + const int n_permitted = pre_setuid ? 3 : 1; + const int n_inheritable = 1; + const int keepcaps = pre_setuid ? 1 : 0; + + /* Sets whether we keep capabilities across a setuid. */ + if (prctl(PR_SET_KEEPCAPS, keepcaps) < 0) { + log_warn(LD_CONFIG, "Unable to call prctl() %s: %s", + where, strerror(errno)); + return -1; + } + + cap_t caps = cap_get_proc(); + if (!caps) { + log_warn(LD_CONFIG, "Unable to call cap_get_proc() %s: %s", + where, strerror(errno)); + return -1; + } + cap_clear(caps); + + cap_set_flag(caps, CAP_EFFECTIVE, n_effective, caplist, CAP_SET); + cap_set_flag(caps, CAP_PERMITTED, n_permitted, caplist, CAP_SET); + cap_set_flag(caps, CAP_INHERITABLE, n_inheritable, caplist, CAP_SET); + + int r = cap_set_proc(caps); + cap_free(caps); + if (r < 0) { + log_warn(LD_CONFIG, "No permission to set capabilities %s: %s", + where, strerror(errno)); + return -1; + } + + return 0; +} +#endif /* defined(HAVE_LINUX_CAPABILITIES) */ + +/** Call setuid and setgid to run as <b>user</b> and switch to their + * primary group. Return 0 on success. On failure, log and return -1. + * + * If SWITCH_ID_KEEP_BINDLOW is set in 'flags', try to use the capability + * system to retain the abilitity to bind low ports. + * + * If SWITCH_ID_WARN_IF_NO_CAPS is set in flags, also warn if we have + * don't have capability support. + */ +int +switch_id(const char *user, const unsigned flags) +{ +#ifndef _WIN32 + const struct passwd *pw = NULL; + uid_t old_uid; + gid_t old_gid; + static int have_already_switched_id = 0; + const int keep_bindlow = !!(flags & SWITCH_ID_KEEP_BINDLOW); + const int warn_if_no_caps = !!(flags & SWITCH_ID_WARN_IF_NO_CAPS); + + tor_assert(user); + + if (have_already_switched_id) + return 0; + + /* Log the initial credential state */ + if (log_credential_status()) + return -1; + + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Changing user and groups"); + + /* Get old UID/GID to check if we changed correctly */ + old_uid = getuid(); + old_gid = getgid(); + + /* Lookup the user and group information, if we have a problem, bail out. */ + pw = tor_getpwnam(user); + if (pw == NULL) { + log_warn(LD_CONFIG, "Error setting configured user: %s not found", user); + return -1; + } + +#ifdef HAVE_LINUX_CAPABILITIES + (void) warn_if_no_caps; + if (keep_bindlow) { + if (drop_capabilities(1)) + return -1; + } +#else /* !(defined(HAVE_LINUX_CAPABILITIES)) */ + (void) keep_bindlow; + if (warn_if_no_caps) { + log_warn(LD_CONFIG, "KeepBindCapabilities set, but no capability support " + "on this system."); + } +#endif /* defined(HAVE_LINUX_CAPABILITIES) */ + + /* Properly switch egid,gid,euid,uid here or bail out */ + if (setgroups(1, &pw->pw_gid)) { + log_warn(LD_GENERAL, "Error setting groups to gid %d: \"%s\".", + (int)pw->pw_gid, strerror(errno)); + if (old_uid == pw->pw_uid) { + log_warn(LD_GENERAL, "Tor is already running as %s. You do not need " + "the \"User\" option if you are already running as the user " + "you want to be. (If you did not set the User option in your " + "torrc, check whether it was specified on the command line " + "by a startup script.)", user); + } else { + log_warn(LD_GENERAL, "If you set the \"User\" option, you must start Tor" + " as root."); + } + return -1; + } + + if (setegid(pw->pw_gid)) { + log_warn(LD_GENERAL, "Error setting egid to %d: %s", + (int)pw->pw_gid, strerror(errno)); + return -1; + } + + if (setgid(pw->pw_gid)) { + log_warn(LD_GENERAL, "Error setting gid to %d: %s", + (int)pw->pw_gid, strerror(errno)); + return -1; + } + + if (setuid(pw->pw_uid)) { + log_warn(LD_GENERAL, "Error setting configured uid to %s (%d): %s", + user, (int)pw->pw_uid, strerror(errno)); + return -1; + } + + if (seteuid(pw->pw_uid)) { + log_warn(LD_GENERAL, "Error setting configured euid to %s (%d): %s", + user, (int)pw->pw_uid, strerror(errno)); + return -1; + } + + /* This is how OpenBSD rolls: + if (setgroups(1, &pw->pw_gid) || setegid(pw->pw_gid) || + setgid(pw->pw_gid) || setuid(pw->pw_uid) || seteuid(pw->pw_uid)) { + setgid(pw->pw_gid) || seteuid(pw->pw_uid) || setuid(pw->pw_uid)) { + log_warn(LD_GENERAL, "Error setting configured UID/GID: %s", + strerror(errno)); + return -1; + } + */ + + /* We've properly switched egid, gid, euid, uid, and supplementary groups if + * we're here. */ +#ifdef HAVE_LINUX_CAPABILITIES + if (keep_bindlow) { + if (drop_capabilities(0)) + return -1; + } +#endif /* defined(HAVE_LINUX_CAPABILITIES) */ + +#if !defined(CYGWIN) && !defined(__CYGWIN__) + /* If we tried to drop privilege to a group/user other than root, attempt to + * restore root (E)(U|G)ID, and abort if the operation succeeds */ + + /* Only check for privilege dropping if we were asked to be non-root */ + if (pw->pw_uid) { + /* Try changing GID/EGID */ + if (pw->pw_gid != old_gid && + (setgid(old_gid) != -1 || setegid(old_gid) != -1)) { + log_warn(LD_GENERAL, "Was able to restore group credentials even after " + "switching GID: this means that the setgid code didn't work."); + return -1; + } + + /* Try changing UID/EUID */ + if (pw->pw_uid != old_uid && + (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) { + log_warn(LD_GENERAL, "Was able to restore user credentials even after " + "switching UID: this means that the setuid code didn't work."); + return -1; + } + } +#endif /* !defined(CYGWIN) && !defined(__CYGWIN__) */ + + /* Check what really happened */ + if (log_credential_status()) { + return -1; + } + + have_already_switched_id = 1; /* mark success so we never try again */ + +#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && \ + defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) + if (pw->pw_uid) { + /* Re-enable core dumps if we're not running as root. */ + log_info(LD_CONFIG, "Re-enabling coredumps"); + if (prctl(PR_SET_DUMPABLE, 1)) { + log_warn(LD_CONFIG, "Unable to re-enable coredumps: %s",strerror(errno)); + } + } +#endif /* defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && ... */ + return 0; + +#else /* !(!defined(_WIN32)) */ + (void)user; + (void)flags; + + log_warn(LD_CONFIG, "Switching users is unsupported on your OS."); + return -1; +#endif /* !defined(_WIN32) */ +} diff --git a/src/lib/process/setuid.h b/src/lib/process/setuid.h new file mode 100644 index 0000000000..61aeefe1b7 --- /dev/null +++ b/src/lib/process/setuid.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SETUID_H +#define TOR_SETUID_H + +int have_capability_support(void); + +/** Flag for switch_id; see switch_id() for documentation */ +#define SWITCH_ID_KEEP_BINDLOW (1<<0) +/** Flag for switch_id; see switch_id() for documentation */ +#define SWITCH_ID_WARN_IF_NO_CAPS (1<<1) +int switch_id(const char *user, unsigned flags); + +#endif diff --git a/src/lib/process/subprocess.c b/src/lib/process/subprocess.c new file mode 100644 index 0000000000..516494d105 --- /dev/null +++ b/src/lib/process/subprocess.c @@ -0,0 +1,1231 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define SUBPROCESS_PRIVATE +#include "lib/process/subprocess.h" + +#include "lib/container/smartlist.h" +#include "lib/err/torerr.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/log/win32err.h" +#include "lib/malloc/util_malloc.h" +#include "lib/process/env.h" +#include "lib/process/waitpid.h" +#include "lib/string/compat_ctype.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_PRCTL_H +#include <sys/prctl.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +#include <errno.h> +#include <string.h> + +/** Format a single argument for being put on a Windows command line. + * Returns a newly allocated string */ +static char * +format_win_cmdline_argument(const char *arg) +{ + char *formatted_arg; + char need_quotes; + const char *c; + int i; + int bs_counter = 0; + /* Backslash we can point to when one is inserted into the string */ + const char backslash = '\\'; + + /* Smartlist of *char */ + smartlist_t *arg_chars; + arg_chars = smartlist_new(); + + /* Quote string if it contains whitespace or is empty */ + need_quotes = (strchr(arg, ' ') || strchr(arg, '\t') || '\0' == arg[0]); + + /* Build up smartlist of *chars */ + for (c=arg; *c != '\0'; c++) { + if ('"' == *c) { + /* Double up backslashes preceding a quote */ + for (i=0; i<(bs_counter*2); i++) + smartlist_add(arg_chars, (void*)&backslash); + bs_counter = 0; + /* Escape the quote */ + smartlist_add(arg_chars, (void*)&backslash); + smartlist_add(arg_chars, (void*)c); + } else if ('\\' == *c) { + /* Count backslashes until we know whether to double up */ + bs_counter++; + } else { + /* Don't double up slashes preceding a non-quote */ + for (i=0; i<bs_counter; i++) + smartlist_add(arg_chars, (void*)&backslash); + bs_counter = 0; + smartlist_add(arg_chars, (void*)c); + } + } + /* Don't double up trailing backslashes */ + for (i=0; i<bs_counter; i++) + smartlist_add(arg_chars, (void*)&backslash); + + /* Allocate space for argument, quotes (if needed), and terminator */ + const size_t formatted_arg_len = smartlist_len(arg_chars) + + (need_quotes ? 2 : 0) + 1; + formatted_arg = tor_malloc_zero(formatted_arg_len); + + /* Add leading quote */ + i=0; + if (need_quotes) + formatted_arg[i++] = '"'; + + /* Add characters */ + SMARTLIST_FOREACH(arg_chars, char*, ch, + { + formatted_arg[i++] = *ch; + }); + + /* Add trailing quote */ + if (need_quotes) + formatted_arg[i++] = '"'; + formatted_arg[i] = '\0'; + + smartlist_free(arg_chars); + return formatted_arg; +} + +/** Format a command line for use on Windows, which takes the command as a + * string rather than string array. Follows the rules from "Parsing C++ + * Command-Line Arguments" in MSDN. Algorithm based on list2cmdline in the + * Python subprocess module. Returns a newly allocated string */ +char * +tor_join_win_cmdline(const char *argv[]) +{ + smartlist_t *argv_list; + char *joined_argv; + int i; + + /* Format each argument and put the result in a smartlist */ + argv_list = smartlist_new(); + for (i=0; argv[i] != NULL; i++) { + smartlist_add(argv_list, (void *)format_win_cmdline_argument(argv[i])); + } + + /* Join the arguments with whitespace */ + joined_argv = smartlist_join_strings(argv_list, " ", 0, NULL); + + /* Free the newly allocated arguments, and the smartlist */ + SMARTLIST_FOREACH(argv_list, char *, arg, + { + tor_free(arg); + }); + smartlist_free(argv_list); + + return joined_argv; +} + +#ifndef _WIN32 +/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in + * <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler + * safe. + * + * <b>hex_errno</b> must have at least HEX_ERRNO_SIZE+1 bytes available. + * + * The format of <b>hex_errno</b> is: "CHILD_STATE/ERRNO\n", left-padded + * with spaces. CHILD_STATE indicates where + * in the process of starting the child process did the failure occur (see + * CHILD_STATE_* macros for definition), and SAVED_ERRNO is the value of + * errno when the failure occurred. + * + * On success return the number of characters added to hex_errno, not counting + * the terminating NUL; return -1 on error. + */ +STATIC int +format_helper_exit_status(unsigned char child_state, int saved_errno, + char *hex_errno) +{ + unsigned int unsigned_errno; + int written, left; + char *cur; + size_t i; + int res = -1; + + /* Fill hex_errno with spaces, and a trailing newline (memset may + not be signal handler safe, so we can't use it) */ + for (i = 0; i < (HEX_ERRNO_SIZE - 1); i++) + hex_errno[i] = ' '; + hex_errno[HEX_ERRNO_SIZE - 1] = '\n'; + + /* Convert errno to be unsigned for hex conversion */ + if (saved_errno < 0) { + // Avoid overflow on the cast to unsigned int when result is INT_MIN + // by adding 1 to the signed int negative value, + // then, after it has been negated and cast to unsigned, + // adding the original 1 back (the double-addition is intentional). + // Otherwise, the cast to signed could cause a temporary int + // to equal INT_MAX + 1, which is undefined. + unsigned_errno = ((unsigned int) -(saved_errno + 1)) + 1; + } else { + unsigned_errno = (unsigned int) saved_errno; + } + + /* + * Count how many chars of space we have left, and keep a pointer into the + * current point in the buffer. + */ + left = HEX_ERRNO_SIZE+1; + cur = hex_errno; + + /* Emit child_state */ + written = format_hex_number_sigsafe(child_state, cur, left); + + if (written <= 0) + goto err; + + /* Adjust left and cur */ + left -= written; + cur += written; + if (left <= 0) + goto err; + + /* Now the '/' */ + *cur = '/'; + + /* Adjust left and cur */ + ++cur; + --left; + if (left <= 0) + goto err; + + /* Need minus? */ + if (saved_errno < 0) { + *cur = '-'; + ++cur; + --left; + if (left <= 0) + goto err; + } + + /* Emit unsigned_errno */ + written = format_hex_number_sigsafe(unsigned_errno, cur, left); + + if (written <= 0) + goto err; + + /* Adjust left and cur */ + left -= written; + cur += written; + + /* Check that we have enough space left for a newline and a NUL */ + if (left <= 1) + goto err; + + /* Emit the newline and NUL */ + *cur++ = '\n'; + *cur++ = '\0'; + + res = (int)(cur - hex_errno - 1); + + goto done; + + err: + /* + * In error exit, just write a '\0' in the first char so whatever called + * this at least won't fall off the end. + */ + *hex_errno = '\0'; + + done: + return res; +} +#endif /* !defined(_WIN32) */ + +/* Maximum number of file descriptors, if we cannot get it via sysconf() */ +#define DEFAULT_MAX_FD 256 + +/** Terminate the process of <b>process_handle</b>, if that process has not + * already exited. + * + * Return 0 if we succeeded in terminating the process (or if the process + * already exited), and -1 if we tried to kill the process but failed. + * + * Based on code originally borrowed from Python's os.kill. */ +int +tor_terminate_process(process_handle_t *process_handle) +{ +#ifdef _WIN32 + if (tor_get_exit_code(process_handle, 0, NULL) == PROCESS_EXIT_RUNNING) { + HANDLE handle = process_handle->pid.hProcess; + + if (!TerminateProcess(handle, 0)) + return -1; + else + return 0; + } +#else /* !(defined(_WIN32)) */ + if (process_handle->waitpid_cb) { + /* We haven't got a waitpid yet, so we can just kill off the process. */ + return kill(process_handle->pid, SIGTERM); + } +#endif /* defined(_WIN32) */ + + return 0; /* We didn't need to kill the process, so report success */ +} + +/** Return the Process ID of <b>process_handle</b>. */ +int +tor_process_get_pid(process_handle_t *process_handle) +{ +#ifdef _WIN32 + return (int) process_handle->pid.dwProcessId; +#else + return (int) process_handle->pid; +#endif +} + +#ifdef _WIN32 +HANDLE +tor_process_get_stdout_pipe(process_handle_t *process_handle) +{ + return process_handle->stdout_pipe; +} +#else /* !(defined(_WIN32)) */ +/* DOCDOC tor_process_get_stdout_pipe */ +int +tor_process_get_stdout_pipe(process_handle_t *process_handle) +{ + return process_handle->stdout_pipe; +} +#endif /* defined(_WIN32) */ + +/* DOCDOC process_handle_new */ +static process_handle_t * +process_handle_new(void) +{ + process_handle_t *out = tor_malloc_zero(sizeof(process_handle_t)); + +#ifdef _WIN32 + out->stdin_pipe = INVALID_HANDLE_VALUE; + out->stdout_pipe = INVALID_HANDLE_VALUE; + out->stderr_pipe = INVALID_HANDLE_VALUE; +#else + out->stdin_pipe = -1; + out->stdout_pipe = -1; + out->stderr_pipe = -1; +#endif /* defined(_WIN32) */ + + return out; +} + +#ifndef _WIN32 +/** Invoked when a process that we've launched via tor_spawn_background() has + * been found to have terminated. + */ +static void +process_handle_waitpid_cb(int status, void *arg) +{ + process_handle_t *process_handle = arg; + + process_handle->waitpid_exit_status = status; + clear_waitpid_callback(process_handle->waitpid_cb); + if (process_handle->status == PROCESS_STATUS_RUNNING) + process_handle->status = PROCESS_STATUS_NOTRUNNING; + process_handle->waitpid_cb = 0; +} +#endif /* !defined(_WIN32) */ + +/** + * @name child-process states + * + * Each of these values represents a possible state that a child process can + * be in. They're used to determine what to say when telling the parent how + * far along we were before failure. + * + * @{ + */ +#define CHILD_STATE_INIT 0 +#define CHILD_STATE_PIPE 1 +#define CHILD_STATE_MAXFD 2 +#define CHILD_STATE_FORK 3 +#define CHILD_STATE_DUPOUT 4 +#define CHILD_STATE_DUPERR 5 +#define CHILD_STATE_DUPIN 6 +#define CHILD_STATE_CLOSEFD 7 +#define CHILD_STATE_EXEC 8 +#define CHILD_STATE_FAILEXEC 9 +/** @} */ +/** + * Boolean. If true, then Tor may call execve or CreateProcess via + * tor_spawn_background. + **/ +static int may_spawn_background_process = 1; +/** + * Turn off may_spawn_background_process, so that all future calls to + * tor_spawn_background are guaranteed to fail. + **/ +void +tor_disable_spawning_background_processes(void) +{ + may_spawn_background_process = 0; +} +/** Start a program in the background. If <b>filename</b> contains a '/', then + * it will be treated as an absolute or relative path. Otherwise, on + * non-Windows systems, the system path will be searched for <b>filename</b>. + * On Windows, only the current directory will be searched. Here, to search the + * system path (as well as the application directory, current working + * directory, and system directories), set filename to NULL. + * + * The strings in <b>argv</b> will be passed as the command line arguments of + * the child program (following convention, argv[0] should normally be the + * filename of the executable, and this must be the case if <b>filename</b> is + * NULL). The last element of argv must be NULL. A handle to the child process + * will be returned in process_handle (which must be non-NULL). Read + * process_handle.status to find out if the process was successfully launched. + * For convenience, process_handle.status is returned by this function. + * + * Some parts of this code are based on the POSIX subprocess module from + * Python, and example code from + * http://msdn.microsoft.com/en-us/library/ms682499%28v=vs.85%29.aspx. + */ +int +tor_spawn_background(const char *const filename, const char **argv, + process_environment_t *env, + process_handle_t **process_handle_out) +{ + if (BUG(may_spawn_background_process == 0)) { + /* We should never reach this point if we're forbidden to spawn + * processes. Instead we should have caught the attempt earlier. */ + return PROCESS_STATUS_ERROR; + } + +#ifdef _WIN32 + HANDLE stdout_pipe_read = NULL; + HANDLE stdout_pipe_write = NULL; + HANDLE stderr_pipe_read = NULL; + HANDLE stderr_pipe_write = NULL; + HANDLE stdin_pipe_read = NULL; + HANDLE stdin_pipe_write = NULL; + process_handle_t *process_handle; + int status; + + STARTUPINFOA siStartInfo; + BOOL retval = FALSE; + + SECURITY_ATTRIBUTES saAttr; + char *joined_argv; + + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + /* TODO: should we set explicit security attributes? (#2046, comment 5) */ + saAttr.lpSecurityDescriptor = NULL; + + /* Assume failure to start process */ + status = PROCESS_STATUS_ERROR; + + /* Set up pipe for stdout */ + if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, &saAttr, 0)) { + log_warn(LD_GENERAL, + "Failed to create pipe for stdout communication with child process: %s", + format_win32_error(GetLastError())); + return status; + } + if (!SetHandleInformation(stdout_pipe_read, HANDLE_FLAG_INHERIT, 0)) { + log_warn(LD_GENERAL, + "Failed to configure pipe for stdout communication with child " + "process: %s", format_win32_error(GetLastError())); + return status; + } + + /* Set up pipe for stderr */ + if (!CreatePipe(&stderr_pipe_read, &stderr_pipe_write, &saAttr, 0)) { + log_warn(LD_GENERAL, + "Failed to create pipe for stderr communication with child process: %s", + format_win32_error(GetLastError())); + return status; + } + if (!SetHandleInformation(stderr_pipe_read, HANDLE_FLAG_INHERIT, 0)) { + log_warn(LD_GENERAL, + "Failed to configure pipe for stderr communication with child " + "process: %s", format_win32_error(GetLastError())); + return status; + } + + /* Set up pipe for stdin */ + if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, &saAttr, 0)) { + log_warn(LD_GENERAL, + "Failed to create pipe for stdin communication with child process: %s", + format_win32_error(GetLastError())); + return status; + } + if (!SetHandleInformation(stdin_pipe_write, HANDLE_FLAG_INHERIT, 0)) { + log_warn(LD_GENERAL, + "Failed to configure pipe for stdin communication with child " + "process: %s", format_win32_error(GetLastError())); + return status; + } + + /* Create the child process */ + + /* Windows expects argv to be a whitespace delimited string, so join argv up + */ + joined_argv = tor_join_win_cmdline(argv); + + process_handle = process_handle_new(); + process_handle->status = status; + + ZeroMemory(&(process_handle->pid), sizeof(PROCESS_INFORMATION)); + ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = stderr_pipe_write; + siStartInfo.hStdOutput = stdout_pipe_write; + siStartInfo.hStdInput = stdin_pipe_read; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES; + + /* Create the child process */ + + retval = CreateProcessA(filename, // module name + joined_argv, // command line + /* TODO: should we set explicit security attributes? (#2046, comment 5) */ + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + /*(TODO: set CREATE_NEW CONSOLE/PROCESS_GROUP to make GetExitCodeProcess() + * work?) */ + CREATE_NO_WINDOW, // creation flags + (env==NULL) ? NULL : env->windows_environment_block, + NULL, // use parent's current directory + &siStartInfo, // STARTUPINFO pointer + &(process_handle->pid)); // receives PROCESS_INFORMATION + + tor_free(joined_argv); + + if (!retval) { + log_warn(LD_GENERAL, + "Failed to create child process %s: %s", filename?filename:argv[0], + format_win32_error(GetLastError())); + tor_free(process_handle); + } else { + /* TODO: Close hProcess and hThread in process_handle->pid? */ + process_handle->stdout_pipe = stdout_pipe_read; + process_handle->stderr_pipe = stderr_pipe_read; + process_handle->stdin_pipe = stdin_pipe_write; + status = process_handle->status = PROCESS_STATUS_RUNNING; + } + + /* TODO: Close pipes on exit */ + *process_handle_out = process_handle; + return status; +#else /* !(defined(_WIN32)) */ + pid_t pid; + int stdout_pipe[2]; + int stderr_pipe[2]; + int stdin_pipe[2]; + int fd, retval; + process_handle_t *process_handle; + int status; + + const char *error_message = SPAWN_ERROR_MESSAGE; + size_t error_message_length; + + /* Represents where in the process of spawning the program is; + this is used for printing out the error message */ + unsigned char child_state = CHILD_STATE_INIT; + + char hex_errno[HEX_ERRNO_SIZE + 2]; /* + 1 should be sufficient actually */ + + static int max_fd = -1; + + status = PROCESS_STATUS_ERROR; + + /* We do the strlen here because strlen() is not signal handler safe, + and we are not allowed to use unsafe functions between fork and exec */ + error_message_length = strlen(error_message); + + // child_state = CHILD_STATE_PIPE; + + /* Set up pipe for redirecting stdout, stderr, and stdin of child */ + retval = pipe(stdout_pipe); + if (-1 == retval) { + log_warn(LD_GENERAL, + "Failed to set up pipe for stdout communication with child process: %s", + strerror(errno)); + return status; + } + + retval = pipe(stderr_pipe); + if (-1 == retval) { + log_warn(LD_GENERAL, + "Failed to set up pipe for stderr communication with child process: %s", + strerror(errno)); + + close(stdout_pipe[0]); + close(stdout_pipe[1]); + + return status; + } + + retval = pipe(stdin_pipe); + if (-1 == retval) { + log_warn(LD_GENERAL, + "Failed to set up pipe for stdin communication with child process: %s", + strerror(errno)); + + close(stdout_pipe[0]); + close(stdout_pipe[1]); + close(stderr_pipe[0]); + close(stderr_pipe[1]); + + return status; + } + + // child_state = CHILD_STATE_MAXFD; + +#ifdef _SC_OPEN_MAX + if (-1 == max_fd) { + max_fd = (int) sysconf(_SC_OPEN_MAX); + if (max_fd == -1) { + max_fd = DEFAULT_MAX_FD; + log_warn(LD_GENERAL, + "Cannot find maximum file descriptor, assuming %d", max_fd); + } + } +#else /* !(defined(_SC_OPEN_MAX)) */ + max_fd = DEFAULT_MAX_FD; +#endif /* defined(_SC_OPEN_MAX) */ + + // child_state = CHILD_STATE_FORK; + + pid = fork(); + if (0 == pid) { + /* In child */ + +#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) + /* Attempt to have the kernel issue a SIGTERM if the parent + * goes away. Certain attributes of the binary being execve()ed + * will clear this during the execve() call, but it's better + * than nothing. + */ + prctl(PR_SET_PDEATHSIG, SIGTERM); +#endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) */ + + child_state = CHILD_STATE_DUPOUT; + + /* Link child stdout to the write end of the pipe */ + retval = dup2(stdout_pipe[1], STDOUT_FILENO); + if (-1 == retval) + goto error; + + child_state = CHILD_STATE_DUPERR; + + /* Link child stderr to the write end of the pipe */ + retval = dup2(stderr_pipe[1], STDERR_FILENO); + if (-1 == retval) + goto error; + + child_state = CHILD_STATE_DUPIN; + + /* Link child stdin to the read end of the pipe */ + retval = dup2(stdin_pipe[0], STDIN_FILENO); + if (-1 == retval) + goto error; + + // child_state = CHILD_STATE_CLOSEFD; + + close(stderr_pipe[0]); + close(stderr_pipe[1]); + close(stdout_pipe[0]); + close(stdout_pipe[1]); + close(stdin_pipe[0]); + close(stdin_pipe[1]); + + /* Close all other fds, including the read end of the pipe */ + /* XXX: We should now be doing enough FD_CLOEXEC setting to make + * this needless. */ + for (fd = STDERR_FILENO + 1; fd < max_fd; fd++) { + close(fd); + } + + // child_state = CHILD_STATE_EXEC; + + /* Call the requested program. We need the cast because + execvp doesn't define argv as const, even though it + does not modify the arguments */ + if (env) + execve(filename, (char *const *) argv, env->unixoid_environment_block); + else { + static char *new_env[] = { NULL }; + execve(filename, (char *const *) argv, new_env); + } + + /* If we got here, the exec or open(/dev/null) failed */ + + child_state = CHILD_STATE_FAILEXEC; + + error: + { + /* XXX: are we leaking fds from the pipe? */ + int n, err=0; + ssize_t nbytes; + + n = format_helper_exit_status(child_state, errno, hex_errno); + + if (n >= 0) { + /* Write the error message. GCC requires that we check the return + value, but there is nothing we can do if it fails */ + /* TODO: Don't use STDOUT, use a pipe set up just for this purpose */ + nbytes = write(STDOUT_FILENO, error_message, error_message_length); + err = (nbytes < 0); + nbytes = write(STDOUT_FILENO, hex_errno, n); + err += (nbytes < 0); + } + + _exit(err?254:255); // exit ok: in child. + } + + /* Never reached, but avoids compiler warning */ + return status; // LCOV_EXCL_LINE + } + + /* In parent */ + + if (-1 == pid) { + log_warn(LD_GENERAL, "Failed to fork child process: %s", strerror(errno)); + close(stdin_pipe[0]); + close(stdin_pipe[1]); + close(stdout_pipe[0]); + close(stdout_pipe[1]); + close(stderr_pipe[0]); + close(stderr_pipe[1]); + return status; + } + + process_handle = process_handle_new(); + process_handle->status = status; + process_handle->pid = pid; + + /* TODO: If the child process forked but failed to exec, waitpid it */ + + /* Return read end of the pipes to caller, and close write end */ + process_handle->stdout_pipe = stdout_pipe[0]; + retval = close(stdout_pipe[1]); + + if (-1 == retval) { + log_warn(LD_GENERAL, + "Failed to close write end of stdout pipe in parent process: %s", + strerror(errno)); + } + + process_handle->waitpid_cb = set_waitpid_callback(pid, + process_handle_waitpid_cb, + process_handle); + + process_handle->stderr_pipe = stderr_pipe[0]; + retval = close(stderr_pipe[1]); + + if (-1 == retval) { + log_warn(LD_GENERAL, + "Failed to close write end of stderr pipe in parent process: %s", + strerror(errno)); + } + + /* Return write end of the stdin pipe to caller, and close the read end */ + process_handle->stdin_pipe = stdin_pipe[1]; + retval = close(stdin_pipe[0]); + + if (-1 == retval) { + log_warn(LD_GENERAL, + "Failed to close read end of stdin pipe in parent process: %s", + strerror(errno)); + } + + status = process_handle->status = PROCESS_STATUS_RUNNING; + /* Set stdin/stdout/stderr pipes to be non-blocking */ + if (fcntl(process_handle->stdout_pipe, F_SETFL, O_NONBLOCK) < 0 || + fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK) < 0 || + fcntl(process_handle->stdin_pipe, F_SETFL, O_NONBLOCK) < 0) { + log_warn(LD_GENERAL, "Failed to set stderror/stdout/stdin pipes " + "nonblocking in parent process: %s", strerror(errno)); + } + + *process_handle_out = process_handle; + return status; +#endif /* defined(_WIN32) */ +} + +/** Destroy all resources allocated by the process handle in + * <b>process_handle</b>. + * If <b>also_terminate_process</b> is true, also terminate the + * process of the process handle. */ +MOCK_IMPL(void, +tor_process_handle_destroy,(process_handle_t *process_handle, + int also_terminate_process)) +{ + if (!process_handle) + return; + + if (also_terminate_process) { + if (tor_terminate_process(process_handle) < 0) { + const char *errstr = +#ifdef _WIN32 + format_win32_error(GetLastError()); +#else + strerror(errno); +#endif + log_notice(LD_GENERAL, "Failed to terminate process with " + "PID '%d' ('%s').", tor_process_get_pid(process_handle), + errstr); + } else { + log_info(LD_GENERAL, "Terminated process with PID '%d'.", + tor_process_get_pid(process_handle)); + } + } + + process_handle->status = PROCESS_STATUS_NOTRUNNING; + +#ifdef _WIN32 + if (process_handle->stdout_pipe) + CloseHandle(process_handle->stdout_pipe); + + if (process_handle->stderr_pipe) + CloseHandle(process_handle->stderr_pipe); + + if (process_handle->stdin_pipe) + CloseHandle(process_handle->stdin_pipe); +#else /* !(defined(_WIN32)) */ + close(process_handle->stdout_pipe); + close(process_handle->stderr_pipe); + close(process_handle->stdin_pipe); + + clear_waitpid_callback(process_handle->waitpid_cb); +#endif /* defined(_WIN32) */ + + memset(process_handle, 0x0f, sizeof(process_handle_t)); + tor_free(process_handle); +} + +/** Get the exit code of a process specified by <b>process_handle</b> and store + * it in <b>exit_code</b>, if set to a non-NULL value. If <b>block</b> is set + * to true, the call will block until the process has exited. Otherwise if + * the process is still running, the function will return + * PROCESS_EXIT_RUNNING, and exit_code will be left unchanged. Returns + * PROCESS_EXIT_EXITED if the process did exit. If there is a failure, + * PROCESS_EXIT_ERROR will be returned and the contents of exit_code (if + * non-NULL) will be undefined. N.B. Under *nix operating systems, this will + * probably not work in Tor, because waitpid() is called in main.c to reap any + * terminated child processes.*/ +int +tor_get_exit_code(process_handle_t *process_handle, + int block, int *exit_code) +{ +#ifdef _WIN32 + DWORD retval; + BOOL success; + + if (block) { + /* Wait for the process to exit */ + retval = WaitForSingleObject(process_handle->pid.hProcess, INFINITE); + if (retval != WAIT_OBJECT_0) { + log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s", + (int)retval, format_win32_error(GetLastError())); + return PROCESS_EXIT_ERROR; + } + } else { + retval = WaitForSingleObject(process_handle->pid.hProcess, 0); + if (WAIT_TIMEOUT == retval) { + /* Process has not exited */ + return PROCESS_EXIT_RUNNING; + } else if (retval != WAIT_OBJECT_0) { + log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s", + (int)retval, format_win32_error(GetLastError())); + return PROCESS_EXIT_ERROR; + } + } + + if (exit_code != NULL) { + success = GetExitCodeProcess(process_handle->pid.hProcess, + (PDWORD)exit_code); + if (!success) { + log_warn(LD_GENERAL, "GetExitCodeProcess() failed: %s", + format_win32_error(GetLastError())); + return PROCESS_EXIT_ERROR; + } + } +#else /* !(defined(_WIN32)) */ + int stat_loc; + int retval; + + if (process_handle->waitpid_cb) { + /* We haven't processed a SIGCHLD yet. */ + retval = waitpid(process_handle->pid, &stat_loc, block?0:WNOHANG); + if (retval == process_handle->pid) { + clear_waitpid_callback(process_handle->waitpid_cb); + process_handle->waitpid_cb = NULL; + process_handle->waitpid_exit_status = stat_loc; + } + } else { + /* We already got a SIGCHLD for this process, and handled it. */ + retval = process_handle->pid; + stat_loc = process_handle->waitpid_exit_status; + } + + if (!block && 0 == retval) { + /* Process has not exited */ + return PROCESS_EXIT_RUNNING; + } else if (retval != process_handle->pid) { + log_warn(LD_GENERAL, "waitpid() failed for PID %d: %s", + (int)process_handle->pid, strerror(errno)); + return PROCESS_EXIT_ERROR; + } + + if (!WIFEXITED(stat_loc)) { + log_warn(LD_GENERAL, "Process %d did not exit normally", + (int)process_handle->pid); + return PROCESS_EXIT_ERROR; + } + + if (exit_code != NULL) + *exit_code = WEXITSTATUS(stat_loc); +#endif /* defined(_WIN32) */ + + return PROCESS_EXIT_EXITED; +} + +#ifdef _WIN32 +/** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes. If + * <b>hProcess</b> is NULL, the function will return immediately if there is + * nothing more to read. Otherwise <b>hProcess</b> should be set to the handle + * to the process owning the <b>h</b>. In this case, the function will exit + * only once the process has exited, or <b>count</b> bytes are read. Returns + * the number of bytes read, or -1 on error. */ +ssize_t +tor_read_all_handle(HANDLE h, char *buf, size_t count, + const process_handle_t *process) +{ + size_t numread = 0; + BOOL retval; + DWORD byte_count; + BOOL process_exited = FALSE; + + if (count > SIZE_T_CEILING || count > SSIZE_MAX) + return -1; + + while (numread < count) { + /* Check if there is anything to read */ + retval = PeekNamedPipe(h, NULL, 0, NULL, &byte_count, NULL); + if (!retval) { + log_warn(LD_GENERAL, + "Failed to peek from handle: %s", + format_win32_error(GetLastError())); + return -1; + } else if (0 == byte_count) { + /* Nothing available: process exited or it is busy */ + + /* Exit if we don't know whether the process is running */ + if (NULL == process) + break; + + /* The process exited and there's nothing left to read from it */ + if (process_exited) + break; + + /* If process is not running, check for output one more time in case + it wrote something after the peek was performed. Otherwise keep on + waiting for output */ + tor_assert(process != NULL); + byte_count = WaitForSingleObject(process->pid.hProcess, 0); + if (WAIT_TIMEOUT != byte_count) + process_exited = TRUE; + + continue; + } + + /* There is data to read; read it */ + retval = ReadFile(h, buf+numread, count-numread, &byte_count, NULL); + tor_assert(byte_count + numread <= count); + if (!retval) { + log_warn(LD_GENERAL, "Failed to read from handle: %s", + format_win32_error(GetLastError())); + return -1; + } else if (0 == byte_count) { + /* End of file */ + break; + } + numread += byte_count; + } + return (ssize_t)numread; +} +#else /* !(defined(_WIN32)) */ +/** Read from a handle <b>fd</b> into <b>buf</b>, up to <b>count</b> bytes. If + * <b>process</b> is NULL, the function will return immediately if there is + * nothing more to read. Otherwise data will be read until end of file, or + * <b>count</b> bytes are read. Returns the number of bytes read, or -1 on + * error. Sets <b>eof</b> to true if <b>eof</b> is not NULL and the end of the + * file has been reached. */ +ssize_t +tor_read_all_handle(int fd, char *buf, size_t count, + const process_handle_t *process, + int *eof) +{ + size_t numread = 0; + ssize_t result; + + if (eof) + *eof = 0; + + if (count > SIZE_T_CEILING || count > SSIZE_MAX) + return -1; + + while (numread < count) { + result = read(fd, buf+numread, count-numread); + + if (result == 0) { + log_debug(LD_GENERAL, "read() reached end of file"); + if (eof) + *eof = 1; + break; + } else if (result < 0 && errno == EAGAIN) { + if (process) + continue; + else + break; + } else if (result < 0) { + log_warn(LD_GENERAL, "read() failed: %s", strerror(errno)); + return -1; + } + + numread += result; + } + + log_debug(LD_GENERAL, "read() read %d bytes from handle", (int)numread); + return (ssize_t)numread; +} +#endif /* defined(_WIN32) */ + +/** Read from stdout of a process until the process exits. */ +ssize_t +tor_read_all_from_process_stdout(const process_handle_t *process_handle, + char *buf, size_t count) +{ +#ifdef _WIN32 + return tor_read_all_handle(process_handle->stdout_pipe, buf, count, + process_handle); +#else + return tor_read_all_handle(process_handle->stdout_pipe, buf, count, + process_handle, NULL); +#endif /* defined(_WIN32) */ +} + +/** Read from stdout of a process until the process exits. */ +ssize_t +tor_read_all_from_process_stderr(const process_handle_t *process_handle, + char *buf, size_t count) +{ +#ifdef _WIN32 + return tor_read_all_handle(process_handle->stderr_pipe, buf, count, + process_handle); +#else + return tor_read_all_handle(process_handle->stderr_pipe, buf, count, + process_handle, NULL); +#endif /* defined(_WIN32) */ +} + +/** Return a string corresponding to <b>stream_status</b>. */ +const char * +stream_status_to_string(enum stream_status stream_status) +{ + switch (stream_status) { + case IO_STREAM_OKAY: + return "okay"; + case IO_STREAM_EAGAIN: + return "temporarily unavailable"; + case IO_STREAM_TERM: + return "terminated"; + case IO_STREAM_CLOSED: + return "closed"; + default: + tor_fragile_assert(); + return "unknown"; + } +} + +/** Split buf into lines, and add to smartlist. The buffer <b>buf</b> will be + * modified. The resulting smartlist will consist of pointers to buf, so there + * is no need to free the contents of sl. <b>buf</b> must be a NUL-terminated + * string. <b>len</b> should be set to the length of the buffer excluding the + * NUL. Non-printable characters (including NUL) will be replaced with "." */ +int +tor_split_lines(smartlist_t *sl, char *buf, int len) +{ + /* Index in buf of the start of the current line */ + int start = 0; + /* Index in buf of the current character being processed */ + int cur = 0; + /* Are we currently in a line */ + char in_line = 0; + + /* Loop over string */ + while (cur < len) { + /* Loop until end of line or end of string */ + for (; cur < len; cur++) { + if (in_line) { + if ('\r' == buf[cur] || '\n' == buf[cur]) { + /* End of line */ + buf[cur] = '\0'; + /* Point cur to the next line */ + cur++; + /* Line starts at start and ends with a nul */ + break; + } else { + if (!TOR_ISPRINT(buf[cur])) + buf[cur] = '.'; + } + } else { + if ('\r' == buf[cur] || '\n' == buf[cur]) { + /* Skip leading vertical space */ + ; + } else { + in_line = 1; + start = cur; + if (!TOR_ISPRINT(buf[cur])) + buf[cur] = '.'; + } + } + } + /* We are at the end of the line or end of string. If in_line is true there + * is a line which starts at buf+start and ends at a NUL. cur points to + * the character after the NUL. */ + if (in_line) + smartlist_add(sl, (void *)(buf+start)); + in_line = 0; + } + return smartlist_len(sl); +} + +#ifdef _WIN32 + +/** Return a smartlist containing lines outputted from + * <b>handle</b>. Return NULL on error, and set + * <b>stream_status_out</b> appropriately. */ +MOCK_IMPL(smartlist_t *, +tor_get_lines_from_handle, (HANDLE *handle, + enum stream_status *stream_status_out)) +{ + int pos; + char stdout_buf[600] = {0}; + smartlist_t *lines = NULL; + + tor_assert(stream_status_out); + + *stream_status_out = IO_STREAM_TERM; + + pos = tor_read_all_handle(handle, stdout_buf, sizeof(stdout_buf) - 1, NULL); + if (pos < 0) { + *stream_status_out = IO_STREAM_TERM; + return NULL; + } + if (pos == 0) { + *stream_status_out = IO_STREAM_EAGAIN; + return NULL; + } + + /* End with a null even if there isn't a \r\n at the end */ + /* TODO: What if this is a partial line? */ + stdout_buf[pos] = '\0'; + + /* Split up the buffer */ + lines = smartlist_new(); + tor_split_lines(lines, stdout_buf, pos); + + /* Currently 'lines' is populated with strings residing on the + stack. Replace them with their exact copies on the heap: */ + SMARTLIST_FOREACH(lines, char *, line, + SMARTLIST_REPLACE_CURRENT(lines, line, tor_strdup(line))); + + *stream_status_out = IO_STREAM_OKAY; + + return lines; +} + +#else /* !(defined(_WIN32)) */ + +/** Return a smartlist containing lines outputted from + * <b>fd</b>. Return NULL on error, and set + * <b>stream_status_out</b> appropriately. */ +MOCK_IMPL(smartlist_t *, +tor_get_lines_from_handle, (int fd, enum stream_status *stream_status_out)) +{ + enum stream_status stream_status; + char stdout_buf[400]; + smartlist_t *lines = NULL; + + while (1) { + memset(stdout_buf, 0, sizeof(stdout_buf)); + + stream_status = get_string_from_pipe(fd, + stdout_buf, sizeof(stdout_buf) - 1); + if (stream_status != IO_STREAM_OKAY) + goto done; + + if (!lines) lines = smartlist_new(); + smartlist_split_string(lines, stdout_buf, "\n", 0, 0); + } + + done: + *stream_status_out = stream_status; + return lines; +} + +#endif /* defined(_WIN32) */ + +/** Reads from <b>fd</b> and stores input in <b>buf_out</b> making + * sure it's below <b>count</b> bytes. + * If the string has a trailing newline, we strip it off. + * + * This function is specifically created to handle input from managed + * proxies, according to the pluggable transports spec. Make sure it + * fits your needs before using it. + * + * Returns: + * IO_STREAM_CLOSED: If the stream is closed. + * IO_STREAM_EAGAIN: If there is nothing to read and we should check back + * later. + * IO_STREAM_TERM: If something is wrong with the stream. + * IO_STREAM_OKAY: If everything went okay and we got a string + * in <b>buf_out</b>. */ +enum stream_status +get_string_from_pipe(int fd, char *buf_out, size_t count) +{ + ssize_t ret; + + tor_assert(count <= INT_MAX); + + ret = read(fd, buf_out, count); + + if (ret == 0) + return IO_STREAM_CLOSED; + else if (ret < 0 && errno == EAGAIN) + return IO_STREAM_EAGAIN; + else if (ret < 0) + return IO_STREAM_TERM; + + if (buf_out[ret - 1] == '\n') { + /* Remove the trailing newline */ + buf_out[ret - 1] = '\0'; + } else + buf_out[ret] = '\0'; + + return IO_STREAM_OKAY; +} diff --git a/src/lib/process/subprocess.h b/src/lib/process/subprocess.h new file mode 100644 index 0000000000..a319b3505c --- /dev/null +++ b/src/lib/process/subprocess.h @@ -0,0 +1,129 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SUBPROCESS_H +#define TOR_SUBPROCESS_H + +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" +#include <stddef.h> +#ifdef _WIN32 +#include <windows.h> +#endif + +struct smartlist_t; + +void tor_disable_spawning_background_processes(void); + +typedef struct process_handle_t process_handle_t; +struct process_environment_t; +int tor_spawn_background(const char *const filename, const char **argv, + struct process_environment_t *env, + process_handle_t **process_handle_out); + +#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code " + +/** Status of an I/O stream. */ +enum stream_status { + IO_STREAM_OKAY, + IO_STREAM_EAGAIN, + IO_STREAM_TERM, + IO_STREAM_CLOSED +}; + +const char *stream_status_to_string(enum stream_status stream_status); + +enum stream_status get_string_from_pipe(int fd, char *buf, size_t count); + +/* Values of process_handle_t.status. */ +#define PROCESS_STATUS_NOTRUNNING 0 +#define PROCESS_STATUS_RUNNING 1 +#define PROCESS_STATUS_ERROR -1 + +#ifdef SUBPROCESS_PRIVATE +struct waitpid_callback_t; + +/** Structure to represent the state of a process with which Tor is + * communicating. The contents of this structure are private to util.c */ +struct process_handle_t { + /** One of the PROCESS_STATUS_* values */ + int status; +#ifdef _WIN32 + HANDLE stdin_pipe; + HANDLE stdout_pipe; + HANDLE stderr_pipe; + PROCESS_INFORMATION pid; +#else /* !(defined(_WIN32)) */ + int stdin_pipe; + int stdout_pipe; + int stderr_pipe; + pid_t pid; + /** If the process has not given us a SIGCHLD yet, this has the + * waitpid_callback_t that gets invoked once it has. Otherwise this + * contains NULL. */ + struct waitpid_callback_t *waitpid_cb; + /** The exit status reported by waitpid. */ + int waitpid_exit_status; +#endif /* defined(_WIN32) */ +}; +#endif /* defined(SUBPROCESS_PRIVATE) */ + +/* Return values of tor_get_exit_code() */ +#define PROCESS_EXIT_RUNNING 1 +#define PROCESS_EXIT_EXITED 0 +#define PROCESS_EXIT_ERROR -1 +int tor_get_exit_code(process_handle_t *process_handle, + int block, int *exit_code); +int tor_split_lines(struct smartlist_t *sl, char *buf, int len); +#ifdef _WIN32 +ssize_t tor_read_all_handle(HANDLE h, char *buf, size_t count, + const process_handle_t *process); +#else +ssize_t tor_read_all_handle(int fd, char *buf, size_t count, + const process_handle_t *process, + int *eof); +#endif /* defined(_WIN32) */ +ssize_t tor_read_all_from_process_stdout( + const process_handle_t *process_handle, char *buf, size_t count); +ssize_t tor_read_all_from_process_stderr( + const process_handle_t *process_handle, char *buf, size_t count); +char *tor_join_win_cmdline(const char *argv[]); + +int tor_process_get_pid(process_handle_t *process_handle); +#ifdef _WIN32 +HANDLE tor_process_get_stdout_pipe(process_handle_t *process_handle); +#else +int tor_process_get_stdout_pipe(process_handle_t *process_handle); +#endif + +#ifdef _WIN32 +MOCK_DECL(struct smartlist_t *, tor_get_lines_from_handle,(HANDLE *handle, + enum stream_status *stream_status)); +#else +MOCK_DECL(struct smartlist_t *, tor_get_lines_from_handle,(int fd, + enum stream_status *stream_status)); +#endif /* defined(_WIN32) */ + +int tor_terminate_process(process_handle_t *process_handle); + +MOCK_DECL(void, tor_process_handle_destroy,(process_handle_t *process_handle, + int also_terminate_process)); + +#ifdef SUBPROCESS_PRIVATE +/* Prototypes for private functions only used by util.c (and unit tests) */ + +#ifndef _WIN32 +STATIC int format_helper_exit_status(unsigned char child_state, + int saved_errno, char *hex_errno); + +/* Space for hex values of child state, a slash, saved_errno (with + leading minus) and newline (no null) */ +#define HEX_ERRNO_SIZE (sizeof(char) * 2 + 1 + \ + 1 + sizeof(int) * 2 + 1) +#endif /* !defined(_WIN32) */ + +#endif /* defined(SUBPROCESS_PRIVATE) */ + +#endif diff --git a/src/common/util_process.c b/src/lib/process/waitpid.c index c2826152e9..66c77b05f3 100644 --- a/src/common/util_process.c +++ b/src/lib/process/waitpid.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,18 +12,19 @@ #include "orconfig.h" -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif +#ifndef _WIN32 + +#include "lib/process/waitpid.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "ht.h" + #ifdef HAVE_SYS_WAIT_H #include <sys/wait.h> #endif -#include "compat.h" -#include "util.h" -#include "torlog.h" -#include "util_process.h" -#include "ht.h" +#include <string.h> /* ================================================== */ /* Convenience structures for handlers for waitpid(). @@ -32,8 +33,6 @@ * monitoring a non-child process. */ -#ifndef _WIN32 - /** Mapping from a PID to a userfn/userdata pair. */ struct waitpid_callback_t { HT_ENTRY(waitpid_callback_t) node; @@ -155,4 +154,3 @@ notify_pending_waitpid_callbacks(void) } #endif /* !defined(_WIN32) */ - diff --git a/src/common/util_process.h b/src/lib/process/waitpid.h index c9aa771b77..85905da6bf 100644 --- a/src/common/util_process.h +++ b/src/lib/process/waitpid.h @@ -1,15 +1,19 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ +/* Copyright (c) 2011-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file util_process.h - * \brief Headers for util_process.c + * \file waitpid.h + * \brief Headers for waitpid.c **/ -#ifndef TOR_UTIL_PROCESS_H -#define TOR_UTIL_PROCESS_H +#ifndef TOR_WAITPID_H +#define TOR_WAITPID_H #ifndef _WIN32 +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + /** A callback structure waiting for us to get a SIGCHLD informing us that a * PID has been closed. Created by set_waitpid_callback. Cancelled or cleaned- * up from clear_waitpid_callback(). Do not access outside of the main thread; @@ -22,5 +26,4 @@ void clear_waitpid_callback(waitpid_callback_t *ent); void notify_pending_waitpid_callbacks(void); #endif /* !defined(_WIN32) */ -#endif /* !defined(TOR_UTIL_PROCESS_H) */ - +#endif /* !defined(TOR_WAITPID_H) */ diff --git a/src/lib/sandbox/.may_include b/src/lib/sandbox/.may_include new file mode 100644 index 0000000000..84906dfb3d --- /dev/null +++ b/src/lib/sandbox/.may_include @@ -0,0 +1,15 @@ +orconfig.h + +lib/cc/*.h +lib/container/*.h +lib/err/*.h +lib/log/*.h +lib/malloc/*.h +lib/net/*.h +lib/sandbox/*.h +lib/sandbox/*.inc +lib/string/*.h + +ht.h +siphash.h +tor_queue.h diff --git a/src/lib/sandbox/include.am b/src/lib/sandbox/include.am new file mode 100644 index 0000000000..adfda6bde5 --- /dev/null +++ b/src/lib/sandbox/include.am @@ -0,0 +1,18 @@ + +noinst_LIBRARIES += src/lib/libtor-sandbox.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-sandbox-testing.a +endif + +src_lib_libtor_sandbox_a_SOURCES = \ + src/lib/sandbox/sandbox.c + +src_lib_libtor_sandbox_testing_a_SOURCES = \ + $(src_lib_libtor_sandbox_a_SOURCES) +src_lib_libtor_sandbox_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_sandbox_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/sandbox/linux_syscalls.inc \ + src/lib/sandbox/sandbox.h diff --git a/src/common/linux_syscalls.inc b/src/lib/sandbox/linux_syscalls.inc index cf47c73809..cf47c73809 100644 --- a/src/common/linux_syscalls.inc +++ b/src/lib/sandbox/linux_syscalls.inc diff --git a/src/common/sandbox.c b/src/lib/sandbox/sandbox.c index 440f8722f2..e49cbd863a 100644 --- a/src/common/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -1,7 +1,7 @@ - /* Copyright (c) 2001 Matej Pfajfar. +/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -31,15 +31,20 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <errno.h> -#include "sandbox.h" -#include "container.h" -#include "torlog.h" -#include "torint.h" -#include "util.h" -#include "tor_queue.h" +#include "lib/sandbox/sandbox.h" +#include "lib/container/map.h" +#include "lib/err/torerr.h" +#include "lib/log/torlog.h" +#include "lib/cc/torint.h" +#include "lib/net/resolve.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/scanf.h" +#include "tor_queue.h" #include "ht.h" +#include "siphash.h" #define DEBUGGING_CLOSE @@ -79,7 +84,7 @@ defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) #define USE_BACKTRACE #define EXPOSE_CLEAN_BACKTRACE -#include "backtrace.h" +#include "lib/err/backtrace.h" #endif /* defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && ... */ #ifdef USE_BACKTRACE @@ -1455,183 +1460,6 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file) return 0; } -/** Cache entry for getaddrinfo results; used when sandboxing is implemented - * so that we can consult the cache when the sandbox prevents us from doing - * getaddrinfo. - * - * We support only a limited range of getaddrinfo calls, where servname is null - * and hints contains only socktype=SOCK_STREAM, family in INET,INET6,UNSPEC. - */ -typedef struct cached_getaddrinfo_item_t { - HT_ENTRY(cached_getaddrinfo_item_t) node; - char *name; - int family; - /** set if no error; otherwise NULL */ - struct addrinfo *res; - /** 0 for no error; otherwise an EAI_* value */ - int err; -} cached_getaddrinfo_item_t; - -static unsigned -cached_getaddrinfo_item_hash(const cached_getaddrinfo_item_t *item) -{ - return (unsigned)siphash24g(item->name, strlen(item->name)) + item->family; -} - -static unsigned -cached_getaddrinfo_items_eq(const cached_getaddrinfo_item_t *a, - const cached_getaddrinfo_item_t *b) -{ - return (a->family == b->family) && 0 == strcmp(a->name, b->name); -} - -#define cached_getaddrinfo_item_free(item) \ - FREE_AND_NULL(cached_getaddrinfo_item_t, \ - cached_getaddrinfo_item_free_, (item)) - -static void -cached_getaddrinfo_item_free_(cached_getaddrinfo_item_t *item) -{ - if (item == NULL) - return; - - tor_free(item->name); - if (item->res) - freeaddrinfo(item->res); - tor_free(item); -} - -static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t) - getaddrinfo_cache = HT_INITIALIZER(); - -HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node, - cached_getaddrinfo_item_hash, - cached_getaddrinfo_items_eq) -HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node, - cached_getaddrinfo_item_hash, - cached_getaddrinfo_items_eq, - 0.6, tor_reallocarray_, tor_free_) - -/** If true, don't try to cache getaddrinfo results. */ -static int sandbox_getaddrinfo_cache_disabled = 0; - -/** Tell the sandbox layer not to try to cache getaddrinfo results. Used as in - * tor-resolve, when we have no intention of initializing crypto or of - * installing the sandbox.*/ -void -sandbox_disable_getaddrinfo_cache(void) -{ - sandbox_getaddrinfo_cache_disabled = 1; -} - -void -sandbox_freeaddrinfo(struct addrinfo *ai) -{ - if (sandbox_getaddrinfo_cache_disabled) - freeaddrinfo(ai); -} - -int -sandbox_getaddrinfo(const char *name, const char *servname, - const struct addrinfo *hints, - struct addrinfo **res) -{ - int err; - struct cached_getaddrinfo_item_t search, *item; - - if (sandbox_getaddrinfo_cache_disabled) { - return getaddrinfo(name, NULL, hints, res); - } - - if (servname != NULL) { - log_warn(LD_BUG, "called with non-NULL servname"); - return EAI_NONAME; - } - if (name == NULL) { - log_warn(LD_BUG, "called with NULL name"); - return EAI_NONAME; - } - - *res = NULL; - - memset(&search, 0, sizeof(search)); - search.name = (char *) name; - search.family = hints ? hints->ai_family : AF_UNSPEC; - item = HT_FIND(getaddrinfo_cache, &getaddrinfo_cache, &search); - - if (! sandbox_is_active()) { - /* If the sandbox is not turned on yet, then getaddrinfo and store the - result. */ - - err = getaddrinfo(name, NULL, hints, res); - log_info(LD_NET,"(Sandbox) getaddrinfo %s.", err ? "failed" : "succeeded"); - - if (! item) { - item = tor_malloc_zero(sizeof(*item)); - item->name = tor_strdup(name); - item->family = hints ? hints->ai_family : AF_UNSPEC; - HT_INSERT(getaddrinfo_cache, &getaddrinfo_cache, item); - } - - if (item->res) { - freeaddrinfo(item->res); - item->res = NULL; - } - item->res = *res; - item->err = err; - return err; - } - - /* Otherwise, the sandbox is on. If we have an item, yield its cached - result. */ - if (item) { - *res = item->res; - return item->err; - } - - /* getting here means something went wrong */ - log_err(LD_BUG,"(Sandbox) failed to get address %s!", name); - return EAI_NONAME; -} - -int -sandbox_add_addrinfo(const char *name) -{ - struct addrinfo *res; - struct addrinfo hints; - int i; - static const int families[] = { AF_INET, AF_INET6, AF_UNSPEC }; - - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - for (i = 0; i < 3; ++i) { - hints.ai_family = families[i]; - - res = NULL; - (void) sandbox_getaddrinfo(name, NULL, &hints, &res); - if (res) - sandbox_freeaddrinfo(res); - } - - return 0; -} - -void -sandbox_free_getaddrinfo_cache(void) -{ - cached_getaddrinfo_item_t **next, **item, *this; - - for (item = HT_START(getaddrinfo_cache, &getaddrinfo_cache); - item; - item = next) { - this = *item; - next = HT_NEXT_RMV(getaddrinfo_cache, &getaddrinfo_cache, item); - cached_getaddrinfo_item_free(this); - } - - HT_CLEAR(getaddrinfo_cache, &getaddrinfo_cache); -} - /** * Function responsible for going through the parameter syscall filters and * call each function pointer in the list. @@ -1724,13 +1552,15 @@ install_syscall_filter(sandbox_cfg_t* cfg) // marking the sandbox as active sandbox_active = 1; + sandbox_make_getaddrinfo_cache_active(); end: seccomp_release(ctx); return (rc < 0 ? -rc : rc); } -#include "linux_syscalls.inc" +#include "lib/sandbox/linux_syscalls.inc" + static const char * get_syscall_name(int syscall_num) { @@ -1974,4 +1804,3 @@ sandbox_disable_getaddrinfo_cache(void) { } #endif /* !defined(USE_LIBSECCOMP) */ - diff --git a/src/common/sandbox.h b/src/lib/sandbox/sandbox.h index d0f85570f4..60d8e8816a 100644 --- a/src/common/sandbox.h +++ b/src/lib/sandbox/sandbox.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,7 +13,7 @@ #define SANDBOX_H_ #include "orconfig.h" -#include "torint.h" +#include "lib/cc/torint.h" #ifndef SYS_SECCOMP @@ -104,27 +104,6 @@ typedef struct { #endif /* defined(USE_LIBSECCOMP) */ #ifdef USE_LIBSECCOMP -/** Pre-calls getaddrinfo in order to pre-record result. */ -int sandbox_add_addrinfo(const char *addr); - -struct addrinfo; -/** Replacement for getaddrinfo(), using pre-recorded results. */ -int sandbox_getaddrinfo(const char *name, const char *servname, - const struct addrinfo *hints, - struct addrinfo **res); -void sandbox_freeaddrinfo(struct addrinfo *addrinfo); -void sandbox_free_getaddrinfo_cache(void); -#else /* !(defined(USE_LIBSECCOMP)) */ -#define sandbox_getaddrinfo(name, servname, hints, res) \ - getaddrinfo((name),(servname), (hints),(res)) -#define sandbox_add_addrinfo(name) \ - ((void)(name)) -#define sandbox_freeaddrinfo(addrinfo) \ - freeaddrinfo((addrinfo)) -#define sandbox_free_getaddrinfo_cache() -#endif /* defined(USE_LIBSECCOMP) */ - -#ifdef USE_LIBSECCOMP /** Returns a registered protected string used with the sandbox, given that * it matches the parameter. */ @@ -168,7 +147,4 @@ int sandbox_init(sandbox_cfg_t* cfg); /** Return true iff the sandbox is turned on. */ int sandbox_is_active(void); -void sandbox_disable_getaddrinfo_cache(void); - #endif /* !defined(SANDBOX_H_) */ - diff --git a/src/lib/smartlist_core/.may_include b/src/lib/smartlist_core/.may_include new file mode 100644 index 0000000000..a8507761a4 --- /dev/null +++ b/src/lib/smartlist_core/.may_include @@ -0,0 +1,7 @@ +orconfig.h +lib/cc/*.h +lib/malloc/*.h +lib/err/*.h +lib/string/*.h +lib/smartlist_core/*.h +lib/testsupport/testsupport.h diff --git a/src/lib/smartlist_core/include.am b/src/lib/smartlist_core/include.am new file mode 100644 index 0000000000..9ee93fdee7 --- /dev/null +++ b/src/lib/smartlist_core/include.am @@ -0,0 +1,21 @@ + +noinst_LIBRARIES += src/lib/libtor-smartlist-core.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-smartlist-core-testing.a +endif + +src_lib_libtor_smartlist_core_a_SOURCES = \ + src/lib/smartlist_core/smartlist_core.c \ + src/lib/smartlist_core/smartlist_split.c + +src_lib_libtor_smartlist_core_testing_a_SOURCES = \ + $(src_lib_libtor_smartlist_core_a_SOURCES) +src_lib_libtor_smartlist_core_testing_a_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_smartlist_core_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/smartlist_core/smartlist_core.h \ + src/lib/smartlist_core/smartlist_foreach.h \ + src/lib/smartlist_core/smartlist_split.h diff --git a/src/lib/smartlist_core/smartlist_core.c b/src/lib/smartlist_core/smartlist_core.c new file mode 100644 index 0000000000..b9c5f728ce --- /dev/null +++ b/src/lib/smartlist_core/smartlist_core.c @@ -0,0 +1,234 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file smartlist_core.c + * \brief Implements the core functionality of a smartlist (a resizeable + * dynamic array). For more functionality and helper functions, see the + * container library. + **/ + +#include "lib/err/torerr.h" +#include "lib/malloc/util_malloc.h" +#include "lib/smartlist_core/smartlist_core.h" + +#include <stdlib.h> +#include <string.h> + +/** All newly allocated smartlists have this capacity. */ +#define SMARTLIST_DEFAULT_CAPACITY 16 + +/** Allocate and return an empty smartlist. + */ +MOCK_IMPL(smartlist_t *, +smartlist_new,(void)) +{ + smartlist_t *sl = tor_malloc(sizeof(smartlist_t)); + sl->num_used = 0; + sl->capacity = SMARTLIST_DEFAULT_CAPACITY; + sl->list = tor_calloc(sizeof(void *), sl->capacity); + return sl; +} + +/** Deallocate a smartlist. Does not release storage associated with the + * list's elements. + */ +MOCK_IMPL(void, +smartlist_free_,(smartlist_t *sl)) +{ + if (!sl) + return; + tor_free(sl->list); + tor_free(sl); +} + +/** Remove all elements from the list. + */ +void +smartlist_clear(smartlist_t *sl) +{ + memset(sl->list, 0, sizeof(void *) * sl->num_used); + sl->num_used = 0; +} + +#if SIZE_MAX < INT_MAX +#error "We don't support systems where size_t is smaller than int." +#endif + +/** Make sure that <b>sl</b> can hold at least <b>size</b> entries. */ +static inline void +smartlist_ensure_capacity(smartlist_t *sl, size_t size) +{ + /* Set MAX_CAPACITY to MIN(INT_MAX, SIZE_MAX / sizeof(void*)) */ +#if (SIZE_MAX/SIZEOF_VOID_P) > INT_MAX +#define MAX_CAPACITY (INT_MAX) +#else +#define MAX_CAPACITY (int)((SIZE_MAX / (sizeof(void*)))) +#endif + + raw_assert(size <= MAX_CAPACITY); + + if (size > (size_t) sl->capacity) { + size_t higher = (size_t) sl->capacity; + if (PREDICT_UNLIKELY(size > MAX_CAPACITY/2)) { + higher = MAX_CAPACITY; + } else { + while (size > higher) + higher *= 2; + } + sl->list = tor_reallocarray(sl->list, sizeof(void *), + ((size_t)higher)); + memset(sl->list + sl->capacity, 0, + sizeof(void *) * (higher - sl->capacity)); + sl->capacity = (int) higher; + } +#undef ASSERT_CAPACITY +#undef MAX_CAPACITY +} + +/** Append element to the end of the list. */ +void +smartlist_add(smartlist_t *sl, void *element) +{ + smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1); + sl->list[sl->num_used++] = element; +} + +/** Append each element from S2 to the end of S1. */ +void +smartlist_add_all(smartlist_t *s1, const smartlist_t *s2) +{ + size_t new_size = (size_t)s1->num_used + (size_t)s2->num_used; + raw_assert(new_size >= (size_t) s1->num_used); /* check for overflow. */ + smartlist_ensure_capacity(s1, new_size); + memcpy(s1->list + s1->num_used, s2->list, s2->num_used*sizeof(void*)); + raw_assert(new_size <= INT_MAX); /* redundant. */ + s1->num_used = (int) new_size; +} + +/** Append a copy of string to sl */ +void +smartlist_add_strdup(struct smartlist_t *sl, const char *string) +{ + char *copy; + + copy = tor_strdup(string); + + smartlist_add(sl, copy); +} + +/** Remove all elements E from sl such that E==element. Preserve + * the order of any elements before E, but elements after E can be + * rearranged. + */ +void +smartlist_remove(smartlist_t *sl, const void *element) +{ + int i; + if (element == NULL) + return; + for (i=0; i < sl->num_used; i++) + if (sl->list[i] == element) { + sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ + i--; /* so we process the new i'th element */ + sl->list[sl->num_used] = NULL; + } +} + +/** As <b>smartlist_remove</b>, but do not change the order of + * any elements not removed */ +void +smartlist_remove_keeporder(smartlist_t *sl, const void *element) +{ + int i, j, num_used_orig = sl->num_used; + if (element == NULL) + return; + + for (i=j=0; j < num_used_orig; ++j) { + if (sl->list[j] == element) { + --sl->num_used; + } else { + sl->list[i++] = sl->list[j]; + } + } +} + +/** If <b>sl</b> is nonempty, remove and return the final element. Otherwise, + * return NULL. */ +void * +smartlist_pop_last(smartlist_t *sl) +{ + raw_assert(sl); + if (sl->num_used) { + void *tmp = sl->list[--sl->num_used]; + sl->list[sl->num_used] = NULL; + return tmp; + } else + return NULL; +} + +/** Return true iff some element E of sl has E==element. + */ +int +smartlist_contains(const smartlist_t *sl, const void *element) +{ + int i; + for (i=0; i < sl->num_used; i++) + if (sl->list[i] == element) + return 1; + return 0; +} + +/** Remove the <b>idx</b>th element of sl; if idx is not the last + * element, swap the last element of sl into the <b>idx</b>th space. + */ +void +smartlist_del(smartlist_t *sl, int idx) +{ + raw_assert(sl); + raw_assert(idx>=0); + raw_assert(idx < sl->num_used); + sl->list[idx] = sl->list[--sl->num_used]; + sl->list[sl->num_used] = NULL; +} + +/** Remove the <b>idx</b>th element of sl; if idx is not the last element, + * moving all subsequent elements back one space. Return the old value + * of the <b>idx</b>th element. + */ +void +smartlist_del_keeporder(smartlist_t *sl, int idx) +{ + raw_assert(sl); + raw_assert(idx>=0); + raw_assert(idx < sl->num_used); + --sl->num_used; + if (idx < sl->num_used) + memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx)); + sl->list[sl->num_used] = NULL; +} + +/** Insert the value <b>val</b> as the new <b>idx</b>th element of + * <b>sl</b>, moving all items previously at <b>idx</b> or later + * forward one space. + */ +void +smartlist_insert(smartlist_t *sl, int idx, void *val) +{ + raw_assert(sl); + raw_assert(idx>=0); + raw_assert(idx <= sl->num_used); + if (idx == sl->num_used) { + smartlist_add(sl, val); + } else { + smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1); + /* Move other elements away */ + if (idx < sl->num_used) + memmove(sl->list + idx + 1, sl->list + idx, + sizeof(void*)*(sl->num_used-idx)); + sl->num_used++; + sl->list[idx] = val; + } +} diff --git a/src/lib/smartlist_core/smartlist_core.h b/src/lib/smartlist_core/smartlist_core.h new file mode 100644 index 0000000000..b1adf2ebdb --- /dev/null +++ b/src/lib/smartlist_core/smartlist_core.h @@ -0,0 +1,95 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SMARTLIST_CORE_H +#define TOR_SMARTLIST_CORE_H + +#include <stddef.h> + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" + +/** A resizeable list of pointers, with associated helpful functionality. + * + * The members of this struct are exposed only so that macros and inlines can + * use them; all access to smartlist internals should go through the functions + * and macros defined here. + **/ +typedef struct smartlist_t { + /** @{ */ + /** <b>list</b> has enough capacity to store exactly <b>capacity</b> elements + * before it needs to be resized. Only the first <b>num_used</b> (\<= + * capacity) elements point to valid data. + */ + void **list; + int num_used; + int capacity; + /** @} */ +} smartlist_t; + +MOCK_DECL(smartlist_t *, smartlist_new, (void)); +MOCK_DECL(void, smartlist_free_, (smartlist_t *sl)); +#define smartlist_free(sl) FREE_AND_NULL(smartlist_t, smartlist_free_, (sl)) + +void smartlist_clear(smartlist_t *sl); +void smartlist_add(smartlist_t *sl, void *element); +void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2); +void smartlist_add_strdup(struct smartlist_t *sl, const char *string); + +void smartlist_remove(smartlist_t *sl, const void *element); +void smartlist_remove_keeporder(smartlist_t *sl, const void *element); +void *smartlist_pop_last(smartlist_t *sl); + +int smartlist_contains(const smartlist_t *sl, const void *element); + +/* smartlist_choose() is defined in crypto.[ch] */ +#ifdef DEBUG_SMARTLIST +#include "lib/err/torerr.h" +#include <stdlib.h> +/** Return the number of items in sl. + */ +static inline int smartlist_len(const smartlist_t *sl); +static inline int smartlist_len(const smartlist_t *sl) { + raw_assert(sl); + return (sl)->num_used; +} +/** Return the <b>idx</b>th element of sl. + */ +static inline void *smartlist_get(const smartlist_t *sl, int idx); +static inline void *smartlist_get(const smartlist_t *sl, int idx) { + raw_assert(sl); + raw_assert(idx>=0); + raw_assert(sl->num_used > idx); + return sl->list[idx]; +} +static inline void smartlist_set(smartlist_t *sl, int idx, void *val) { + raw_assert(sl); + raw_assert(idx>=0); + raw_assert(sl->num_used > idx); + sl->list[idx] = val; +} +#else /* !(defined(DEBUG_SMARTLIST)) */ +#define smartlist_len(sl) ((sl)->num_used) +#define smartlist_get(sl, idx) ((sl)->list[idx]) +#define smartlist_set(sl, idx, val) ((sl)->list[idx] = (val)) +#endif /* defined(DEBUG_SMARTLIST) */ + +/** Exchange the elements at indices <b>idx1</b> and <b>idx2</b> of the + * smartlist <b>sl</b>. */ +static inline void smartlist_swap(smartlist_t *sl, int idx1, int idx2) +{ + if (idx1 != idx2) { + void *elt = smartlist_get(sl, idx1); + smartlist_set(sl, idx1, smartlist_get(sl, idx2)); + smartlist_set(sl, idx2, elt); + } +} + +void smartlist_del(smartlist_t *sl, int idx); +void smartlist_del_keeporder(smartlist_t *sl, int idx); +void smartlist_insert(smartlist_t *sl, int idx, void *val); + +#endif /* !defined(TOR_CONTAINER_H) */ diff --git a/src/lib/smartlist_core/smartlist_foreach.h b/src/lib/smartlist_core/smartlist_foreach.h new file mode 100644 index 0000000000..4bef36d99c --- /dev/null +++ b/src/lib/smartlist_core/smartlist_foreach.h @@ -0,0 +1,128 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SMARTLIST_FOREACH_H +#define TOR_SMARTLIST_FOREACH_H + +/** Iterate over the items in a smartlist <b>sl</b>, in order. For each item, + * assign it to a new local variable of type <b>type</b> named <b>var</b>, and + * execute the statements inside the loop body. Inside the loop, the loop + * index can be accessed as <b>var</b>_sl_idx and the length of the list can + * be accessed as <b>var</b>_sl_len. + * + * NOTE: Do not change the length of the list while the loop is in progress, + * unless you adjust the _sl_len variable correspondingly. See second example + * below. + * + * Example use: + * <pre> + * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0); + * SMARTLIST_FOREACH_BEGIN(list, char *, cp) { + * printf("%d: %s\n", cp_sl_idx, cp); + * tor_free(cp); + * } SMARTLIST_FOREACH_END(cp); + * smartlist_free(list); + * </pre> + * + * Example use (advanced): + * <pre> + * SMARTLIST_FOREACH_BEGIN(list, char *, cp) { + * if (!strcmp(cp, "junk")) { + * tor_free(cp); + * SMARTLIST_DEL_CURRENT(list, cp); + * } + * } SMARTLIST_FOREACH_END(cp); + * </pre> + */ +/* Note: these macros use token pasting, and reach into smartlist internals. + * This can make them a little daunting. Here's the approximate unpacking of + * the above examples, for entertainment value: + * + * <pre> + * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0); + * { + * int cp_sl_idx, cp_sl_len = smartlist_len(list); + * char *cp; + * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) { + * cp = smartlist_get(list, cp_sl_idx); + * printf("%d: %s\n", cp_sl_idx, cp); + * tor_free(cp); + * } + * } + * smartlist_free(list); + * </pre> + * + * <pre> + * { + * int cp_sl_idx, cp_sl_len = smartlist_len(list); + * char *cp; + * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) { + * cp = smartlist_get(list, cp_sl_idx); + * if (!strcmp(cp, "junk")) { + * tor_free(cp); + * smartlist_del(list, cp_sl_idx); + * --cp_sl_idx; + * --cp_sl_len; + * } + * } + * } + * </pre> + */ +#define SMARTLIST_FOREACH_BEGIN(sl, type, var) \ + STMT_BEGIN \ + int var ## _sl_idx, var ## _sl_len=(sl)->num_used; \ + type var; \ + for (var ## _sl_idx = 0; var ## _sl_idx < var ## _sl_len; \ + ++var ## _sl_idx) { \ + var = (sl)->list[var ## _sl_idx]; + +#define SMARTLIST_FOREACH_END(var) \ + var = NULL; \ + (void) var ## _sl_idx; \ + } STMT_END + +/** + * An alias for SMARTLIST_FOREACH_BEGIN and SMARTLIST_FOREACH_END, using + * <b>cmd</b> as the loop body. This wrapper is here for convenience with + * very short loops. + * + * By convention, we do not use this for loops which nest, or for loops over + * 10 lines or so. Use SMARTLIST_FOREACH_{BEGIN,END} for those. + */ +#define SMARTLIST_FOREACH(sl, type, var, cmd) \ + SMARTLIST_FOREACH_BEGIN(sl,type,var) { \ + cmd; \ + } SMARTLIST_FOREACH_END(var) + +/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed + * with the variable <b>var</b>, remove the current element in a way that + * won't confuse the loop. */ +#define SMARTLIST_DEL_CURRENT(sl, var) \ + STMT_BEGIN \ + smartlist_del(sl, var ## _sl_idx); \ + --var ## _sl_idx; \ + --var ## _sl_len; \ + STMT_END + +/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed + * with the variable <b>var</b>, remove the current element in a way that + * won't confuse the loop. */ +#define SMARTLIST_DEL_CURRENT_KEEPORDER(sl, var) \ + STMT_BEGIN \ + smartlist_del_keeporder(sl, var ## _sl_idx); \ + --var ## _sl_idx; \ + --var ## _sl_len; \ + STMT_END + +/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed + * with the variable <b>var</b>, replace the current element with <b>val</b>. + * Does not deallocate the current value of <b>var</b>. + */ +#define SMARTLIST_REPLACE_CURRENT(sl, var, val) \ + STMT_BEGIN \ + smartlist_set(sl, var ## _sl_idx, val); \ + STMT_END + +#endif /* !defined(TOR_SMARTLIST_FOREACH_H) */ diff --git a/src/lib/smartlist_core/smartlist_split.c b/src/lib/smartlist_core/smartlist_split.c new file mode 100644 index 0000000000..b9340e7924 --- /dev/null +++ b/src/lib/smartlist_core/smartlist_split.c @@ -0,0 +1,87 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/smartlist_core/smartlist_core.h" +#include "lib/smartlist_core/smartlist_split.h" + +#include "lib/err/torerr.h" +#include "lib/string/util_string.h" +#include "lib/string/compat_ctype.h" +#include "lib/malloc/util_malloc.h" + +#include <string.h> + +/** + * Split a string <b>str</b> along all occurrences of <b>sep</b>, + * appending the (newly allocated) split strings, in order, to + * <b>sl</b>. Return the number of strings added to <b>sl</b>. + * + * If <b>flags</b>&SPLIT_SKIP_SPACE is true, remove initial and + * trailing space from each entry. + * If <b>flags</b>&SPLIT_IGNORE_BLANK is true, remove any entries + * of length 0. + * If <b>flags</b>&SPLIT_STRIP_SPACE is true, strip spaces from each + * split string. + * + * If <b>max</b>\>0, divide the string into no more than <b>max</b> pieces. If + * <b>sep</b> is NULL, split on any sequence of horizontal space. + */ +int +smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, + int flags, int max) +{ + const char *cp, *end, *next; + int n = 0; + + raw_assert(sl); + raw_assert(str); + + cp = str; + while (1) { + if (flags&SPLIT_SKIP_SPACE) { + while (TOR_ISSPACE(*cp)) ++cp; + } + + if (max>0 && n == max-1) { + end = strchr(cp,'\0'); + } else if (sep) { + end = strstr(cp,sep); + if (!end) + end = strchr(cp,'\0'); + } else { + for (end = cp; *end && *end != '\t' && *end != ' '; ++end) + ; + } + + raw_assert(end); + + if (!*end) { + next = NULL; + } else if (sep) { + next = end+strlen(sep); + } else { + next = end+1; + while (*next == '\t' || *next == ' ') + ++next; + } + + if (flags&SPLIT_SKIP_SPACE) { + while (end > cp && TOR_ISSPACE(*(end-1))) + --end; + } + if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) { + char *string = tor_strndup(cp, end-cp); + if (flags&SPLIT_STRIP_SPACE) + tor_strstrip(string, " "); + smartlist_add(sl, string); + ++n; + } + if (!next) + break; + cp = next; + } + + return n; +} diff --git a/src/lib/smartlist_core/smartlist_split.h b/src/lib/smartlist_core/smartlist_split.h new file mode 100644 index 0000000000..8ed2abafb8 --- /dev/null +++ b/src/lib/smartlist_core/smartlist_split.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SMARTLIST_SPLIT_H +#define TOR_SMARTLIST_SPLIT_H + +#define SPLIT_SKIP_SPACE 0x01 +#define SPLIT_IGNORE_BLANK 0x02 +#define SPLIT_STRIP_SPACE 0x04 +int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, + int flags, int max); + +#endif diff --git a/src/lib/string/.may_include b/src/lib/string/.may_include new file mode 100644 index 0000000000..ec5c769831 --- /dev/null +++ b/src/lib/string/.may_include @@ -0,0 +1,10 @@ +orconfig.h +lib/cc/*.h +lib/defs/*.h +lib/err/*.h +lib/malloc/*.h +lib/ctime/*.h +lib/string/*.h + +strlcat.c +strlcpy.c diff --git a/src/lib/string/compat_ctype.c b/src/lib/string/compat_ctype.c new file mode 100644 index 0000000000..d1d4ce0ffc --- /dev/null +++ b/src/lib/string/compat_ctype.c @@ -0,0 +1,67 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/string/compat_ctype.h" + +/** + * Tables to implement ctypes-replacement TOR_IS*() functions. Each table + * has 256 bits to look up whether a character is in some set or not. This + * fails on non-ASCII platforms, but it is hard to find a platform whose + * character set is not a superset of ASCII nowadays. */ + +/**@{*/ +const uint32_t TOR_ISALPHA_TABLE[8] = + { 0, 0, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 }; +const uint32_t TOR_ISALNUM_TABLE[8] = + { 0, 0x3ff0000, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 }; +const uint32_t TOR_ISSPACE_TABLE[8] = { 0x3e00, 0x1, 0, 0, 0, 0, 0, 0 }; +const uint32_t TOR_ISXDIGIT_TABLE[8] = + { 0, 0x3ff0000, 0x7e, 0x7e, 0, 0, 0, 0 }; +const uint32_t TOR_ISDIGIT_TABLE[8] = { 0, 0x3ff0000, 0, 0, 0, 0, 0, 0 }; +const uint32_t TOR_ISPRINT_TABLE[8] = + { 0, 0xffffffff, 0xffffffff, 0x7fffffff, 0, 0, 0, 0x0 }; +const uint32_t TOR_ISUPPER_TABLE[8] = { 0, 0, 0x7fffffe, 0, 0, 0, 0, 0 }; +const uint32_t TOR_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 }; + +/** Upper-casing and lowercasing tables to map characters to upper/lowercase + * equivalents. Used by tor_toupper() and tor_tolower(). */ +/**@{*/ +const uint8_t TOR_TOUPPER_TABLE[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, + 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, + 96,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, + 80,81,82,83,84,85,86,87,88,89,90,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, +}; +const uint8_t TOR_TOLOWER_TABLE[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,95, + 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, +}; +/**@}*/ diff --git a/src/lib/string/compat_ctype.h b/src/lib/string/compat_ctype.h new file mode 100644 index 0000000000..530a10270f --- /dev/null +++ b/src/lib/string/compat_ctype.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_COMPAT_CTYPE_H +#define TOR_COMPAT_CTYPE_H + +#include "orconfig.h" +#include "lib/cc/torint.h" + +/* Much of the time when we're checking ctypes, we're doing spec compliance, + * which all assumes we're doing ASCII. */ +#define DECLARE_CTYPE_FN(name) \ + static int TOR_##name(char c); \ + extern const uint32_t TOR_##name##_TABLE[]; \ + static inline int TOR_##name(char c) { \ + uint8_t u = c; \ + return !!(TOR_##name##_TABLE[(u >> 5) & 7] & (1u << (u & 31))); \ + } +DECLARE_CTYPE_FN(ISALPHA) +DECLARE_CTYPE_FN(ISALNUM) +DECLARE_CTYPE_FN(ISSPACE) +DECLARE_CTYPE_FN(ISDIGIT) +DECLARE_CTYPE_FN(ISXDIGIT) +DECLARE_CTYPE_FN(ISPRINT) +DECLARE_CTYPE_FN(ISLOWER) +DECLARE_CTYPE_FN(ISUPPER) +extern const uint8_t TOR_TOUPPER_TABLE[]; +extern const uint8_t TOR_TOLOWER_TABLE[]; +#define TOR_TOLOWER(c) (TOR_TOLOWER_TABLE[(uint8_t)c]) +#define TOR_TOUPPER(c) (TOR_TOUPPER_TABLE[(uint8_t)c]) + +static inline int hex_decode_digit(char c); + +/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */ +static inline int +hex_decode_digit(char c) +{ + switch (c) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'A': case 'a': return 10; + case 'B': case 'b': return 11; + case 'C': case 'c': return 12; + case 'D': case 'd': return 13; + case 'E': case 'e': return 14; + case 'F': case 'f': return 15; + default: + return -1; + } +} + +#endif /* !defined(TOR_COMPAT_CTYPE_H) */ diff --git a/src/lib/string/compat_string.c b/src/lib/string/compat_string.c new file mode 100644 index 0000000000..8b063b7242 --- /dev/null +++ b/src/lib/string/compat_string.c @@ -0,0 +1,68 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/string/compat_string.h" +#include "lib/err/torerr.h" + +/* Inline the strl functions if the platform doesn't have them. */ +#ifndef HAVE_STRLCPY +#include "strlcpy.c" +#endif +#ifndef HAVE_STRLCAT +#include "strlcat.c" +#endif + +#include <stdlib.h> +#include <string.h> + +/** Helper for tor_strtok_r_impl: Advances cp past all characters in + * <b>sep</b>, and returns its new value. */ +static char * +strtok_helper(char *cp, const char *sep) +{ + if (sep[1]) { + while (*cp && strchr(sep, *cp)) + ++cp; + } else { + while (*cp && *cp == *sep) + ++cp; + } + return cp; +} + +/** Implementation of strtok_r for platforms whose coders haven't figured out + * how to write one. Hey, retrograde libc developers! You can use this code + * here for free! */ +char * +tor_strtok_r_impl(char *str, const char *sep, char **lasts) +{ + char *cp, *start; + raw_assert(*sep); + if (str) { + str = strtok_helper(str, sep); + if (!*str) + return NULL; + start = cp = *lasts = str; + } else if (!*lasts || !**lasts) { + return NULL; + } else { + start = cp = *lasts; + } + + if (sep[1]) { + while (*cp && !strchr(sep, *cp)) + ++cp; + } else { + cp = strchr(cp, *sep); + } + + if (!cp || !*cp) { + *lasts = NULL; + } else { + *cp++ = '\0'; + *lasts = strtok_helper(cp, sep); + } + return start; +} diff --git a/src/lib/string/compat_string.h b/src/lib/string/compat_string.h new file mode 100644 index 0000000000..24cd0f8b11 --- /dev/null +++ b/src/lib/string/compat_string.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_COMPAT_STRING_H +#define TOR_COMPAT_STRING_H + +#include "orconfig.h" +#include "lib/cc/compat_compiler.h" + +#include <stddef.h> + +/* ===== String compatibility */ +#ifdef _WIN32 +/* Windows names string functions differently from most other platforms. */ +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#endif + +#if defined __APPLE__ +/* On OSX 10.9 and later, the overlap-checking code for strlcat would + * appear to have a severe bug that can sometimes cause aborts in Tor. + * Instead, use the non-checking variants. This is sad. + * + * See https://trac.torproject.org/projects/tor/ticket/15205 + */ +#undef strlcat +#undef strlcpy +#endif /* defined __APPLE__ */ + +#ifndef HAVE_STRLCAT +size_t strlcat(char *dst, const char *src, size_t siz) ATTR_NONNULL((1,2)); +#endif +#ifndef HAVE_STRLCPY +size_t strlcpy(char *dst, const char *src, size_t siz) ATTR_NONNULL((1,2)); +#endif + +char *tor_strtok_r_impl(char *str, const char *sep, char **lasts); +#ifdef HAVE_STRTOK_R +#define tor_strtok_r(str, sep, lasts) strtok_r(str, sep, lasts) +#else +#define tor_strtok_r(str, sep, lasts) tor_strtok_r_impl(str, sep, lasts) +#endif + +#endif diff --git a/src/lib/string/include.am b/src/lib/string/include.am new file mode 100644 index 0000000000..edd74b8a3e --- /dev/null +++ b/src/lib/string/include.am @@ -0,0 +1,27 @@ + +noinst_LIBRARIES += src/lib/libtor-string.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-string-testing.a +endif + +src_lib_libtor_string_a_SOURCES = \ + src/lib/string/compat_ctype.c \ + src/lib/string/compat_string.c \ + src/lib/string/util_string.c \ + src/lib/string/parse_int.c \ + src/lib/string/printf.c \ + src/lib/string/scanf.c + +src_lib_libtor_string_testing_a_SOURCES = \ + $(src_lib_libtor_string_a_SOURCES) +src_lib_libtor_string_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_string_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/string/compat_ctype.h \ + src/lib/string/compat_string.h \ + src/lib/string/util_string.h \ + src/lib/string/parse_int.h \ + src/lib/string/printf.h \ + src/lib/string/scanf.h diff --git a/src/lib/string/parse_int.c b/src/lib/string/parse_int.c new file mode 100644 index 0000000000..e552730cc4 --- /dev/null +++ b/src/lib/string/parse_int.c @@ -0,0 +1,126 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/string/parse_int.h" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +/* Helper: common code to check whether the result of a strtol or strtoul or + * strtoll is correct. */ +#define CHECK_STRTOX_RESULT() \ + /* Did an overflow occur? */ \ + if (errno == ERANGE) \ + goto err; \ + /* Was at least one character converted? */ \ + if (endptr == s) \ + goto err; \ + /* Were there unexpected unconverted characters? */ \ + if (!next && *endptr) \ + goto err; \ + /* Illogical (max, min) inputs? */ \ + if (max < min) \ + goto err; \ + /* Is r within limits? */ \ + if (r < min || r > max) \ + goto err; \ + if (ok) *ok = 1; \ + if (next) *next = endptr; \ + return r; \ + err: \ + if (ok) *ok = 0; \ + if (next) *next = endptr; \ + return 0 + +/** Extract a long from the start of <b>s</b>, in the given numeric + * <b>base</b>. If <b>base</b> is 0, <b>s</b> is parsed as a decimal, + * octal, or hex number in the syntax of a C integer literal. If + * there is unconverted data and <b>next</b> is provided, set + * *<b>next</b> to the first unconverted character. An error has + * occurred if no characters are converted; or if there are + * unconverted characters and <b>next</b> is NULL; or if the parsed + * value is not between <b>min</b> and <b>max</b>. When no error + * occurs, return the parsed value and set *<b>ok</b> (if provided) to + * 1. When an error occurs, return 0 and set *<b>ok</b> (if provided) + * to 0. + */ +long +tor_parse_long(const char *s, int base, long min, long max, + int *ok, char **next) +{ + char *endptr; + long r; + + if (base < 0) { + if (ok) + *ok = 0; + return 0; + } + + errno = 0; + r = strtol(s, &endptr, base); + CHECK_STRTOX_RESULT(); +} + +/** As tor_parse_long(), but return an unsigned long. */ +unsigned long +tor_parse_ulong(const char *s, int base, unsigned long min, + unsigned long max, int *ok, char **next) +{ + char *endptr; + unsigned long r; + + if (base < 0) { + if (ok) + *ok = 0; + return 0; + } + + errno = 0; + r = strtoul(s, &endptr, base); + CHECK_STRTOX_RESULT(); +} + +/** As tor_parse_long(), but return a double. */ +double +tor_parse_double(const char *s, double min, double max, int *ok, char **next) +{ + char *endptr; + double r; + + errno = 0; + r = strtod(s, &endptr); + CHECK_STRTOX_RESULT(); +} + +/** As tor_parse_long, but return a uint64_t. Only base 10 is guaranteed to + * work for now. */ +uint64_t +tor_parse_uint64(const char *s, int base, uint64_t min, + uint64_t max, int *ok, char **next) +{ + char *endptr; + uint64_t r; + + if (base < 0) { + if (ok) + *ok = 0; + return 0; + } + + errno = 0; +#ifdef HAVE_STRTOULL + r = (uint64_t)strtoull(s, &endptr, base); +#elif defined(_WIN32) + r = (uint64_t)_strtoui64(s, &endptr, base); +#elif SIZEOF_LONG == 8 + r = (uint64_t)strtoul(s, &endptr, base); +#else +#error "I don't know how to parse 64-bit numbers." +#endif /* defined(HAVE_STRTOULL) || ... */ + + CHECK_STRTOX_RESULT(); +} diff --git a/src/lib/string/parse_int.h b/src/lib/string/parse_int.h new file mode 100644 index 0000000000..6f56fc32a8 --- /dev/null +++ b/src/lib/string/parse_int.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_PARSE_INT_H +#define TOR_PARSE_INT_H + +#include "lib/cc/torint.h" + +long tor_parse_long(const char *s, int base, long min, + long max, int *ok, char **next); +unsigned long tor_parse_ulong(const char *s, int base, unsigned long min, + unsigned long max, int *ok, char **next); +double tor_parse_double(const char *s, double min, double max, int *ok, + char **next); +uint64_t tor_parse_uint64(const char *s, int base, uint64_t min, + uint64_t max, int *ok, char **next); + +#endif diff --git a/src/lib/string/printf.c b/src/lib/string/printf.c new file mode 100644 index 0000000000..4443e25fb4 --- /dev/null +++ b/src/lib/string/printf.c @@ -0,0 +1,152 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/string/printf.h" +#include "lib/err/torerr.h" +#include "lib/cc/torint.h" +#include "lib/malloc/util_malloc.h" + +#include <stdlib.h> +#include <stdio.h> + +/** Replacement for snprintf. Differs from platform snprintf in two + * ways: First, always NUL-terminates its output. Second, always + * returns -1 if the result is truncated. (Note that this return + * behavior does <i>not</i> conform to C99; it just happens to be + * easier to emulate "return -1" with conformant implementations than + * it is to emulate "return number that would be written" with + * non-conformant implementations.) */ +int +tor_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int r; + va_start(ap,format); + r = tor_vsnprintf(str,size,format,ap); + va_end(ap); + return r; +} + +/** Replacement for vsnprintf; behavior differs as tor_snprintf differs from + * snprintf. + */ +int +tor_vsnprintf(char *str, size_t size, const char *format, va_list args) +{ + int r; + if (size == 0) + return -1; /* no place for the NUL */ + if (size > SIZE_T_CEILING) + return -1; +#ifdef _WIN32 + r = _vsnprintf(str, size, format, args); +#else + r = vsnprintf(str, size, format, args); +#endif + str[size-1] = '\0'; + if (r < 0 || r >= (ssize_t)size) + return -1; + return r; +} + +/** + * Portable asprintf implementation. Does a printf() into a newly malloc'd + * string. Sets *<b>strp</b> to this string, and returns its length (not + * including the terminating NUL character). + * + * You can treat this function as if its implementation were something like + <pre> + char buf[_INFINITY_]; + tor_snprintf(buf, sizeof(buf), fmt, args); + *strp = tor_strdup(buf); + return strlen(*strp): + </pre> + * Where _INFINITY_ is an imaginary constant so big that any string can fit + * into it. + */ +int +tor_asprintf(char **strp, const char *fmt, ...) +{ + int r; + va_list args; + va_start(args, fmt); + r = tor_vasprintf(strp, fmt, args); + va_end(args); + if (!*strp || r < 0) { + /* LCOV_EXCL_START */ + raw_assert_unreached_msg("Internal error in asprintf"); + /* LCOV_EXCL_STOP */ + } + return r; +} + +/** + * Portable vasprintf implementation. Does a printf() into a newly malloc'd + * string. Differs from regular vasprintf in the same ways that + * tor_asprintf() differs from regular asprintf. + */ +int +tor_vasprintf(char **strp, const char *fmt, va_list args) +{ + /* use a temporary variable in case *strp is in args. */ + char *strp_tmp=NULL; +#ifdef HAVE_VASPRINTF + /* If the platform gives us one, use it. */ + int r = vasprintf(&strp_tmp, fmt, args); + if (r < 0) + *strp = NULL; + else + *strp = strp_tmp; + return r; +#elif defined(HAVE__VSCPRINTF) + /* On Windows, _vsnprintf won't tell us the length of the string if it + * overflows, so we need to use _vcsprintf to tell how much to allocate */ + int len, r; + va_list tmp_args; + va_copy(tmp_args, args); + len = _vscprintf(fmt, tmp_args); + va_end(tmp_args); + if (len < 0) { + *strp = NULL; + return -1; + } + strp_tmp = tor_malloc(len + 1); + r = _vsnprintf(strp_tmp, len+1, fmt, args); + if (r != len) { + tor_free(strp_tmp); + *strp = NULL; + return -1; + } + *strp = strp_tmp; + return len; +#else + /* Everywhere else, we have a decent vsnprintf that tells us how many + * characters we need. We give it a try on a short buffer first, since + * it might be nice to avoid the second vsnprintf call. + */ + char buf[128]; + int len, r; + va_list tmp_args; + va_copy(tmp_args, args); + /* vsnprintf() was properly checked but tor_vsnprintf() available so + * why not use it? */ + len = tor_vsnprintf(buf, sizeof(buf), fmt, tmp_args); + va_end(tmp_args); + if (len < (int)sizeof(buf)) { + *strp = tor_strdup(buf); + return len; + } + strp_tmp = tor_malloc(len+1); + /* use of tor_vsnprintf() will ensure string is null terminated */ + r = tor_vsnprintf(strp_tmp, len+1, fmt, args); + if (r != len) { + tor_free(strp_tmp); + *strp = NULL; + return -1; + } + *strp = strp_tmp; + return len; +#endif /* defined(HAVE_VASPRINTF) || ... */ +} diff --git a/src/lib/string/printf.h b/src/lib/string/printf.h new file mode 100644 index 0000000000..2f46206545 --- /dev/null +++ b/src/lib/string/printf.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_UTIL_PRINTF_H +#define TOR_UTIL_PRINTF_H + +#include "orconfig.h" +#include "lib/cc/compat_compiler.h" + +#include <stdarg.h> +#include <stddef.h> + +int tor_snprintf(char *str, size_t size, const char *format, ...) + CHECK_PRINTF(3,4) ATTR_NONNULL((1,3)); +int tor_vsnprintf(char *str, size_t size, const char *format, va_list args) + CHECK_PRINTF(3,0) ATTR_NONNULL((1,3)); + +int tor_asprintf(char **strp, const char *fmt, ...) + CHECK_PRINTF(2,3); +int tor_vasprintf(char **strp, const char *fmt, va_list args) + CHECK_PRINTF(2,0); + +#endif /* !defined(TOR_UTIL_STRING_H) */ diff --git a/src/lib/string/scanf.c b/src/lib/string/scanf.c new file mode 100644 index 0000000000..0c5082799c --- /dev/null +++ b/src/lib/string/scanf.c @@ -0,0 +1,312 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/string/scanf.h" +#include "lib/string/compat_ctype.h" +#include "lib/cc/torint.h" +#include "lib/err/torerr.h" + +#include <stdlib.h> + +#define MAX_SCANF_WIDTH 9999 + +/** Helper: given an ASCII-encoded decimal digit, return its numeric value. + * NOTE: requires that its input be in-bounds. */ +static int +digit_to_num(char d) +{ + int num = ((int)d) - (int)'0'; + raw_assert(num <= 9 && num >= 0); + return num; +} + +/** Helper: Read an unsigned int from *<b>bufp</b> of up to <b>width</b> + * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On + * success, store the result in <b>out</b>, advance bufp to the next + * character, and return 0. On failure, return -1. */ +static int +scan_unsigned(const char **bufp, unsigned long *out, int width, unsigned base) +{ + unsigned long result = 0; + int scanned_so_far = 0; + const int hex = base==16; + raw_assert(base == 10 || base == 16); + if (!bufp || !*bufp || !out) + return -1; + if (width<0) + width=MAX_SCANF_WIDTH; + + while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp)) + && scanned_so_far < width) { + unsigned digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++); + // Check for overflow beforehand, without actually causing any overflow + // This preserves functionality on compilers that don't wrap overflow + // (i.e. that trap or optimise away overflow) + // result * base + digit > ULONG_MAX + // result * base > ULONG_MAX - digit + if (result > (ULONG_MAX - digit)/base) + return -1; /* Processing this digit would overflow */ + result = result * base + digit; + ++scanned_so_far; + } + + if (!scanned_so_far) /* No actual digits scanned */ + return -1; + + *out = result; + return 0; +} + +/** Helper: Read an signed int from *<b>bufp</b> of up to <b>width</b> + * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On + * success, store the result in <b>out</b>, advance bufp to the next + * character, and return 0. On failure, return -1. */ +static int +scan_signed(const char **bufp, long *out, int width) +{ + int neg = 0; + unsigned long result = 0; + + if (!bufp || !*bufp || !out) + return -1; + if (width<0) + width=MAX_SCANF_WIDTH; + + if (**bufp == '-') { + neg = 1; + ++*bufp; + --width; + } + + if (scan_unsigned(bufp, &result, width, 10) < 0) + return -1; + + if (neg && result > 0) { + if (result > ((unsigned long)LONG_MAX) + 1) + return -1; /* Underflow */ + else if (result == ((unsigned long)LONG_MAX) + 1) + *out = LONG_MIN; + else { + /* We once had a far more clever no-overflow conversion here, but + * some versions of GCC apparently ran it into the ground. Now + * we just check for LONG_MIN explicitly. + */ + *out = -(long)result; + } + } else { + if (result > LONG_MAX) + return -1; /* Overflow */ + *out = (long)result; + } + + return 0; +} + +/** Helper: Read a decimal-formatted double from *<b>bufp</b> of up to + * <b>width</b> characters. (Handle arbitrary width if <b>width</b> is less + * than 0.) On success, store the result in <b>out</b>, advance bufp to the + * next character, and return 0. On failure, return -1. */ +static int +scan_double(const char **bufp, double *out, int width) +{ + int neg = 0; + double result = 0; + int scanned_so_far = 0; + + if (!bufp || !*bufp || !out) + return -1; + if (width<0) + width=MAX_SCANF_WIDTH; + + if (**bufp == '-') { + neg = 1; + ++*bufp; + } + + while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) { + const int digit = digit_to_num(*(*bufp)++); + result = result * 10 + digit; + ++scanned_so_far; + } + if (**bufp == '.') { + double fracval = 0, denominator = 1; + ++*bufp; + ++scanned_so_far; + while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) { + const int digit = digit_to_num(*(*bufp)++); + fracval = fracval * 10 + digit; + denominator *= 10; + ++scanned_so_far; + } + result += fracval / denominator; + } + + if (!scanned_so_far) /* No actual digits scanned */ + return -1; + + *out = neg ? -result : result; + return 0; +} + +/** Helper: copy up to <b>width</b> non-space characters from <b>bufp</b> to + * <b>out</b>. Make sure <b>out</b> is nul-terminated. Advance <b>bufp</b> + * to the next non-space character or the EOS. */ +static int +scan_string(const char **bufp, char *out, int width) +{ + int scanned_so_far = 0; + if (!bufp || !out || width < 0) + return -1; + while (**bufp && ! TOR_ISSPACE(**bufp) && scanned_so_far < width) { + *out++ = *(*bufp)++; + ++scanned_so_far; + } + *out = '\0'; + return 0; +} + +/** Locale-independent, minimal, no-surprises scanf variant, accepting only a + * restricted pattern format. For more info on what it supports, see + * tor_sscanf() documentation. */ +int +tor_vsscanf(const char *buf, const char *pattern, va_list ap) +{ + int n_matched = 0; + + while (*pattern) { + if (*pattern != '%') { + if (*buf == *pattern) { + ++buf; + ++pattern; + continue; + } else { + return n_matched; + } + } else { + int width = -1; + int longmod = 0; + ++pattern; + if (TOR_ISDIGIT(*pattern)) { + width = digit_to_num(*pattern++); + while (TOR_ISDIGIT(*pattern)) { + width *= 10; + width += digit_to_num(*pattern++); + if (width > MAX_SCANF_WIDTH) + return -1; + } + if (!width) /* No zero-width things. */ + return -1; + } + if (*pattern == 'l') { + longmod = 1; + ++pattern; + } + if (*pattern == 'u' || *pattern == 'x') { + unsigned long u; + const int base = (*pattern == 'u') ? 10 : 16; + if (!*buf) + return n_matched; + if (scan_unsigned(&buf, &u, width, base)<0) + return n_matched; + if (longmod) { + unsigned long *out = va_arg(ap, unsigned long *); + *out = u; + } else { + unsigned *out = va_arg(ap, unsigned *); + if (u > UINT_MAX) + return n_matched; + *out = (unsigned) u; + } + ++pattern; + ++n_matched; + } else if (*pattern == 'f') { + double *d = va_arg(ap, double *); + if (!longmod) + return -1; /* float not supported */ + if (!*buf) + return n_matched; + if (scan_double(&buf, d, width)<0) + return n_matched; + ++pattern; + ++n_matched; + } else if (*pattern == 'd') { + long lng=0; + if (scan_signed(&buf, &lng, width)<0) + return n_matched; + if (longmod) { + long *out = va_arg(ap, long *); + *out = lng; + } else { + int *out = va_arg(ap, int *); +#if LONG_MAX > INT_MAX + if (lng < INT_MIN || lng > INT_MAX) + return n_matched; +#endif + *out = (int)lng; + } + ++pattern; + ++n_matched; + } else if (*pattern == 's') { + char *s = va_arg(ap, char *); + if (longmod) + return -1; + if (width < 0) + return -1; + if (scan_string(&buf, s, width)<0) + return n_matched; + ++pattern; + ++n_matched; + } else if (*pattern == 'c') { + char *ch = va_arg(ap, char *); + if (longmod) + return -1; + if (width != -1) + return -1; + if (!*buf) + return n_matched; + *ch = *buf++; + ++pattern; + ++n_matched; + } else if (*pattern == '%') { + if (*buf != '%') + return n_matched; + if (longmod) + return -1; + ++buf; + ++pattern; + } else { + return -1; /* Unrecognized pattern component. */ + } + } + } + + return n_matched; +} + +/** Minimal sscanf replacement: parse <b>buf</b> according to <b>pattern</b> + * and store the results in the corresponding argument fields. Differs from + * sscanf in that: + * <ul><li>It only handles %u, %lu, %x, %lx, %[NUM]s, %d, %ld, %lf, and %c. + * <li>It only handles decimal inputs for %lf. (12.3, not 1.23e1) + * <li>It does not handle arbitrarily long widths. + * <li>Numbers do not consume any space characters. + * <li>It is locale-independent. + * <li>%u and %x do not consume any space. + * <li>It returns -1 on malformed patterns.</ul> + * + * (As with other locale-independent functions, we need this to parse data that + * is in ASCII without worrying that the C library's locale-handling will make + * miscellaneous characters look like numbers, spaces, and so on.) + */ +int +tor_sscanf(const char *buf, const char *pattern, ...) +{ + int r; + va_list ap; + va_start(ap, pattern); + r = tor_vsscanf(buf, pattern, ap); + va_end(ap); + return r; +} diff --git a/src/lib/string/scanf.h b/src/lib/string/scanf.h new file mode 100644 index 0000000000..9cfa9cc6c1 --- /dev/null +++ b/src/lib/string/scanf.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_UTIL_SCANF_H +#define TOR_UTIL_SCANF_H + +#include "orconfig.h" +#include "lib/cc/compat_compiler.h" + +#include <stdarg.h> + +int tor_vsscanf(const char *buf, const char *pattern, va_list ap) \ + CHECK_SCANF(2, 0); +int tor_sscanf(const char *buf, const char *pattern, ...) + CHECK_SCANF(2, 3); + +#endif /* !defined(TOR_UTIL_STRING_H) */ diff --git a/src/lib/string/util_string.c b/src/lib/string/util_string.c new file mode 100644 index 0000000000..e8ed3d4f54 --- /dev/null +++ b/src/lib/string/util_string.c @@ -0,0 +1,448 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/string/util_string.h" +#include "lib/string/compat_ctype.h" +#include "lib/err/torerr.h" +#include "lib/ctime/di_ops.h" +#include "lib/defs/digest_sizes.h" + +#include <string.h> +#include <stdlib.h> + +/** Given <b>hlen</b> bytes at <b>haystack</b> and <b>nlen</b> bytes at + * <b>needle</b>, return a pointer to the first occurrence of the needle + * within the haystack, or NULL if there is no such occurrence. + * + * This function is <em>not</em> timing-safe. + * + * Requires that <b>nlen</b> be greater than zero. + */ +const void * +tor_memmem(const void *_haystack, size_t hlen, + const void *_needle, size_t nlen) +{ +#if defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2) + raw_assert(nlen); + return memmem(_haystack, hlen, _needle, nlen); +#else + /* This isn't as fast as the GLIBC implementation, but it doesn't need to + * be. */ + const char *p, *last_possible_start; + const char *haystack = (const char*)_haystack; + const char *needle = (const char*)_needle; + char first; + raw_assert(nlen); + + if (nlen > hlen) + return NULL; + + p = haystack; + /* Last position at which the needle could start. */ + last_possible_start = haystack + hlen - nlen; + first = *(const char*)needle; + while ((p = memchr(p, first, last_possible_start + 1 - p))) { + if (fast_memeq(p, needle, nlen)) + return p; + if (++p > last_possible_start) { + /* This comparison shouldn't be necessary, since if p was previously + * equal to last_possible_start, the next memchr call would be + * "memchr(p, first, 0)", which will return NULL. But it clarifies the + * logic. */ + return NULL; + } + } + return NULL; +#endif /* defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2) */ +} + +const void * +tor_memstr(const void *haystack, size_t hlen, const char *needle) +{ + return tor_memmem(haystack, hlen, needle, strlen(needle)); +} + +/** Return true iff the 'len' bytes at 'mem' are all zero. */ +int +tor_mem_is_zero(const char *mem, size_t len) +{ + static const char ZERO[] = { + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + }; + while (len >= sizeof(ZERO)) { + /* It's safe to use fast_memcmp here, since the very worst thing an + * attacker could learn is how many initial bytes of a secret were zero */ + if (fast_memcmp(mem, ZERO, sizeof(ZERO))) + return 0; + len -= sizeof(ZERO); + mem += sizeof(ZERO); + } + /* Deal with leftover bytes. */ + if (len) + return fast_memeq(mem, ZERO, len); + + return 1; +} + +/** Return true iff the DIGEST_LEN bytes in digest are all zero. */ +int +tor_digest_is_zero(const char *digest) +{ + static const uint8_t ZERO_DIGEST[] = { + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 + }; + return tor_memeq(digest, ZERO_DIGEST, DIGEST_LEN); +} + +/** Return true iff the DIGEST256_LEN bytes in digest are all zero. */ +int +tor_digest256_is_zero(const char *digest) +{ + return tor_mem_is_zero(digest, DIGEST256_LEN); +} + +/** Remove from the string <b>s</b> every character which appears in + * <b>strip</b>. */ +void +tor_strstrip(char *s, const char *strip) +{ + char *readp = s; + while (*readp) { + if (strchr(strip, *readp)) { + ++readp; + } else { + *s++ = *readp++; + } + } + *s = '\0'; +} + +/** Convert all alphabetic characters in the nul-terminated string <b>s</b> to + * lowercase. */ +void +tor_strlower(char *s) +{ + while (*s) { + *s = TOR_TOLOWER(*s); + ++s; + } +} + +/** Convert all alphabetic characters in the nul-terminated string <b>s</b> to + * lowercase. */ +void +tor_strupper(char *s) +{ + while (*s) { + *s = TOR_TOUPPER(*s); + ++s; + } +} + +/** Return 1 if every character in <b>s</b> is printable, else return 0. + */ +int +tor_strisprint(const char *s) +{ + while (*s) { + if (!TOR_ISPRINT(*s)) + return 0; + s++; + } + return 1; +} + +/** Return 1 if no character in <b>s</b> is uppercase, else return 0. + */ +int +tor_strisnonupper(const char *s) +{ + while (*s) { + if (TOR_ISUPPER(*s)) + return 0; + s++; + } + return 1; +} + +/** Return true iff every character in <b>s</b> is whitespace space; else + * return false. */ +int +tor_strisspace(const char *s) +{ + while (*s) { + if (!TOR_ISSPACE(*s)) + return 0; + s++; + } + return 1; +} + +/** As strcmp, except that either string may be NULL. The NULL string is + * considered to be before any non-NULL string. */ +int +strcmp_opt(const char *s1, const char *s2) +{ + if (!s1) { + if (!s2) + return 0; + else + return -1; + } else if (!s2) { + return 1; + } else { + return strcmp(s1, s2); + } +} + +/** Compares the first strlen(s2) characters of s1 with s2. Returns as for + * strcmp. + */ +int +strcmpstart(const char *s1, const char *s2) +{ + size_t n = strlen(s2); + return strncmp(s1, s2, n); +} + +/** Compare the s1_len-byte string <b>s1</b> with <b>s2</b>, + * without depending on a terminating nul in s1. Sorting order is first by + * length, then lexically; return values are as for strcmp. + */ +int +strcmp_len(const char *s1, const char *s2, size_t s1_len) +{ + size_t s2_len = strlen(s2); + if (s1_len < s2_len) + return -1; + if (s1_len > s2_len) + return 1; + return fast_memcmp(s1, s2, s2_len); +} + +/** Compares the first strlen(s2) characters of s1 with s2. Returns as for + * strcasecmp. + */ +int +strcasecmpstart(const char *s1, const char *s2) +{ + size_t n = strlen(s2); + return strncasecmp(s1, s2, n); +} + +/** Compare the value of the string <b>prefix</b> with the start of the + * <b>memlen</b>-byte memory chunk at <b>mem</b>. Return as for strcmp. + * + * [As fast_memcmp(mem, prefix, strlen(prefix)) but returns -1 if memlen is + * less than strlen(prefix).] + */ +int +fast_memcmpstart(const void *mem, size_t memlen, + const char *prefix) +{ + size_t plen = strlen(prefix); + if (memlen < plen) + return -1; + return fast_memcmp(mem, prefix, plen); +} + +/** Compares the last strlen(s2) characters of s1 with s2. Returns as for + * strcmp. + */ +int +strcmpend(const char *s1, const char *s2) +{ + size_t n1 = strlen(s1), n2 = strlen(s2); + if (n2>n1) + return strcmp(s1,s2); + else + return strncmp(s1+(n1-n2), s2, n2); +} + +/** Compares the last strlen(s2) characters of s1 with s2. Returns as for + * strcasecmp. + */ +int +strcasecmpend(const char *s1, const char *s2) +{ + size_t n1 = strlen(s1), n2 = strlen(s2); + if (n2>n1) /* then they can't be the same; figure out which is bigger */ + return strcasecmp(s1,s2); + else + return strncasecmp(s1+(n1-n2), s2, n2); +} + +/** Return a pointer to the first char of s that is not whitespace and + * not a comment, or to the terminating NUL if no such character exists. + */ +const char * +eat_whitespace(const char *s) +{ + raw_assert(s); + + while (1) { + switch (*s) { + case '\0': + default: + return s; + case ' ': + case '\t': + case '\n': + case '\r': + ++s; + break; + case '#': + ++s; + while (*s && *s != '\n') + ++s; + } + } +} + +/** Return a pointer to the first char of s that is not whitespace and + * not a comment, or to the terminating NUL if no such character exists. + */ +const char * +eat_whitespace_eos(const char *s, const char *eos) +{ + raw_assert(s); + raw_assert(eos && s <= eos); + + while (s < eos) { + switch (*s) { + case '\0': + default: + return s; + case ' ': + case '\t': + case '\n': + case '\r': + ++s; + break; + case '#': + ++s; + while (s < eos && *s && *s != '\n') + ++s; + } + } + return s; +} + +/** Return a pointer to the first char of s that is not a space or a tab + * or a \\r, or to the terminating NUL if no such character exists. */ +const char * +eat_whitespace_no_nl(const char *s) +{ + while (*s == ' ' || *s == '\t' || *s == '\r') + ++s; + return s; +} + +/** As eat_whitespace_no_nl, but stop at <b>eos</b> whether we have + * found a non-whitespace character or not. */ +const char * +eat_whitespace_eos_no_nl(const char *s, const char *eos) +{ + while (s < eos && (*s == ' ' || *s == '\t' || *s == '\r')) + ++s; + return s; +} + +/** Return a pointer to the first char of s that is whitespace or <b>#</b>, + * or to the terminating NUL if no such character exists. + */ +const char * +find_whitespace(const char *s) +{ + /* tor_assert(s); */ + while (1) { + switch (*s) + { + case '\0': + case '#': + case ' ': + case '\r': + case '\n': + case '\t': + return s; + default: + ++s; + } + } +} + +/** As find_whitespace, but stop at <b>eos</b> whether we have found a + * whitespace or not. */ +const char * +find_whitespace_eos(const char *s, const char *eos) +{ + /* tor_assert(s); */ + while (s < eos) { + switch (*s) + { + case '\0': + case '#': + case ' ': + case '\r': + case '\n': + case '\t': + return s; + default: + ++s; + } + } + return s; +} + +/** Return the first occurrence of <b>needle</b> in <b>haystack</b> that + * occurs at the start of a line (that is, at the beginning of <b>haystack</b> + * or immediately after a newline). Return NULL if no such string is found. + */ +const char * +find_str_at_start_of_line(const char *haystack, const char *needle) +{ + size_t needle_len = strlen(needle); + + do { + if (!strncmp(haystack, needle, needle_len)) + return haystack; + + haystack = strchr(haystack, '\n'); + if (!haystack) + return NULL; + else + ++haystack; + } while (*haystack); + + return NULL; +} + +/** Returns true if <b>string</b> could be a C identifier. + A C identifier must begin with a letter or an underscore and the + rest of its characters can be letters, numbers or underscores. No + length limit is imposed. */ +int +string_is_C_identifier(const char *string) +{ + size_t iter; + size_t length = strlen(string); + if (!length) + return 0; + + for (iter = 0; iter < length ; iter++) { + if (iter == 0) { + if (!(TOR_ISALPHA(string[iter]) || + string[iter] == '_')) + return 0; + } else { + if (!(TOR_ISALPHA(string[iter]) || + TOR_ISDIGIT(string[iter]) || + string[iter] == '_')) + return 0; + } + } + + return 1; +} diff --git a/src/lib/string/util_string.h b/src/lib/string/util_string.h new file mode 100644 index 0000000000..bdc2e77cea --- /dev/null +++ b/src/lib/string/util_string.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_UTIL_STRING_H +#define TOR_UTIL_STRING_H + +#include "orconfig.h" +#include "lib/cc/compat_compiler.h" + +#include <stddef.h> + +const void *tor_memmem(const void *haystack, size_t hlen, const void *needle, + size_t nlen) ATTR_NONNULL((1,3)); +const void *tor_memstr(const void *haystack, size_t hlen, + const char *needle) ATTR_NONNULL((1,3)); +int tor_mem_is_zero(const char *mem, size_t len); +int tor_digest_is_zero(const char *digest); +int tor_digest256_is_zero(const char *digest); + +/** Allowable characters in a hexadecimal string. */ +#define HEX_CHARACTERS "0123456789ABCDEFabcdef" +void tor_strlower(char *s) ATTR_NONNULL((1)); +void tor_strupper(char *s) ATTR_NONNULL((1)); +int tor_strisprint(const char *s) ATTR_NONNULL((1)); +int tor_strisnonupper(const char *s) ATTR_NONNULL((1)); +int tor_strisspace(const char *s); +int strcmp_opt(const char *s1, const char *s2); +int strcmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2)); +int strcmp_len(const char *s1, const char *s2, size_t len) ATTR_NONNULL((1,2)); +int strcasecmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2)); +int strcmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2)); +int strcasecmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2)); +int fast_memcmpstart(const void *mem, size_t memlen, const char *prefix); + +void tor_strstrip(char *s, const char *strip) ATTR_NONNULL((1,2)); + +const char *eat_whitespace(const char *s); +const char *eat_whitespace_eos(const char *s, const char *eos); +const char *eat_whitespace_no_nl(const char *s); +const char *eat_whitespace_eos_no_nl(const char *s, const char *eos); +const char *find_whitespace(const char *s); +const char *find_whitespace_eos(const char *s, const char *eos); +const char *find_str_at_start_of_line(const char *haystack, + const char *needle); + +int string_is_C_identifier(const char *string); + +#endif /* !defined(TOR_UTIL_STRING_H) */ diff --git a/src/lib/term/.may_include b/src/lib/term/.may_include new file mode 100644 index 0000000000..c93a06e59e --- /dev/null +++ b/src/lib/term/.may_include @@ -0,0 +1,9 @@ +orconfig.h + +lib/cc/*.h +lib/log/*.h +lib/term/*.h +lib/malloc/*.h + +# From src/ext +tor_readpassphrase.h diff --git a/src/lib/term/getpass.c b/src/lib/term/getpass.c new file mode 100644 index 0000000000..10c99914f8 --- /dev/null +++ b/src/lib/term/getpass.c @@ -0,0 +1,115 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/term/getpass.h" + +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" + +#ifdef _WIN32 +#include <windows.h> +#include <conio.h> +#include <wchar.h> +/* Some mingw headers lack these. :p */ +#if defined(HAVE_DECL__GETWCH) && !HAVE_DECL__GETWCH +wint_t _getwch(void); +#endif +#ifndef WEOF +#define WEOF (wchar_t)(0xFFFF) +#endif +#if defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY +static inline void +SecureZeroMemory(PVOID ptr, SIZE_T cnt) +{ + volatile char *vcptr = (volatile char*)ptr; + while (cnt--) + *vcptr++ = 0; +} +#endif /* defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY */ +#elif defined(HAVE_READPASSPHRASE_H) +#include <readpassphrase.h> +#else +#include "tor_readpassphrase.h" +#endif /* defined(_WIN32) || ... */ + +#include <stdlib.h> +#include <string.h> + +/** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b> + * bytes of passphrase into <b>output</b>. Return the number of bytes in + * the passphrase, excluding terminating NUL. + */ +ssize_t +tor_getpass(const char *prompt, char *output, size_t buflen) +{ + tor_assert(buflen <= SSIZE_MAX); + tor_assert(buflen >= 1); +#if defined(HAVE_READPASSPHRASE) + char *pwd = readpassphrase(prompt, output, buflen, RPP_ECHO_OFF); + if (pwd == NULL) + return -1; + return strlen(pwd); +#elif defined(_WIN32) + int r = -1; + while (*prompt) { + _putch(*prompt++); + } + + tor_assert(buflen <= INT_MAX); + wchar_t *buf = tor_calloc(buflen, sizeof(wchar_t)); + + wchar_t *ptr = buf, *lastch = buf + buflen - 1; + while (ptr < lastch) { + wint_t ch = _getwch(); + switch (ch) { + case '\r': + case '\n': + case WEOF: + goto done_reading; + case 3: + goto done; /* Can't actually read ctrl-c this way. */ + case '\b': + if (ptr > buf) + --ptr; + continue; + case 0: + case 0xe0: + ch = _getwch(); /* Ignore; this is a function or arrow key */ + break; + default: + *ptr++ = ch; + break; + } + } + done_reading: + ; + +#ifndef WC_ERR_INVALID_CHARS +#define WC_ERR_INVALID_CHARS 0x80 +#endif + + /* Now convert it to UTF-8 */ + r = WideCharToMultiByte(CP_UTF8, + WC_NO_BEST_FIT_CHARS|WC_ERR_INVALID_CHARS, + buf, (int)(ptr-buf), + output, (int)(buflen-1), + NULL, NULL); + if (r <= 0) { + r = -1; + goto done; + } + + tor_assert(r < (int)buflen); + + output[r] = 0; + + done: + SecureZeroMemory(buf, sizeof(wchar_t)*buflen); + tor_free(buf); + return r; +#else +#error "No implementation for tor_getpass found!" +#endif /* defined(HAVE_READPASSPHRASE) || ... */ +} diff --git a/src/lib/term/getpass.h b/src/lib/term/getpass.h new file mode 100644 index 0000000000..9d03f7036c --- /dev/null +++ b/src/lib/term/getpass.h @@ -0,0 +1,13 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_GETPASS_H +#define TOR_GETPASS_H + +#include "lib/cc/torint.h" + +ssize_t tor_getpass(const char *prompt, char *output, size_t buflen); + +#endif diff --git a/src/lib/term/include.am b/src/lib/term/include.am new file mode 100644 index 0000000000..55fe548ebc --- /dev/null +++ b/src/lib/term/include.am @@ -0,0 +1,24 @@ + +noinst_LIBRARIES += src/lib/libtor-term.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-term-testing.a +endif + +if BUILD_READPASSPHRASE_C +readpassphrase_source=src/ext/readpassphrase.c +else +readpassphrase_source= +endif + +src_lib_libtor_term_a_SOURCES = \ + src/lib/term/getpass.c \ + $(readpassphrase_source) + +src_lib_libtor_term_testing_a_SOURCES = \ + $(src_lib_libtor_term_a_SOURCES) +src_lib_libtor_term_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_term_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/term/getpass.h diff --git a/src/lib/testsupport/.may_include b/src/lib/testsupport/.may_include new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/src/lib/testsupport/.may_include diff --git a/src/lib/testsupport/include.am b/src/lib/testsupport/include.am new file mode 100644 index 0000000000..b2aa620985 --- /dev/null +++ b/src/lib/testsupport/include.am @@ -0,0 +1,3 @@ + +noinst_HEADERS += \ + src/lib/testsupport/testsupport.h diff --git a/src/common/testsupport.h b/src/lib/testsupport/testsupport.h index a3f2ff91ed..9a55d306fc 100644 --- a/src/common/testsupport.h +++ b/src/lib/testsupport/testsupport.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TESTSUPPORT_H diff --git a/src/lib/thread/.may_include b/src/lib/thread/.may_include new file mode 100644 index 0000000000..93ad0cd734 --- /dev/null +++ b/src/lib/thread/.may_include @@ -0,0 +1,6 @@ +orconfig.h +lib/cc/*.h +lib/lock/*.h +lib/log/*.h +lib/testsupport/*.h +lib/thread/*.h diff --git a/src/common/compat_pthreads.c b/src/lib/thread/compat_pthreads.c index 002274c469..246c6254bb 100644 --- a/src/common/compat_pthreads.c +++ b/src/lib/thread/compat_pthreads.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,13 +11,16 @@ */ #include "orconfig.h" +#include "lib/thread/threads.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +#include <sys/time.h> #include <pthread.h> #include <signal.h> #include <time.h> - -#include "compat.h" -#include "torlog.h" -#include "util.h" +#include <errno.h> +#include <string.h> /** Wraps a void (*)(void*) function and its argument so we can * invoke them in a way pthreads would expect. @@ -91,88 +94,6 @@ spawn_exit(void) pthread_exit(NULL); } -/** A mutex attribute that we're going to use to tell pthreads that we want - * "recursive" mutexes (i.e., once we can re-lock if we're already holding - * them.) */ -static pthread_mutexattr_t attr_recursive; - -/** Initialize <b>mutex</b> so it can be locked. Every mutex must be set - * up with tor_mutex_init() or tor_mutex_new(); not both. */ -void -tor_mutex_init(tor_mutex_t *mutex) -{ - if (PREDICT_UNLIKELY(!threads_initialized)) - tor_threads_init(); // LCOV_EXCL_LINE - const int err = pthread_mutex_init(&mutex->mutex, &attr_recursive); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d creating a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} - -/** As tor_mutex_init, but initialize a mutex suitable that may be - * non-recursive, if the OS supports that. */ -void -tor_mutex_init_nonrecursive(tor_mutex_t *mutex) -{ - int err; - if (!threads_initialized) - tor_threads_init(); // LCOV_EXCL_LINE - err = pthread_mutex_init(&mutex->mutex, NULL); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d creating a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} - -/** Wait until <b>m</b> is free, then acquire it. */ -void -tor_mutex_acquire(tor_mutex_t *m) -{ - int err; - tor_assert(m); - err = pthread_mutex_lock(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d locking a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} -/** Release the lock <b>m</b> so another thread can have it. */ -void -tor_mutex_release(tor_mutex_t *m) -{ - int err; - tor_assert(m); - err = pthread_mutex_unlock(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d unlocking a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} -/** Clean up the mutex <b>m</b> so that it no longer uses any system - * resources. Does not free <b>m</b>. This function must only be called on - * mutexes from tor_mutex_init(). */ -void -tor_mutex_uninit(tor_mutex_t *m) -{ - int err; - tor_assert(m); - err = pthread_mutex_destroy(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d destroying a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} /** Return an integer representing this thread. */ unsigned long tor_get_thread_id(void) @@ -333,8 +254,7 @@ void tor_threads_init(void) { if (!threads_initialized) { - pthread_mutexattr_init(&attr_recursive); - pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE); + tor_locking_init(); const int ret1 = pthread_attr_init(&attr_detached); tor_assert(ret1 == 0); #ifndef PTHREAD_CREATE_DETACHED @@ -347,4 +267,3 @@ tor_threads_init(void) set_main_thread(); } } - diff --git a/src/lib/thread/compat_threads.c b/src/lib/thread/compat_threads.c new file mode 100644 index 0000000000..972960e242 --- /dev/null +++ b/src/lib/thread/compat_threads.c @@ -0,0 +1,111 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_threads.c + * + * \brief Cross-platform threading and inter-thread communication logic. + * (Platform-specific parts are written in the other compat_*threads + * modules.) + */ + +#include "orconfig.h" +#include <stdlib.h> +#include "lib/thread/threads.h" + +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +#include <string.h> + +/** Allocate and return a new condition variable. */ +tor_cond_t * +tor_cond_new(void) +{ + tor_cond_t *cond = tor_malloc(sizeof(tor_cond_t)); + if (BUG(tor_cond_init(cond)<0)) + tor_free(cond); // LCOV_EXCL_LINE + return cond; +} + +/** Free all storage held in <b>c</b>. */ +void +tor_cond_free_(tor_cond_t *c) +{ + if (!c) + return; + tor_cond_uninit(c); + tor_free(c); +} + +/** Identity of the "main" thread */ +static unsigned long main_thread_id = -1; + +/** Start considering the current thread to be the 'main thread'. This has + * no effect on anything besides in_main_thread(). */ +void +set_main_thread(void) +{ + main_thread_id = tor_get_thread_id(); +} +/** Return true iff called from the main thread. */ +int +in_main_thread(void) +{ + return main_thread_id == tor_get_thread_id(); +} + +#ifndef HAVE_STDATOMIC_H +/** Initialize a new atomic counter with the value 0 */ +void +atomic_counter_init(atomic_counter_t *counter) +{ + memset(counter, 0, sizeof(*counter)); + tor_mutex_init_nonrecursive(&counter->mutex); +} +/** Clean up all resources held by an atomic counter. */ +void +atomic_counter_destroy(atomic_counter_t *counter) +{ + tor_mutex_uninit(&counter->mutex); + memset(counter, 0, sizeof(*counter)); +} +/** Add a value to an atomic counter. */ +void +atomic_counter_add(atomic_counter_t *counter, size_t add) +{ + tor_mutex_acquire(&counter->mutex); + counter->val += add; + tor_mutex_release(&counter->mutex); +} +/** Subtract a value from an atomic counter. */ +void +atomic_counter_sub(atomic_counter_t *counter, size_t sub) +{ + // this relies on unsigned overflow, but that's fine. + atomic_counter_add(counter, -sub); +} +/** Return the current value of an atomic counter */ +size_t +atomic_counter_get(atomic_counter_t *counter) +{ + size_t val; + tor_mutex_acquire(&counter->mutex); + val = counter->val; + tor_mutex_release(&counter->mutex); + return val; +} +/** Replace the value of an atomic counter; return the old one. */ +size_t +atomic_counter_exchange(atomic_counter_t *counter, size_t newval) +{ + size_t oldval; + tor_mutex_acquire(&counter->mutex); + oldval = counter->val; + counter->val = newval; + tor_mutex_release(&counter->mutex); + return oldval; +} +#endif /* !defined(HAVE_STDATOMIC_H) */ diff --git a/src/common/compat_winthreads.c b/src/lib/thread/compat_winthreads.c index 7021344f6e..7f9877d21e 100644 --- a/src/common/compat_winthreads.c +++ b/src/lib/thread/compat_winthreads.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,12 +12,12 @@ #ifdef _WIN32 -#include "compat.h" #include <windows.h> #include <process.h> -#include "util.h" -#include "container.h" -#include "torlog.h" +#include "lib/thread/threads.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/log/win32err.h" /* This value is more or less total cargo-cult */ #define SPIN_COUNT 2000 @@ -55,33 +55,6 @@ spawn_exit(void) // LCOV_EXCL_STOP } -void -tor_mutex_init(tor_mutex_t *m) -{ - InitializeCriticalSection(&m->mutex); -} -void -tor_mutex_init_nonrecursive(tor_mutex_t *m) -{ - InitializeCriticalSection(&m->mutex); -} - -void -tor_mutex_uninit(tor_mutex_t *m) -{ - DeleteCriticalSection(&m->mutex); -} -void -tor_mutex_acquire(tor_mutex_t *m) -{ - tor_assert(m); - EnterCriticalSection(&m->mutex); -} -void -tor_mutex_release(tor_mutex_t *m) -{ - LeaveCriticalSection(&m->mutex); -} unsigned long tor_get_thread_id(void) { @@ -248,4 +221,3 @@ tor_threads_init(void) } #endif /* defined(_WIN32) */ - diff --git a/src/lib/thread/include.am b/src/lib/thread/include.am new file mode 100644 index 0000000000..9ec23d166e --- /dev/null +++ b/src/lib/thread/include.am @@ -0,0 +1,27 @@ + +noinst_LIBRARIES += src/lib/libtor-thread.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-thread-testing.a +endif + +if THREADS_PTHREADS +threads_impl_source=src/lib/thread/compat_pthreads.c +endif +if THREADS_WIN32 +threads_impl_source=src/lib/thread/compat_winthreads.c +endif + +src_lib_libtor_thread_a_SOURCES = \ + src/lib/thread/compat_threads.c \ + src/lib/thread/numcpus.c \ + $(threads_impl_source) + +src_lib_libtor_thread_testing_a_SOURCES = \ + $(src_lib_libtor_thread_a_SOURCES) +src_lib_libtor_thread_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_thread_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/thread/threads.h \ + src/lib/thread/numcpus.h diff --git a/src/lib/thread/numcpus.c b/src/lib/thread/numcpus.c new file mode 100644 index 0000000000..534b0570f8 --- /dev/null +++ b/src/lib/thread/numcpus.c @@ -0,0 +1,93 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/thread/numcpus.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef _WIN32 +#include <windows.h> +#endif + +#include <stdlib.h> + +/** Implementation logic for compute_num_cpus(). */ +static int +compute_num_cpus_impl(void) +{ +#ifdef _WIN32 + SYSTEM_INFO info; + memset(&info, 0, sizeof(info)); + GetSystemInfo(&info); + if (info.dwNumberOfProcessors >= 1 && info.dwNumberOfProcessors < INT_MAX) + return (int)info.dwNumberOfProcessors; + else + return -1; +#elif defined(HAVE_SYSCONF) +#ifdef _SC_NPROCESSORS_CONF + long cpus_conf = sysconf(_SC_NPROCESSORS_CONF); +#else + long cpus_conf = -1; +#endif +#ifdef _SC_NPROCESSORS_ONLN + long cpus_onln = sysconf(_SC_NPROCESSORS_ONLN); +#else + long cpus_onln = -1; +#endif + long cpus = -1; + + if (cpus_conf > 0 && cpus_onln < 0) { + cpus = cpus_conf; + } else if (cpus_onln > 0 && cpus_conf < 0) { + cpus = cpus_onln; + } else if (cpus_onln > 0 && cpus_conf > 0) { + if (cpus_onln < cpus_conf) { + log_notice(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them " + "are available. Telling Tor to only use %ld. You can over" + "ride this with the NumCPUs option", + cpus_conf, cpus_onln, cpus_onln); + } + cpus = cpus_onln; + } + + if (cpus >= 1 && cpus < INT_MAX) + return (int)cpus; + else + return -1; +#else + return -1; +#endif /* defined(_WIN32) || ... */ +} + +#define MAX_DETECTABLE_CPUS 16 + +/** Return how many CPUs we are running with. We assume that nobody is + * using hot-swappable CPUs, so we don't recompute this after the first + * time. Return -1 if we don't know how to tell the number of CPUs on this + * system. + */ +int +compute_num_cpus(void) +{ + static int num_cpus = -2; + if (num_cpus == -2) { + num_cpus = compute_num_cpus_impl(); + tor_assert(num_cpus != -2); + if (num_cpus > MAX_DETECTABLE_CPUS) { + /* LCOV_EXCL_START */ + log_notice(LD_GENERAL, "Wow! I detected that you have %d CPUs. I " + "will not autodetect any more than %d, though. If you " + "want to configure more, set NumCPUs in your torrc", + num_cpus, MAX_DETECTABLE_CPUS); + num_cpus = MAX_DETECTABLE_CPUS; + /* LCOV_EXCL_STOP */ + } + } + return num_cpus; +} diff --git a/src/lib/thread/numcpus.h b/src/lib/thread/numcpus.h new file mode 100644 index 0000000000..2899a9ec8a --- /dev/null +++ b/src/lib/thread/numcpus.h @@ -0,0 +1,11 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_NUMCPUS_H +#define TOR_NUMCPUS_H + +int compute_num_cpus(void); + +#endif diff --git a/src/common/compat_threads.h b/src/lib/thread/threads.h index c93e601ec5..fcccc643d5 100644 --- a/src/common/compat_threads.h +++ b/src/lib/thread/threads.h @@ -1,62 +1,25 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_COMPAT_THREADS_H #define TOR_COMPAT_THREADS_H #include "orconfig.h" -#include "torint.h" -#include "testsupport.h" - -#if defined(HAVE_PTHREAD_H) && !defined(_WIN32) -#include <pthread.h> -#endif +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" +#include "lib/lock/compat_mutex.h" #ifdef HAVE_STDATOMIC_H #include <stdatomic.h> #endif -#if defined(_WIN32) -#define USE_WIN32_THREADS -#elif defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_CREATE) -#define USE_PTHREADS -#else -#error "No threading system was found" -#endif /* defined(_WIN32) || ... */ +struct timeval; int spawn_func(void (*func)(void *), void *data); void spawn_exit(void) ATTR_NORETURN; -/* Because we use threads instead of processes on most platforms (Windows, - * Linux, etc), we need locking for them. On platforms with poor thread - * support or broken gethostbyname_r, these functions are no-ops. */ - -/** A generic lock structure for multithreaded builds. */ -typedef struct tor_mutex_t { -#if defined(USE_WIN32_THREADS) - /** Windows-only: on windows, we implement locks with CRITICAL_SECTIONS. */ - CRITICAL_SECTION mutex; -#elif defined(USE_PTHREADS) - /** Pthreads-only: with pthreads, we implement locks with - * pthread_mutex_t. */ - pthread_mutex_t mutex; -#else - /** No-threads only: Dummy variable so that tor_mutex_t takes up space. */ - int _unused; -#endif /* defined(USE_WIN32_THREADS) || ... */ -} tor_mutex_t; - -tor_mutex_t *tor_mutex_new(void); -tor_mutex_t *tor_mutex_new_nonrecursive(void); -void tor_mutex_init(tor_mutex_t *m); -void tor_mutex_init_nonrecursive(tor_mutex_t *m); -void tor_mutex_acquire(tor_mutex_t *m); -void tor_mutex_release(tor_mutex_t *m); -void tor_mutex_free_(tor_mutex_t *m); -#define tor_mutex_free(m) FREE_AND_NULL(tor_mutex_t, tor_mutex_free_, (m)) -void tor_mutex_uninit(tor_mutex_t *m); unsigned long tor_get_thread_id(void); void tor_threads_init(void); @@ -91,32 +54,6 @@ int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, void tor_cond_signal_one(tor_cond_t *cond); void tor_cond_signal_all(tor_cond_t *cond); -/** Helper type used to manage waking up the main thread while it's in - * the libevent main loop. Used by the work queue code. */ -typedef struct alert_sockets_s { - /* XXXX This structure needs a better name. */ - /** Socket that the main thread should listen for EV_READ events on. - * Note that this socket may be a regular fd on a non-Windows platform. - */ - tor_socket_t read_fd; - /** Socket to use when alerting the main thread. */ - tor_socket_t write_fd; - /** Function to alert the main thread */ - int (*alert_fn)(tor_socket_t write_fd); - /** Function to make the main thread no longer alerted. */ - int (*drain_fn)(tor_socket_t read_fd); -} alert_sockets_t; - -/* Flags to disable one or more alert_sockets backends. */ -#define ASOCKS_NOEVENTFD2 (1u<<0) -#define ASOCKS_NOEVENTFD (1u<<1) -#define ASOCKS_NOPIPE2 (1u<<2) -#define ASOCKS_NOPIPE (1u<<3) -#define ASOCKS_NOSOCKETPAIR (1u<<4) - -int alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags); -void alert_sockets_close(alert_sockets_t *socks); - typedef struct tor_threadlocal_s { #ifdef _WIN32 DWORD index; @@ -220,4 +157,3 @@ atomic_counter_exchange(atomic_counter_t *counter, size_t newval) #endif /* defined(HAVE_STDATOMIC_H) */ #endif /* !defined(TOR_COMPAT_THREADS_H) */ - diff --git a/src/lib/time/.may_include b/src/lib/time/.may_include new file mode 100644 index 0000000000..2c7e37a836 --- /dev/null +++ b/src/lib/time/.may_include @@ -0,0 +1,11 @@ +orconfig.h + +lib/cc/*.h +lib/err/*.h +lib/intmath/*.h +lib/log/*.h +lib/time/*.h +lib/wallclock/*.h + +# For load_windows_system_lib. +lib/fs/winlib.h
\ No newline at end of file diff --git a/src/common/compat_time.c b/src/lib/time/compat_time.c index 40847a8442..2ea6eca988 100644 --- a/src/common/compat_time.c +++ b/src/lib/time/compat_time.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,7 +10,15 @@ **/ #define COMPAT_TIME_PRIVATE -#include "compat.h" +#include "lib/time/compat_time.h" + +#include "lib/err/torerr.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/intmath/muldiv.h" +#include "lib/intmath/bits.h" +#include "lib/fs/winlib.h" +#include "lib/wallclock/timeval.h" #ifdef _WIN32 #include <winsock2.h> @@ -20,6 +28,9 @@ #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -34,15 +45,9 @@ #include <mach/mach_time.h> #endif -#include "torlog.h" -#include "util.h" -#include "container.h" - -#ifndef HAVE_GETTIMEOFDAY -#ifdef HAVE_FTIME -#include <sys/timeb.h> -#endif -#endif +#include <errno.h> +#include <stdlib.h> +#include <string.h> #ifdef _WIN32 #undef HAVE_CLOCK_GETTIME @@ -68,54 +73,6 @@ tor_sleep_msec(int msec) } #endif /* defined(TOR_UNIT_TESTS) */ -/** Set *timeval to the current time of day. On error, log and terminate. - * (Same as gettimeofday(timeval,NULL), but never returns -1.) - */ -MOCK_IMPL(void, -tor_gettimeofday, (struct timeval *timeval)) -{ -#ifdef _WIN32 - /* Epoch bias copied from perl: number of units between windows epoch and - * Unix epoch. */ -#define EPOCH_BIAS U64_LITERAL(116444736000000000) -#define UNITS_PER_SEC U64_LITERAL(10000000) -#define USEC_PER_SEC U64_LITERAL(1000000) -#define UNITS_PER_USEC U64_LITERAL(10) - union { - uint64_t ft_64; - FILETIME ft_ft; - } ft; - /* number of 100-nsec units since Jan 1, 1601 */ - GetSystemTimeAsFileTime(&ft.ft_ft); - if (ft.ft_64 < EPOCH_BIAS) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"System time is before 1970; failing."); - exit(1); // exit ok: system clock is broken. - /* LCOV_EXCL_STOP */ - } - ft.ft_64 -= EPOCH_BIAS; - timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC); - timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC); -#elif defined(HAVE_GETTIMEOFDAY) - if (gettimeofday(timeval, NULL)) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"gettimeofday failed."); - /* If gettimeofday dies, we have either given a bad timezone (we didn't), - or segfaulted.*/ - exit(1); // exit ok: gettimeofday failed. - /* LCOV_EXCL_STOP */ - } -#elif defined(HAVE_FTIME) - struct timeb tb; - ftime(&tb); - timeval->tv_sec = tb.time; - timeval->tv_usec = tb.millitm * 1000; -#else -#error "No way to get time." -#endif /* defined(_WIN32) || ... */ - return; -} - #define ONE_MILLION ((int64_t) (1000 * 1000)) #define ONE_BILLION ((int64_t) (1000 * 1000 * 1000)) @@ -900,4 +857,3 @@ monotime_msec_to_approx_coarse_stamp_units(uint64_t msec) return (msec * STAMP_TICKS_PER_SECOND) / 1000; } #endif - diff --git a/src/common/compat_time.h b/src/lib/time/compat_time.h index 57ab20ab11..4427ce8f92 100644 --- a/src/common/compat_time.h +++ b/src/lib/time/compat_time.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,6 +19,10 @@ #define TOR_COMPAT_TIME_H #include "orconfig.h" +#include "lib/cc/torint.h" + +#include "lib/wallclock/tor_gettimeofday.h" + #ifdef _WIN32 #undef HAVE_CLOCK_GETTIME #endif @@ -200,8 +204,6 @@ monotime_coarse_diff_msec32(const monotime_coarse_t *start, #endif } -MOCK_DECL(void, tor_gettimeofday, (struct timeval *timeval)); - #ifdef TOR_UNIT_TESTS void tor_sleep_msec(int msec); @@ -230,4 +232,3 @@ void monotime_reset_ratchets_for_testing(void); #endif /* defined(COMPAT_TIME_PRIVATE) */ #endif /* !defined(TOR_COMPAT_TIME_H) */ - diff --git a/src/lib/time/include.am b/src/lib/time/include.am new file mode 100644 index 0000000000..a3f93a3744 --- /dev/null +++ b/src/lib/time/include.am @@ -0,0 +1,19 @@ + +noinst_LIBRARIES += src/lib/libtor-time.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-time-testing.a +endif + +src_lib_libtor_time_a_SOURCES = \ + src/lib/time/compat_time.c \ + src/lib/time/tvdiff.c + +src_lib_libtor_time_testing_a_SOURCES = \ + $(src_lib_libtor_time_a_SOURCES) +src_lib_libtor_time_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_time_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/time/compat_time.h \ + src/lib/time/tvdiff.h diff --git a/src/lib/time/tvdiff.c b/src/lib/time/tvdiff.c new file mode 100644 index 0000000000..5dbc0fd19c --- /dev/null +++ b/src/lib/time/tvdiff.c @@ -0,0 +1,162 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/time/tvdiff.h" + +#include "lib/cc/compat_compiler.h" +#include "lib/log/torlog.h" + +#ifdef _WIN32 +#include <winsock2.h> +#endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#define TOR_USEC_PER_SEC 1000000 + +/** Return the difference between start->tv_sec and end->tv_sec. + * Returns INT64_MAX on overflow and underflow. + */ +static int64_t +tv_secdiff_impl(const struct timeval *start, const struct timeval *end) +{ + const int64_t s = (int64_t)start->tv_sec; + const int64_t e = (int64_t)end->tv_sec; + + /* This may not be the most efficient way of implemeting this check, + * but it's easy to see that it's correct and doesn't overflow */ + + if (s > 0 && e < INT64_MIN + s) { + /* s is positive: equivalent to e - s < INT64_MIN, but without any + * overflow */ + return INT64_MAX; + } else if (s < 0 && e > INT64_MAX + s) { + /* s is negative: equivalent to e - s > INT64_MAX, but without any + * overflow */ + return INT64_MAX; + } + + return e - s; +} + +/** Return the number of microseconds elapsed between *start and *end. + * Returns LONG_MAX on overflow and underflow. + */ +long +tv_udiff(const struct timeval *start, const struct timeval *end) +{ + /* Sanity check tv_usec */ + if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " + "start tv_usec: " I64_FORMAT " microseconds", + I64_PRINTF_ARG(start->tv_usec)); + return LONG_MAX; + } + + if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " + "end tv_usec: " I64_FORMAT " microseconds", + I64_PRINTF_ARG(end->tv_usec)); + return LONG_MAX; + } + + /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit + */ + int64_t udiff; + const int64_t secdiff = tv_secdiff_impl(start, end); + + /* end->tv_usec - start->tv_usec can be up to 1 second either way */ + if (secdiff > (int64_t)(LONG_MAX/1000000 - 1) || + secdiff < (int64_t)(LONG_MIN/1000000 + 1)) { + log_warn(LD_GENERAL, "comparing times on microsecond detail too far " + "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); + return LONG_MAX; + } + + /* we'll never get an overflow here, because we check that both usecs are + * between 0 and TV_USEC_PER_SEC. */ + udiff = secdiff*1000000 + ((int64_t)end->tv_usec - (int64_t)start->tv_usec); + + /* Some compilers are smart enough to work out this is a no-op on L64 */ +#if SIZEOF_LONG < 8 + if (udiff > (int64_t)LONG_MAX || udiff < (int64_t)LONG_MIN) { + return LONG_MAX; + } +#endif + + return (long)udiff; +} + +/** Return the number of milliseconds elapsed between *start and *end. + * If the tv_usec difference is 500, rounds away from zero. + * Returns LONG_MAX on overflow and underflow. + */ +long +tv_mdiff(const struct timeval *start, const struct timeval *end) +{ + /* Sanity check tv_usec */ + if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " + "start tv_usec: " I64_FORMAT " microseconds", + I64_PRINTF_ARG(start->tv_usec)); + return LONG_MAX; + } + + if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " + "end tv_usec: " I64_FORMAT " microseconds", + I64_PRINTF_ARG(end->tv_usec)); + return LONG_MAX; + } + + /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit + */ + int64_t mdiff; + const int64_t secdiff = tv_secdiff_impl(start, end); + + /* end->tv_usec - start->tv_usec can be up to 1 second either way, but the + * mdiff calculation may add another temporary second for rounding. + * Whether this actually causes overflow depends on the compiler's constant + * folding and order of operations. */ + if (secdiff > (int64_t)(LONG_MAX/1000 - 2) || + secdiff < (int64_t)(LONG_MIN/1000 + 1)) { + log_warn(LD_GENERAL, "comparing times on millisecond detail too far " + "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); + return LONG_MAX; + } + + /* Subtract and round */ + mdiff = secdiff*1000 + + /* We add a million usec here to ensure that the result is positive, + * so that the round-towards-zero behavior of the division will give + * the right result for rounding to the nearest msec. Later we subtract + * 1000 in order to get the correct result. + * We'll never get an overflow here, because we check that both usecs are + * between 0 and TV_USEC_PER_SEC. */ + ((int64_t)end->tv_usec - (int64_t)start->tv_usec + 500 + 1000000) / 1000 + - 1000; + + /* Some compilers are smart enough to work out this is a no-op on L64 */ +#if SIZEOF_LONG < 8 + if (mdiff > (int64_t)LONG_MAX || mdiff < (int64_t)LONG_MIN) { + return LONG_MAX; + } +#endif + + return (long)mdiff; +} + +/** + * Converts timeval to milliseconds. + */ +int64_t +tv_to_msec(const struct timeval *tv) +{ + int64_t conv = ((int64_t)tv->tv_sec)*1000L; + /* Round ghetto-style */ + conv += ((int64_t)tv->tv_usec+500)/1000L; + return conv; +} diff --git a/src/lib/time/tvdiff.h b/src/lib/time/tvdiff.h new file mode 100644 index 0000000000..215de9cf37 --- /dev/null +++ b/src/lib/time/tvdiff.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_TVDIFF_H +#define TOR_TVDIFF_H + +#include "lib/cc/torint.h" +struct timeval; + +long tv_udiff(const struct timeval *start, const struct timeval *end); +long tv_mdiff(const struct timeval *start, const struct timeval *end); +int64_t tv_to_msec(const struct timeval *tv); + +#endif diff --git a/src/lib/tls/.may_include b/src/lib/tls/.may_include new file mode 100644 index 0000000000..1a4b8ca521 --- /dev/null +++ b/src/lib/tls/.may_include @@ -0,0 +1,16 @@ +orconfig.h +lib/arch/*.h +lib/cc/*.h +lib/ctime/*.h +lib/container/*.h +lib/crypt_ops/*.h +lib/intmath/*.h +lib/encoding/*.h +lib/err/*.h +lib/net/*.h +lib/string/*.h +lib/testsupport/testsupport.h +lib/tls/*.h +lib/log/*.h + +ciphers.inc diff --git a/src/common/buffers_tls.c b/src/lib/tls/buffers_tls.c index 041f78b818..243e0eb0bc 100644 --- a/src/common/buffers_tls.c +++ b/src/lib/tls/buffers_tls.c @@ -1,20 +1,19 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define BUFFERS_PRIVATE #include "orconfig.h" #include <stddef.h> -#include "buffers.h" -#include "buffers_tls.h" -#include "compat.h" -#include "compress.h" -#include "util.h" -#include "torint.h" -#include "torlog.h" -#include "tortls.h" +#include "lib/container/buffers.h" +#include "lib/tls/buffers_tls.h" +#include "lib/cc/torint.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/tls/tortls.h" + #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -176,4 +175,3 @@ buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen, tor_assert(flushed < INT_MAX); return (int)flushed; } - diff --git a/src/common/buffers_tls.h b/src/lib/tls/buffers_tls.h index 2f9fda45a0..d9d26c82bd 100644 --- a/src/common/buffers_tls.h +++ b/src/lib/tls/buffers_tls.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_BUFFERS_TLS_H diff --git a/src/common/ciphers.inc b/src/lib/tls/ciphers.inc index 0084b3e325..0084b3e325 100644 --- a/src/common/ciphers.inc +++ b/src/lib/tls/ciphers.inc diff --git a/src/lib/tls/include.am b/src/lib/tls/include.am new file mode 100644 index 0000000000..b3b013f4dd --- /dev/null +++ b/src/lib/tls/include.am @@ -0,0 +1,20 @@ + +noinst_LIBRARIES += src/lib/libtor-tls.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-tls-testing.a +endif + +src_lib_libtor_tls_a_SOURCES = \ + src/lib/tls/buffers_tls.c \ + src/lib/tls/tortls.c + +src_lib_libtor_tls_testing_a_SOURCES = \ + $(src_lib_libtor_tls_a_SOURCES) +src_lib_libtor_tls_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_tls_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/tls/ciphers.inc \ + src/lib/tls/buffers_tls.h \ + src/lib/tls/tortls.h diff --git a/src/common/tortls.c b/src/lib/tls/tortls.c index 669742c9dd..3eee41bd16 100644 --- a/src/common/tortls.c +++ b/src/lib/tls/tortls.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,16 +19,15 @@ #define TORTLS_PRIVATE #define TORTLS_OPENSSL_PRIVATE -#include <assert.h> #ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/ #include <winsock2.h> #include <ws2tcpip.h> #endif -#include "crypto.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "compat.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_util.h" /* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */ @@ -52,12 +51,22 @@ DISABLE_GCC_WARNING(redundant-decls) ENABLE_GCC_WARNING(redundant-decls) #define TORTLS_PRIVATE -#include "tortls.h" -#include "util.h" -#include "torlog.h" -#include "container.h" +#include "lib/tls/tortls.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/container/smartlist.h" +#include "lib/string/compat_string.h" +#include "lib/string/printf.h" +#include "lib/net/socket.h" +#include "lib/intmath/cmp.h" +#include "lib/ctime/di_ops.h" +#include "lib/encoding/time_fmt.h" + +#include <stdlib.h> #include <string.h> +#include "lib/arch/bytes.h" + #ifdef OPENSSL_1_1_API #define X509_get_notBefore_const(cert) \ X509_get0_notBefore(cert) @@ -1392,7 +1401,7 @@ find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher) { unsigned char cipherid[3]; tor_assert(ssl); - set_uint16(cipherid, htons(cipher)); + set_uint16(cipherid, tor_htons(cipher)); cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting * with a two-byte 'cipherid', it may look for a v2 * cipher with the appropriate 3 bytes. */ @@ -1406,7 +1415,7 @@ find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher) # if defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR) if (m && m->get_cipher_by_char) { unsigned char cipherid[3]; - set_uint16(cipherid, htons(cipher)); + set_uint16(cipherid, tor_htons(cipher)); cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting * with a two-byte 'cipherid', it may look for a v2 * cipher with the appropriate 3 bytes. */ @@ -2660,4 +2669,3 @@ evaluate_ecgroup_for_tls(const char *ecgroup) return ret; } - diff --git a/src/common/tortls.h b/src/lib/tls/tortls.h index 7c867bfff2..fe192b2abc 100644 --- a/src/common/tortls.h +++ b/src/lib/tls/tortls.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TORTLS_H @@ -11,10 +11,9 @@ * \brief Headers for tortls.c **/ -#include "crypto_rsa.h" -#include "compat_openssl.h" -#include "compat.h" -#include "testsupport.h" +#include "lib/crypt_ops/crypto_rsa.h" +#include "lib/crypt_ops/compat_openssl.h" +#include "lib/testsupport/testsupport.h" /* Opaque structure to hold a TLS connection. */ typedef struct tor_tls_t tor_tls_t; @@ -292,4 +291,3 @@ const char *tor_tls_get_ciphersuite_name(tor_tls_t *tls); int evaluate_ecgroup_for_tls(const char *ecgroup); #endif /* !defined(TOR_TORTLS_H) */ - diff --git a/src/lib/trace/.may_include b/src/lib/trace/.may_include new file mode 100644 index 0000000000..45cd13676b --- /dev/null +++ b/src/lib/trace/.may_include @@ -0,0 +1,3 @@ +orconfig.h +lib/log/*.h +lib/trace/*.h diff --git a/src/trace/debug.h b/src/lib/trace/debug.h index 3a1652543a..9b5d9d05c8 100644 --- a/src/trace/debug.h +++ b/src/lib/trace/debug.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TRACE_LOG_DEBUG_H #define TOR_TRACE_LOG_DEBUG_H -#include "torlog.h" +#include "lib/log/torlog.h" /* Stringify pre-processor trick. */ #define XSTR(d) STR(d) diff --git a/src/trace/events.h b/src/lib/trace/events.h index 1be1fd596e..6d4269aaed 100644 --- a/src/trace/events.h +++ b/src/lib/trace/events.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -31,7 +31,7 @@ /* Enable event tracing for the debug framework where all trace events are * mapped to a log_debug(). */ #ifdef USE_EVENT_TRACING_DEBUG -#include "trace/debug.h" +#include "lib/trace/debug.h" #endif #else /* TOR_EVENT_TRACING_ENABLED */ diff --git a/src/lib/trace/include.am b/src/lib/trace/include.am new file mode 100644 index 0000000000..6f10c98744 --- /dev/null +++ b/src/lib/trace/include.am @@ -0,0 +1,18 @@ + +noinst_LIBRARIES += \ + src/lib/libtor-trace.a + +TRACEHEADERS = \ + src/lib/trace/trace.h \ + src/lib/trace/events.h + +if USE_EVENT_TRACING_DEBUG +TRACEHEADERS += \ + src/lib/trace/debug.h +endif + +# Library source files. +src_lib_libtor_trace_a_SOURCES = \ + src/lib/trace/trace.c + +noinst_HEADERS+= $(TRACEHEADERS) diff --git a/src/trace/trace.c b/src/lib/trace/trace.c index fcdb80091f..c0bbbb0cc6 100644 --- a/src/trace/trace.c +++ b/src/lib/trace/trace.c @@ -1,7 +1,7 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "trace.h" +#include "lib/trace/trace.h" /** Initialize the tracing library. */ void diff --git a/src/trace/trace.h b/src/lib/trace/trace.h index 28fcd8eea8..2dd51aace1 100644 --- a/src/trace/trace.h +++ b/src/lib/trace/trace.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TRACE_TRACE_H diff --git a/src/lib/wallclock/.may_include b/src/lib/wallclock/.may_include new file mode 100644 index 0000000000..dc010da063 --- /dev/null +++ b/src/lib/wallclock/.may_include @@ -0,0 +1,6 @@ +orconfig.h +lib/cc/*.h +lib/err/*.h +lib/wallclock/*.h +lib/string/*.h +lib/testsupport/*.h diff --git a/src/lib/wallclock/approx_time.c b/src/lib/wallclock/approx_time.c new file mode 100644 index 0000000000..2528954f13 --- /dev/null +++ b/src/lib/wallclock/approx_time.c @@ -0,0 +1,38 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/wallclock/approx_time.h" + +/* ===== + * Cached time + * ===== */ + +#ifndef TIME_IS_FAST +/** Cached estimate of the current time. Updated around once per second; + * may be a few seconds off if we are really busy. This is a hack to avoid + * calling time(NULL) (which not everybody has optimized) on critical paths. + */ +static time_t cached_approx_time = 0; + +/** Return a cached estimate of the current time from when + * update_approx_time() was last called. This is a hack to avoid calling + * time(NULL) on critical paths: please do not even think of calling it + * anywhere else. */ +time_t +approx_time(void) +{ + return cached_approx_time; +} + +/** Update the cached estimate of the current time. This function SHOULD be + * called once per second, and MUST be called before the first call to + * get_approx_time. */ +void +update_approx_time(time_t now) +{ + cached_approx_time = now; +} +#endif /* !defined(TIME_IS_FAST) */ diff --git a/src/lib/wallclock/approx_time.h b/src/lib/wallclock/approx_time.h new file mode 100644 index 0000000000..c57ff5bcd3 --- /dev/null +++ b/src/lib/wallclock/approx_time.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_APPROX_TIME_H +#define TOR_APPROX_TIME_H + +#include <time.h> + +/* Cached time */ +#ifdef TIME_IS_FAST +#define approx_time() time(NULL) +#define update_approx_time(t) STMT_NIL +#else +time_t approx_time(void); +void update_approx_time(time_t now); +#endif /* defined(TIME_IS_FAST) */ + +#endif diff --git a/src/lib/wallclock/include.am b/src/lib/wallclock/include.am new file mode 100644 index 0000000000..7864c21e16 --- /dev/null +++ b/src/lib/wallclock/include.am @@ -0,0 +1,22 @@ + +noinst_LIBRARIES += src/lib/libtor-wallclock.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-wallclock-testing.a +endif + +src_lib_libtor_wallclock_a_SOURCES = \ + src/lib/wallclock/approx_time.c \ + src/lib/wallclock/tm_cvt.c \ + src/lib/wallclock/tor_gettimeofday.c + +src_lib_libtor_wallclock_testing_a_SOURCES = \ + $(src_lib_libtor_wallclock_a_SOURCES) +src_lib_libtor_wallclock_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_wallclock_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/wallclock/approx_time.h \ + src/lib/wallclock/timeval.h \ + src/lib/wallclock/tm_cvt.h \ + src/lib/wallclock/tor_gettimeofday.h diff --git a/src/lib/wallclock/timeval.c b/src/lib/wallclock/timeval.c new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/src/lib/wallclock/timeval.c diff --git a/src/lib/wallclock/timeval.h b/src/lib/wallclock/timeval.h new file mode 100644 index 0000000000..6a9b36a022 --- /dev/null +++ b/src/lib/wallclock/timeval.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_TIMEVAL_H +#define TOR_TIMEVAL_H + +#include "orconfig.h" +#include "lib/cc/torint.h" + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#ifndef timeradd +/** Replacement for timeradd on platforms that do not have it: sets tvout to + * the sum of tv1 and tv2. */ +#define timeradd(tv1,tv2,tvout) \ + do { \ + (tvout)->tv_sec = (tv1)->tv_sec + (tv2)->tv_sec; \ + (tvout)->tv_usec = (tv1)->tv_usec + (tv2)->tv_usec; \ + if ((tvout)->tv_usec >= 1000000) { \ + (tvout)->tv_usec -= 1000000; \ + (tvout)->tv_sec++; \ + } \ + } while (0) +#endif /* !defined(timeradd) */ + +#ifndef timersub +/** Replacement for timersub on platforms that do not have it: sets tvout to + * tv1 minus tv2. */ +#define timersub(tv1,tv2,tvout) \ + do { \ + (tvout)->tv_sec = (tv1)->tv_sec - (tv2)->tv_sec; \ + (tvout)->tv_usec = (tv1)->tv_usec - (tv2)->tv_usec; \ + if ((tvout)->tv_usec < 0) { \ + (tvout)->tv_usec += 1000000; \ + (tvout)->tv_sec--; \ + } \ + } while (0) +#endif /* !defined(timersub) */ + +#ifndef timercmp +/** Replacement for timercmp on platforms that do not have it: returns true + * iff the relational operator "op" makes the expression tv1 op tv2 true. + * + * Note that while this definition should work for all boolean operators, some + * platforms' native timercmp definitions do not support >=, <=, or ==. So + * don't use those. + */ +#define timercmp(tv1,tv2,op) \ + (((tv1)->tv_sec == (tv2)->tv_sec) ? \ + ((tv1)->tv_usec op (tv2)->tv_usec) : \ + ((tv1)->tv_sec op (tv2)->tv_sec)) +#endif /* !defined(timercmp) */ + +#endif diff --git a/src/lib/wallclock/tm_cvt.c b/src/lib/wallclock/tm_cvt.c new file mode 100644 index 0000000000..987b0ffebf --- /dev/null +++ b/src/lib/wallclock/tm_cvt.c @@ -0,0 +1,195 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/cc/compat_compiler.h" +#include "lib/wallclock/tm_cvt.h" +#include "lib/string/printf.h" +#include "lib/err/torerr.h" + +#include <errno.h> +#include <time.h> +#include <string.h> +#include <stdlib.h> + +#if !defined(_WIN32) +/** Defined iff we need to add locks when defining fake versions of reentrant + * versions of time-related functions. */ +#define TIME_FNS_NEED_LOCKS +#endif + +/** Helper: Deal with confused or out-of-bounds values from localtime_r and + * friends. (On some platforms, they can give out-of-bounds values or can + * return NULL.) If <b>islocal</b>, this is a localtime result; otherwise + * it's from gmtime. The function returns <b>r</b>, when given <b>timep</b> + * as its input. If we need to store new results, store them in + * <b>resultbuf</b>. */ +static struct tm * +correct_tm(int islocal, const time_t *timep, struct tm *resultbuf, + struct tm *r, char **err_out) +{ + const char *outcome; + + if (PREDICT_LIKELY(r)) { + /* We can't strftime dates after 9999 CE, and we want to avoid dates + * before 1 CE (avoiding the year 0 issue and negative years). */ + if (r->tm_year > 8099) { + r->tm_year = 8099; + r->tm_mon = 11; + r->tm_mday = 31; + r->tm_yday = 364; + r->tm_wday = 6; + r->tm_hour = 23; + r->tm_min = 59; + r->tm_sec = 59; + } else if (r->tm_year < (1-1900)) { + r->tm_year = (1-1900); + r->tm_mon = 0; + r->tm_mday = 1; + r->tm_yday = 0; + r->tm_wday = 0; + r->tm_hour = 0; + r->tm_min = 0; + r->tm_sec = 0; + } + return r; + } + + /* If we get here, gmtime or localtime returned NULL. It might have done + * this because of overrun or underrun, or it might have done it because of + * some other weird issue. */ + if (timep) { + if (*timep < 0) { + r = resultbuf; + r->tm_year = 70; /* 1970 CE */ + r->tm_mon = 0; + r->tm_mday = 1; + r->tm_yday = 0; + r->tm_wday = 0; + r->tm_hour = 0; + r->tm_min = 0 ; + r->tm_sec = 0; + outcome = "Rounding up to 1970"; + goto done; + } else if (*timep >= INT32_MAX) { + /* Rounding down to INT32_MAX isn't so great, but keep in mind that we + * only do it if gmtime/localtime tells us NULL. */ + r = resultbuf; + r->tm_year = 137; /* 2037 CE */ + r->tm_mon = 11; + r->tm_mday = 31; + r->tm_yday = 364; + r->tm_wday = 6; + r->tm_hour = 23; + r->tm_min = 59; + r->tm_sec = 59; + outcome = "Rounding down to 2037"; + goto done; + } + } + + /* If we get here, then gmtime/localtime failed without getting an extreme + * value for *timep */ + /* LCOV_EXCL_START */ + r = resultbuf; + memset(resultbuf, 0, sizeof(struct tm)); + outcome="can't recover"; + /* LCOV_EXCL_STOP */ + done: + if (err_out) { + tor_asprintf(err_out, "%s("I64_FORMAT") failed with error %s: %s", + islocal?"localtime":"gmtime", + timep?I64_PRINTF_ARG(*timep):0, + strerror(errno), + outcome); + } + return r; +} + +/** @{ */ +/** As localtime_r, but defined for platforms that don't have it: + * + * Convert *<b>timep</b> to a struct tm in local time, and store the value in + * *<b>result</b>. Return the result on success, or NULL on failure. + */ +#ifdef HAVE_LOCALTIME_R +struct tm * +tor_localtime_r_msg(const time_t *timep, struct tm *result, char **err_out) +{ + struct tm *r; + r = localtime_r(timep, result); + return correct_tm(1, timep, result, r, err_out); +} +#elif defined(TIME_FNS_NEED_LOCKS) +struct tm * +tor_localtime_r_msg(const time_t *timep, struct tm *result, char **err_out) +{ + struct tm *r; + static tor_mutex_t *m=NULL; + if (!m) { m=tor_mutex_new(); } + raw_assert(result); + tor_mutex_acquire(m); + r = localtime(timep); + if (r) + memcpy(result, r, sizeof(struct tm)); + tor_mutex_release(m); + return correct_tm(1, timep, result, r, err_out); +} +#else +struct tm * +tor_localtime_r_msg(const time_t *timep, struct tm *result, char **err_out) +{ + struct tm *r; + raw_assert(result); + r = localtime(timep); + if (r) + memcpy(result, r, sizeof(struct tm)); + return correct_tm(1, timep, result, r, err_out); +} +#endif /* defined(HAVE_LOCALTIME_R) || ... */ +/** @} */ + +/** @{ */ +/** As gmtime_r, but defined for platforms that don't have it: + * + * Convert *<b>timep</b> to a struct tm in UTC, and store the value in + * *<b>result</b>. Return the result on success, or NULL on failure. + */ +#ifdef HAVE_GMTIME_R +struct tm * +tor_gmtime_r_msg(const time_t *timep, struct tm *result, char **err_out) +{ + struct tm *r; + r = gmtime_r(timep, result); + return correct_tm(0, timep, result, r, err_out); +} +#elif defined(TIME_FNS_NEED_LOCKS) +struct tm * +tor_gmtime_r_msg(const time_t *timep, struct tm *result, char **err_out) +{ + struct tm *r; + static tor_mutex_t *m=NULL; + if (!m) { m=tor_mutex_new(); } + raw_assert(result); + tor_mutex_acquire(m); + r = gmtime(timep); + if (r) + memcpy(result, r, sizeof(struct tm)); + tor_mutex_release(m); + return correct_tm(0, timep, result, r, err_out); +} +#else +struct tm * +tor_gmtime_r_msg(const time_t *timep, struct tm *result, char **err_out) +{ + struct tm *r; + raw_assert(result); + r = gmtime(timep); + if (r) + memcpy(result, r, sizeof(struct tm)); + return correct_tm(0, timep, result, r, err_out); +} +#endif /* defined(HAVE_GMTIME_R) || ... */ diff --git a/src/lib/wallclock/tm_cvt.h b/src/lib/wallclock/tm_cvt.h new file mode 100644 index 0000000000..4d87acd4fa --- /dev/null +++ b/src/lib/wallclock/tm_cvt.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_WALLCLOCK_TM_CVT_H +#define TOR_WALLCLOCK_TM_CVT_H + +#include <sys/types.h> + +struct tm; +struct tm *tor_localtime_r_msg(const time_t *timep, struct tm *result, + char **err_out); +struct tm *tor_gmtime_r_msg(const time_t *timep, struct tm *result, + char **err_out); + +#endif diff --git a/src/lib/wallclock/tor_gettimeofday.c b/src/lib/wallclock/tor_gettimeofday.c new file mode 100644 index 0000000000..74a6405720 --- /dev/null +++ b/src/lib/wallclock/tor_gettimeofday.c @@ -0,0 +1,82 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_time.c + * \brief Portable wrappers for finding out the current time, running + * timers, etc. + **/ + +#include "orconfig.h" +#include "lib/err/torerr.h" +#include "lib/wallclock/tor_gettimeofday.h" +#include "lib/cc/torint.h" + +#include <stddef.h> +#include <stdlib.h> + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#ifdef _WIN32 +#include <windows.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifndef HAVE_GETTIMEOFDAY +#ifdef HAVE_FTIME +#include <sys/timeb.h> +#endif +#endif + +/** Set *timeval to the current time of day. On error, log and terminate. + * (Same as gettimeofday(timeval,NULL), but never returns -1.) + */ +MOCK_IMPL(void, +tor_gettimeofday, (struct timeval *timeval)) +{ +#ifdef _WIN32 + /* Epoch bias copied from perl: number of units between windows epoch and + * Unix epoch. */ +#define EPOCH_BIAS U64_LITERAL(116444736000000000) +#define UNITS_PER_SEC U64_LITERAL(10000000) +#define USEC_PER_SEC U64_LITERAL(1000000) +#define UNITS_PER_USEC U64_LITERAL(10) + union { + uint64_t ft_64; + FILETIME ft_ft; + } ft; + /* number of 100-nsec units since Jan 1, 1601 */ + GetSystemTimeAsFileTime(&ft.ft_ft); + if (ft.ft_64 < EPOCH_BIAS) { + /* LCOV_EXCL_START */ + raw_assert_unreached_msg("System time is before 1970; failing."); + /* LCOV_EXCL_STOP */ + } + ft.ft_64 -= EPOCH_BIAS; + timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC); + timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC); +#elif defined(HAVE_GETTIMEOFDAY) + if (gettimeofday(timeval, NULL)) { + /* LCOV_EXCL_START */ + /* If gettimeofday dies, we have either given a bad timezone (we didn't), + or segfaulted.*/ + raw_assert_unreached_msg("gettimeofday failed"); + /* LCOV_EXCL_STOP */ + } +#elif defined(HAVE_FTIME) + struct timeb tb; + ftime(&tb); + timeval->tv_sec = tb.time; + timeval->tv_usec = tb.millitm * 1000; +#else +#error "No way to get time." +#endif /* defined(_WIN32) || ... */ + return; +} diff --git a/src/lib/wallclock/tor_gettimeofday.h b/src/lib/wallclock/tor_gettimeofday.h new file mode 100644 index 0000000000..728ad9565d --- /dev/null +++ b/src/lib/wallclock/tor_gettimeofday.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_GETTIMEOFDAY_H +#define TOR_GETTIMEOFDAY_H + +#include "lib/testsupport/testsupport.h" + +struct timeval; + +MOCK_DECL(void, tor_gettimeofday, (struct timeval *timeval)); + +#endif diff --git a/src/or/addressmap.c b/src/or/addressmap.c index 7f861e4d24..a0df5c9865 100644 --- a/src/or/addressmap.c +++ b/src/or/addressmap.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,16 +15,18 @@ #define ADDRESSMAP_PRIVATE -#include "or.h" -#include "addressmap.h" -#include "circuituse.h" -#include "config.h" -#include "connection_edge.h" -#include "control.h" -#include "crypto_rand.h" -#include "dns.h" -#include "nodelist.h" -#include "routerset.h" +#include "or/or.h" +#include "or/addressmap.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "or/connection_edge.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/dns.h" +#include "or/nodelist.h" +#include "or/routerset.h" + +#include "or/entry_connection_st.h" /** A client-side struct to remember requests to rewrite addresses * to new addresses. These structs are stored in the hash table diff --git a/src/or/addressmap.h b/src/or/addressmap.h index 1544b76e10..b0db5c8b4e 100644 --- a/src/or/addressmap.h +++ b/src/or/addressmap.h @@ -1,13 +1,13 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_ADDRESSMAP_H #define TOR_ADDRESSMAP_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" void addressmap_init(void); void addressmap_clear_excluded_trackexithosts(const or_options_t *options); diff --git a/src/or/authority_cert_st.h b/src/or/authority_cert_st.h new file mode 100644 index 0000000000..19c3fda2de --- /dev/null +++ b/src/or/authority_cert_st.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef AUTHORITY_CERT_ST_H +#define AUTHORITY_CERT_ST_H + +#include "or/signed_descriptor_st.h" + +/** Certificate for v3 directory protocol: binds long-term authority identity + * keys to medium-term authority signing keys. */ +struct authority_cert_t { + /** Information relating to caching this cert on disk and looking it up. */ + signed_descriptor_t cache_info; + /** This authority's long-term authority identity key. */ + crypto_pk_t *identity_key; + /** This authority's medium-term signing key. */ + crypto_pk_t *signing_key; + /** The digest of <b>signing_key</b> */ + char signing_key_digest[DIGEST_LEN]; + /** The listed expiration time of this certificate. */ + time_t expires; + /** This authority's IPv4 address, in host order. */ + uint32_t addr; + /** This authority's directory port. */ + uint16_t dir_port; +}; + +#endif + diff --git a/src/or/bridges.c b/src/or/bridges.c index 699e030e6c..ca0a13f2a0 100644 --- a/src/or/bridges.c +++ b/src/or/bridges.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,19 +13,24 @@ #define TOR_BRIDGES_PRIVATE -#include "or.h" -#include "bridges.h" -#include "circuitbuild.h" -#include "config.h" -#include "connection.h" -#include "directory.h" -#include "entrynodes.h" -#include "nodelist.h" -#include "policies.h" -#include "router.h" -#include "routerlist.h" -#include "routerset.h" -#include "transports.h" +#include "or/or.h" +#include "or/bridges.h" +#include "or/circuitbuild.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/directory.h" +#include "or/entrynodes.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerset.h" +#include "or/transports.h" + +#include "or/extend_info_st.h" +#include "or/node_st.h" +#include "or/routerinfo_st.h" +#include "or/routerstatus_st.h" /** Information about a configured bridge. Currently this just matches the * ones in the torrc file, but one day we may be able to learn about new diff --git a/src/or/bridges.h b/src/or/bridges.h index 3108eb555d..d6fec4b46d 100644 --- a/src/or/bridges.h +++ b/src/or/bridges.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/cached_dir_st.h b/src/or/cached_dir_st.h new file mode 100644 index 0000000000..38ae86d975 --- /dev/null +++ b/src/or/cached_dir_st.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CACHED_DIR_ST_H +#define CACHED_DIR_ST_H + +/** A cached_dir_t represents a cacheable directory object, along with its + * compressed form. */ +struct cached_dir_t { + char *dir; /**< Contents of this object, NUL-terminated. */ + char *dir_compressed; /**< Compressed contents of this object. */ + size_t dir_len; /**< Length of <b>dir</b> (not counting its NUL). */ + size_t dir_compressed_len; /**< Length of <b>dir_compressed</b>. */ + time_t published; /**< When was this object published. */ + common_digests_t digests; /**< Digests of this object (networkstatus only) */ + /** Sha3 digest (also ns only) */ + uint8_t digest_sha3_as_signed[DIGEST256_LEN]; + int refcnt; /**< Reference count for this cached_dir_t. */ +}; + +#endif + diff --git a/src/or/cell_queue_st.h b/src/or/cell_queue_st.h new file mode 100644 index 0000000000..4ad98dafbf --- /dev/null +++ b/src/or/cell_queue_st.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef PACKED_CELL_ST_H +#define PACKED_CELL_ST_H + +/** A cell as packed for writing to the network. */ +struct packed_cell_t { + /** Next cell queued on this circuit. */ + TOR_SIMPLEQ_ENTRY(packed_cell_t) next; + char body[CELL_MAX_NETWORK_SIZE]; /**< Cell as packed for network. */ + uint32_t inserted_timestamp; /**< Time (in timestamp units) when this cell + * was inserted */ +}; + +/** A queue of cells on a circuit, waiting to be added to the + * or_connection_t's outbuf. */ +struct cell_queue_t { + /** Linked list of packed_cell_t*/ + TOR_SIMPLEQ_HEAD(cell_simpleq, packed_cell_t) head; + int n; /**< The number of cells in the queue. */ +}; + +#endif + diff --git a/src/or/cell_st.h b/src/or/cell_st.h new file mode 100644 index 0000000000..6728e783b9 --- /dev/null +++ b/src/or/cell_st.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CELL_ST_H +#define CELL_ST_H + +/** Parsed onion routing cell. All communication between nodes + * is via cells. */ +struct cell_t { + circid_t circ_id; /**< Circuit which received the cell. */ + uint8_t command; /**< Type of the cell: one of CELL_PADDING, CELL_CREATE, + * CELL_DESTROY, etc */ + uint8_t payload[CELL_PAYLOAD_SIZE]; /**< Cell body. */ +}; + +#endif + diff --git a/src/or/channel.c b/src/or/channel.c index c30e508018..ac1960ae03 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -1,5 +1,5 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -57,28 +57,30 @@ /* This one's for stuff only channel.c and the test suite should see */ #define CHANNEL_PRIVATE_ -#include "or.h" -#include "channel.h" -#include "channeltls.h" -#include "channelpadding.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitstats.h" -#include "config.h" -#include "connection_or.h" /* For var_cell_free() */ -#include "circuitmux.h" -#include "entrynodes.h" -#include "geoip.h" -#include "main.h" -#include "nodelist.h" -#include "relay.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "scheduler.h" -#include "compat_time.h" -#include "networkstatus.h" -#include "rendservice.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/channeltls.h" +#include "or/channelpadding.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuitstats.h" +#include "or/config.h" +#include "or/connection_or.h" /* For var_cell_free() */ +#include "or/circuitmux.h" +#include "or/entrynodes.h" +#include "or/geoip.h" +#include "or/main.h" +#include "or/nodelist.h" +#include "or/relay.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/scheduler.h" +#include "lib/time/compat_time.h" +#include "or/networkstatus.h" +#include "or/rendservice.h" + +#include "or/cell_queue_st.h" /* Global lists of channels */ diff --git a/src/or/channel.h b/src/or/channel.h index 6cf8cd7f72..44b752e2c5 100644 --- a/src/or/channel.h +++ b/src/or/channel.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,10 +9,10 @@ #ifndef TOR_CHANNEL_H #define TOR_CHANNEL_H -#include "or.h" -#include "circuitmux.h" -#include "timers.h" -#include "handles.h" +#include "or/or.h" +#include "or/circuitmux.h" +#include "common/timers.h" +#include "common/handles.h" /* Channel handler function pointer typedefs */ typedef void (*channel_listener_fn_ptr)(channel_listener_t *, channel_t *); diff --git a/src/or/channelpadding.c b/src/or/channelpadding.c index a8b9a2b47b..6bef4d8b3d 100644 --- a/src/or/channelpadding.c +++ b/src/or/channelpadding.c @@ -1,27 +1,30 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2015, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* TOR_CHANNEL_INTERNAL_ define needed for an O(1) implementation of * channelpadding_channel_to_channelinfo() */ #define TOR_CHANNEL_INTERNAL_ -#include "or.h" -#include "channel.h" -#include "channelpadding.h" -#include "channeltls.h" -#include "config.h" -#include "networkstatus.h" -#include "connection.h" -#include "connection_or.h" -#include "crypto_rand.h" -#include "main.h" -#include "rephist.h" -#include "router.h" -#include "compat_time.h" -#include "rendservice.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/channelpadding.h" +#include "or/channeltls.h" +#include "or/config.h" +#include "or/networkstatus.h" +#include "or/connection.h" +#include "or/connection_or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/main.h" +#include "or/rephist.h" +#include "or/router.h" +#include "lib/time/compat_time.h" +#include "or/rendservice.h" + +#include "or/cell_st.h" +#include "or/or_connection_st.h" STATIC int32_t channelpadding_get_netflow_inactive_timeout_ms( const channel_t *); diff --git a/src/or/channelpadding.h b/src/or/channelpadding.h index 58bf741d5c..7eddbdbe2d 100644 --- a/src/or/channelpadding.h +++ b/src/or/channelpadding.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2015, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,7 +11,7 @@ #ifndef TOR_CHANNELPADDING_H #define TOR_CHANNELPADDING_H -#include "channelpadding_negotiation.h" +#include "trunnel/channelpadding_negotiation.h" #define CHANNELPADDING_TOR2WEB_PARAM "nf_pad_tor2web" #define CHANNELPADDING_TOR2WEB_DEFAULT 1 diff --git a/src/or/channeltls.c b/src/or/channeltls.c index 54d94f6109..5258935aee 100644 --- a/src/or/channeltls.c +++ b/src/or/channeltls.c @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -38,27 +38,36 @@ #define CHANNELTLS_PRIVATE -#include "or.h" -#include "channel.h" -#include "channeltls.h" -#include "circuitmux.h" -#include "circuitmux_ewma.h" -#include "command.h" -#include "config.h" -#include "connection.h" -#include "connection_or.h" -#include "control.h" -#include "entrynodes.h" -#include "link_handshake.h" -#include "relay.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "scheduler.h" -#include "torcert.h" -#include "networkstatus.h" -#include "channelpadding_negotiation.h" -#include "channelpadding.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/channeltls.h" +#include "or/circuitmux.h" +#include "or/circuitmux_ewma.h" +#include "or/command.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_or.h" +#include "or/control.h" +#include "or/entrynodes.h" +#include "trunnel/link_handshake.h" +#include "or/relay.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/scheduler.h" +#include "or/torcert.h" +#include "or/networkstatus.h" +#include "trunnel/channelpadding_negotiation.h" +#include "or/channelpadding.h" + +#include "or/cell_st.h" +#include "or/cell_queue_st.h" +#include "or/extend_info_st.h" +#include "or/or_connection_st.h" +#include "or/or_handshake_certs_st.h" +#include "or/or_handshake_state_st.h" +#include "or/routerinfo_st.h" +#include "or/var_cell_st.h" /** How many CELL_PADDING cells have we received, ever? */ uint64_t stats_n_padding_cells_processed = 0; diff --git a/src/or/channeltls.h b/src/or/channeltls.h index d9c4239c3a..be74127c9a 100644 --- a/src/or/channeltls.h +++ b/src/or/channeltls.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,8 @@ #ifndef TOR_CHANNELTLS_H #define TOR_CHANNELTLS_H -#include "or.h" -#include "channel.h" +#include "or/or.h" +#include "or/channel.h" #define BASE_CHAN_TO_TLS(c) (channel_tls_from_base((c))) #define TLS_CHAN_TO_BASE(c) (channel_tls_to_base((c))) diff --git a/src/or/circpathbias.c b/src/or/circpathbias.c index ff42bf91e4..32b3212d3f 100644 --- a/src/or/circpathbias.c +++ b/src/or/circpathbias.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,19 +21,27 @@ * each guard, and stored persistently in the state file. */ -#include "or.h" -#include "channel.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "circuitstats.h" -#include "connection_edge.h" -#include "config.h" -#include "crypto_rand.h" -#include "entrynodes.h" -#include "networkstatus.h" -#include "relay.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/circpathbias.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/circuitstats.h" +#include "or/connection_edge.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/entrynodes.h" +#include "or/networkstatus.h" +#include "or/relay.h" +#include "lib/math/fp.h" +#include "lib/math/laplace.h" + +#include "or/cell_st.h" +#include "or/cpath_build_state_st.h" +#include "or/crypt_path_st.h" +#include "or/extend_info_st.h" +#include "or/origin_circuit_st.h" static void pathbias_count_successful_close(origin_circuit_t *circ); static void pathbias_count_collapse(origin_circuit_t *circ); @@ -1568,4 +1576,3 @@ pathbias_scale_use_rates(entry_guard_t *guard) entry_guards_changed(); } } - diff --git a/src/or/circpathbias.h b/src/or/circpathbias.h index c9e572d2ae..09162c40e5 100644 --- a/src/or/circpathbias.h +++ b/src/or/circpathbias.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/circuit_st.h b/src/or/circuit_st.h new file mode 100644 index 0000000000..0ace64f3ee --- /dev/null +++ b/src/or/circuit_st.h @@ -0,0 +1,172 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CIRCUIT_ST_H +#define CIRCUIT_ST_H + +#include "or/or.h" + +#include "or/cell_queue_st.h" + +/** + * A circuit is a path over the onion routing + * network. Applications can connect to one end of the circuit, and can + * create exit connections at the other end of the circuit. AP and exit + * connections have only one circuit associated with them (and thus these + * connection types are closed when the circuit is closed), whereas + * OR connections multiplex many circuits at once, and stay standing even + * when there are no circuits running over them. + * + * A circuit_t structure can fill one of two roles. First, a or_circuit_t + * links two connections together: either an edge connection and an OR + * connection, or two OR connections. (When joined to an OR connection, a + * circuit_t affects only cells sent to a particular circID on that + * connection. When joined to an edge connection, a circuit_t affects all + * data.) + + * Second, an origin_circuit_t holds the cipher keys and state for sending data + * along a given circuit. At the OP, it has a sequence of ciphers, each + * of which is shared with a single OR along the circuit. Separate + * ciphers are used for data going "forward" (away from the OP) and + * "backward" (towards the OP). At the OR, a circuit has only two stream + * ciphers: one for data going forward, and one for data going backward. + */ +struct circuit_t { + uint32_t magic; /**< For memory and type debugging: must equal + * ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */ + + /** The channel that is next in this circuit. */ + channel_t *n_chan; + + /** + * The circuit_id used in the next (forward) hop of this circuit; + * this is unique to n_chan, but this ordered pair is globally + * unique: + * + * (n_chan->global_identifier, n_circ_id) + */ + circid_t n_circ_id; + + /** + * Circuit mux associated with n_chan to which this circuit is attached; + * NULL if we have no n_chan. + */ + circuitmux_t *n_mux; + + /** Queue of cells waiting to be transmitted on n_chan */ + cell_queue_t n_chan_cells; + + /** + * The hop to which we want to extend this circuit. Should be NULL if + * the circuit has attached to a channel. + */ + extend_info_t *n_hop; + + /** True iff we are waiting for n_chan_cells to become less full before + * allowing p_streams to add any more cells. (Origin circuit only.) */ + unsigned int streams_blocked_on_n_chan : 1; + /** True iff we are waiting for p_chan_cells to become less full before + * allowing n_streams to add any more cells. (OR circuit only.) */ + unsigned int streams_blocked_on_p_chan : 1; + + /** True iff we have queued a delete backwards on this circuit, but not put + * it on the output buffer. */ + unsigned int p_delete_pending : 1; + /** True iff we have queued a delete forwards on this circuit, but not put + * it on the output buffer. */ + unsigned int n_delete_pending : 1; + + /** True iff this circuit has received a DESTROY cell in either direction */ + unsigned int received_destroy : 1; + + uint8_t state; /**< Current status of this circuit. */ + uint8_t purpose; /**< Why are we creating this circuit? */ + + /** How many relay data cells can we package (read from edge streams) + * on this circuit before we receive a circuit-level sendme cell asking + * for more? */ + int package_window; + /** How many relay data cells will we deliver (write to edge streams) + * on this circuit? When deliver_window gets low, we send some + * circuit-level sendme cells to indicate that we're willing to accept + * more. */ + int deliver_window; + + /** Temporary field used during circuits_handle_oom. */ + uint32_t age_tmp; + + /** For storage while n_chan is pending (state CIRCUIT_STATE_CHAN_WAIT). */ + struct create_cell_t *n_chan_create_cell; + + /** When did circuit construction actually begin (ie send the + * CREATE cell or begin cannibalization). + * + * Note: This timer will get reset if we decide to cannibalize + * a circuit. It may also get reset during certain phases of hidden + * service circuit use. + * + * We keep this timestamp with a higher resolution than most so that the + * circuit-build-time tracking code can get millisecond resolution. + */ + struct timeval timestamp_began; + + /** This timestamp marks when the init_circuit_base constructor ran. */ + struct timeval timestamp_created; + + /** When the circuit was first used, or 0 if the circuit is clean. + * + * XXXX Note that some code will artificially adjust this value backward + * in time in order to indicate that a circuit shouldn't be used for new + * streams, but that it can stay alive as long as it has streams on it. + * That's a kludge we should fix. + * + * XXX The CBT code uses this field to record when HS-related + * circuits entered certain states. This usage probably won't + * interfere with this field's primary purpose, but we should + * document it more thoroughly to make sure of that. + * + * XXX The SocksPort option KeepaliveIsolateSOCKSAuth will artificially + * adjust this value forward each time a suitable stream is attached to an + * already constructed circuit, potentially keeping the circuit alive + * indefinitely. + */ + time_t timestamp_dirty; + + uint16_t marked_for_close; /**< Should we close this circuit at the end of + * the main loop? (If true, holds the line number + * where this circuit was marked.) */ + const char *marked_for_close_file; /**< For debugging: in which file was this + * circuit marked for close? */ + /** For what reason (See END_CIRC_REASON...) is this circuit being closed? + * This field is set in circuit_mark_for_close and used later in + * circuit_about_to_free. */ + int marked_for_close_reason; + /** As marked_for_close_reason, but reflects the underlying reason for + * closing this circuit. + */ + int marked_for_close_orig_reason; + + /** Unique ID for measuring tunneled network status requests. */ + uint64_t dirreq_id; + + /** Index in smartlist of all circuits (global_circuitlist). */ + int global_circuitlist_idx; + + /** Various statistics about cells being added to or removed from this + * circuit's queues; used only if CELL_STATS events are enabled and + * cleared after being sent to control port. */ + smartlist_t *testing_cell_stats; + + /** If set, points to an HS token that this circuit might be carrying. + * Used by the HS circuitmap. */ + hs_token_t *hs_token; + /** Hashtable node: used to look up the circuit by its HS token using the HS + circuitmap. */ + HT_ENTRY(circuit_t) hs_circuitmap_node; +}; + +#endif + diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 3d1c9c1abf..28295147cc 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,43 +27,54 @@ #define CIRCUITBUILD_PRIVATE -#include "or.h" -#include "bridges.h" -#include "channel.h" -#include "circpathbias.h" +#include "or/or.h" +#include "or/bridges.h" +#include "or/channel.h" +#include "or/circpathbias.h" #define CIRCUITBUILD_PRIVATE -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitstats.h" -#include "circuituse.h" -#include "command.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_rand.h" -#include "directory.h" -#include "entrynodes.h" -#include "hs_ntor.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "onion.h" -#include "onion_tap.h" -#include "onion_fast.h" -#include "policies.h" -#include "relay.h" -#include "relay_crypto.h" -#include "rendcommon.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "transports.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuitstats.h" +#include "or/circuituse.h" +#include "or/command.h" +#include "or/config.h" +#include "or/confparse.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/connection_or.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/directory.h" +#include "or/entrynodes.h" +#include "or/hs_ntor.h" +#include "or/main.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/onion.h" +#include "or/onion_tap.h" +#include "or/onion_fast.h" +#include "or/policies.h" +#include "or/relay.h" +#include "or/relay_crypto.h" +#include "or/rendcommon.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/routerset.h" +#include "or/transports.h" + +#include "or/cell_st.h" +#include "or/cpath_build_state_st.h" +#include "or/entry_connection_st.h" +#include "or/extend_info_st.h" +#include "or/node_st.h" +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" +#include "or/microdesc_st.h" +#include "or/routerinfo_st.h" +#include "or/routerstatus_st.h" static channel_t * channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port, diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 0184898e29..ffbb31e0d8 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 45fff7cc17..a696533ae4 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -1,7 +1,7 @@ /* Copyright 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -51,46 +51,55 @@ * logic, which was originally circuit-focused. **/ #define CIRCUITLIST_PRIVATE -#include "torint.h" /* TOR_PRIuSZ */ - -#include "or.h" -#include "channel.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "circuitstats.h" -#include "connection.h" -#include "config.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "entrynodes.h" -#include "main.h" -#include "hs_circuit.h" -#include "hs_circuitmap.h" -#include "hs_ident.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "onion.h" -#include "onion_fast.h" -#include "policies.h" -#include "relay.h" -#include "relay_crypto.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rephist.h" -#include "routerlist.h" -#include "routerset.h" -#include "channelpadding.h" -#include "compress_lzma.h" -#include "compress_zlib.h" -#include "compress_zstd.h" +#include "lib/cc/torint.h" /* TOR_PRIuSZ */ + +#include "or/or.h" +#include "or/channel.h" +#include "or/circpathbias.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/circuitstats.h" +#include "or/connection.h" +#include "or/config.h" +#include "or/connection_edge.h" +#include "or/connection_or.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/directory.h" +#include "or/entrynodes.h" +#include "or/main.h" +#include "or/hs_circuit.h" +#include "or/hs_circuitmap.h" +#include "or/hs_ident.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/onion.h" +#include "or/onion_fast.h" +#include "or/policies.h" +#include "or/relay.h" +#include "or/relay_crypto.h" +#include "or/rendclient.h" +#include "or/rendcommon.h" +#include "or/rephist.h" +#include "or/routerlist.h" +#include "or/routerset.h" +#include "or/channelpadding.h" +#include "lib/compress/compress_lzma.h" +#include "lib/compress/compress_zlib.h" +#include "lib/compress/compress_zstd.h" #include "ht.h" +#include "or/cpath_build_state_st.h" +#include "or/crypt_path_reference_st.h" +#include "or/dir_connection_st.h" +#include "or/edge_connection_st.h" +#include "or/extend_info_st.h" +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" + /********* START VARIABLES **********/ /** A global list of all circuits at this hop. */ @@ -126,6 +135,31 @@ static int any_opened_circs_cached_val = 0; /********* END VARIABLES ************/ +or_circuit_t * +TO_OR_CIRCUIT(circuit_t *x) +{ + tor_assert(x->magic == OR_CIRCUIT_MAGIC); + return DOWNCAST(or_circuit_t, x); +} +const or_circuit_t * +CONST_TO_OR_CIRCUIT(const circuit_t *x) +{ + tor_assert(x->magic == OR_CIRCUIT_MAGIC); + return DOWNCAST(or_circuit_t, x); +} +origin_circuit_t * +TO_ORIGIN_CIRCUIT(circuit_t *x) +{ + tor_assert(x->magic == ORIGIN_CIRCUIT_MAGIC); + return DOWNCAST(origin_circuit_t, x); +} +const origin_circuit_t * +CONST_TO_ORIGIN_CIRCUIT(const circuit_t *x) +{ + tor_assert(x->magic == ORIGIN_CIRCUIT_MAGIC); + return DOWNCAST(origin_circuit_t, x); +} + /** A map from channel and circuit ID to circuit. (Lookup performance is * very important here, since we need to do it every time a cell arrives.) */ typedef struct chan_circid_circuit_map_t { diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h index 246f0c8815..8b41424eeb 100644 --- a/src/or/circuitlist.h +++ b/src/or/circuitlist.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,17 @@ #ifndef TOR_CIRCUITLIST_H #define TOR_CIRCUITLIST_H -#include "testsupport.h" -#include "hs_ident.h" +#include "lib/testsupport/testsupport.h" +#include "or/hs_ident.h" + +/** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Assert + * if the cast is impossible. */ +or_circuit_t *TO_OR_CIRCUIT(circuit_t *); +const or_circuit_t *CONST_TO_OR_CIRCUIT(const circuit_t *); +/** Convert a circuit_t* to a pointer to the enclosing origin_circuit_t. + * Assert if the cast is impossible. */ +origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *); +const origin_circuit_t *CONST_TO_ORIGIN_CIRCUIT(const circuit_t *); MOCK_DECL(smartlist_t *, circuit_get_global_list, (void)); smartlist_t *circuit_get_global_origin_circuit_list(void); diff --git a/src/or/circuitmux.c b/src/or/circuitmux.c index f9f5faa057..31f9281ebb 100644 --- a/src/or/circuitmux.c +++ b/src/or/circuitmux.c @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -69,11 +69,15 @@ * made to attach all existing circuits to the new policy. **/ -#include "or.h" -#include "channel.h" -#include "circuitlist.h" -#include "circuitmux.h" -#include "relay.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/circuitlist.h" +#include "or/circuitmux.h" +#include "or/relay.h" + +#include "or/cell_queue_st.h" +#include "or/destroy_cell_queue_st.h" +#include "or/or_circuit_st.h" /* * Private typedefs for circuitmux.c diff --git a/src/or/circuitmux.h b/src/or/circuitmux.h index 336e128c76..e94cc354c7 100644 --- a/src/or/circuitmux.h +++ b/src/or/circuitmux.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,8 @@ #ifndef TOR_CIRCUITMUX_H #define TOR_CIRCUITMUX_H -#include "or.h" -#include "testsupport.h" +#include "or/or.h" +#include "lib/testsupport/testsupport.h" typedef struct circuitmux_policy_s circuitmux_policy_t; typedef struct circuitmux_policy_data_s circuitmux_policy_data_t; diff --git a/src/or/circuitmux_ewma.c b/src/or/circuitmux_ewma.c index e5d5a14581..1ee5f1f621 100644 --- a/src/or/circuitmux_ewma.c +++ b/src/or/circuitmux_ewma.c @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -34,11 +34,11 @@ #include <math.h> -#include "or.h" -#include "circuitmux.h" -#include "circuitmux_ewma.h" -#include "crypto_rand.h" -#include "networkstatus.h" +#include "or/or.h" +#include "or/circuitmux.h" +#include "or/circuitmux_ewma.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/networkstatus.h" /*** EWMA parameter #defines ***/ diff --git a/src/or/circuitmux_ewma.h b/src/or/circuitmux_ewma.h index f0c4c36095..1214b0264b 100644 --- a/src/or/circuitmux_ewma.h +++ b/src/or/circuitmux_ewma.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,8 @@ #ifndef TOR_CIRCUITMUX_EWMA_H #define TOR_CIRCUITMUX_EWMA_H -#include "or.h" -#include "circuitmux.h" +#include "or/or.h" +#include "or/circuitmux.h" /* The public EWMA policy callbacks object. */ extern circuitmux_policy_t ewma_policy; diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c index 94f75c590f..c2abb2d14b 100644 --- a/src/or/circuitstats.c +++ b/src/or/circuitstats.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -25,21 +25,26 @@ #define CIRCUITSTATS_PRIVATE -#include "or.h" -#include "circuitbuild.h" -#include "circuitstats.h" -#include "config.h" -#include "confparse.h" -#include "control.h" -#include "crypto_rand.h" -#include "main.h" -#include "networkstatus.h" -#include "rendclient.h" -#include "rendservice.h" -#include "router.h" -#include "statefile.h" -#include "circuitlist.h" -#include "circuituse.h" +#include "or/or.h" +#include "or/circuitbuild.h" +#include "or/circuitstats.h" +#include "or/config.h" +#include "or/confparse.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/main.h" +#include "or/networkstatus.h" +#include "or/rendclient.h" +#include "or/rendservice.h" +#include "or/router.h" +#include "or/statefile.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "lib/math/fp.h" +#include "lib/time/tvdiff.h" + +#include "or/crypt_path_st.h" +#include "or/origin_circuit_st.h" #undef log #include <math.h> @@ -1943,4 +1948,3 @@ cbt_control_event_buildtimeout_set(const circuit_build_times_t *cbt, tor_free(args); } - diff --git a/src/or/circuitstats.h b/src/or/circuitstats.h index 86116cb7f8..d7d1012ce8 100644 --- a/src/or/circuitstats.h +++ b/src/or/circuitstats.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -73,6 +73,21 @@ int circuit_build_times_network_check_live(const circuit_build_times_t *cbt); void circuit_build_times_network_circ_success(circuit_build_times_t *cbt); #ifdef CIRCUITSTATS_PRIVATE +/** Information about the state of our local network connection */ +typedef struct { + /** The timestamp we last completed a TLS handshake or received a cell */ + time_t network_last_live; + /** If the network is not live, how many timeouts has this caused? */ + int nonlive_timeouts; + /** Circular array of circuits that have made it to the first hop. Slot is + * 1 if circuit timed out, 0 if circuit succeeded */ + int8_t *timeouts_after_firsthop; + /** Number of elements allocated for the above array */ + int num_recent_circs; + /** Index into circular array. */ + int after_firsthop_idx; +} network_liveness_t; + /** Structure for circuit build times history */ struct circuit_build_times_s { /** The circular array of recorded build times in milliseconds */ diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 8e007ce920..71abd5d6ce 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,34 +27,45 @@ * logic in circuitstats.c. **/ -#include "or.h" -#include "addressmap.h" -#include "bridges.h" -#include "channel.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitstats.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "control.h" -#include "entrynodes.h" -#include "hs_common.h" -#include "hs_client.h" -#include "hs_circuit.h" -#include "hs_ident.h" -#include "hs_stats.h" -#include "nodelist.h" -#include "networkstatus.h" -#include "policies.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" +#include "or/or.h" +#include "or/addressmap.h" +#include "or/bridges.h" +#include "or/channel.h" +#include "or/circpathbias.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuitstats.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/control.h" +#include "or/directory.h" +#include "or/entrynodes.h" +#include "or/hs_common.h" +#include "or/hs_client.h" +#include "or/hs_circuit.h" +#include "or/hs_ident.h" +#include "or/hs_stats.h" +#include "or/nodelist.h" +#include "or/networkstatus.h" +#include "or/policies.h" +#include "or/rendclient.h" +#include "or/rendcommon.h" +#include "or/rendservice.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "lib/math/fp.h" +#include "lib/time/tvdiff.h" + +#include "or/cpath_build_state_st.h" +#include "or/dir_connection_st.h" +#include "or/entry_connection_st.h" +#include "or/extend_info_st.h" +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" +#include "or/socks_request_st.h" static void circuit_expire_old_circuits_clientside(void); static void circuit_increment_failure_count(void); @@ -3143,4 +3154,3 @@ circuit_read_valid_data(origin_circuit_t *circ, uint16_t relay_body_len) tor_add_u32_nowrap(circ->n_overhead_read_circ_bw, RELAY_PAYLOAD_SIZE-relay_body_len); } - diff --git a/src/or/circuituse.h b/src/or/circuituse.h index 6458bd6908..b65e85d170 100644 --- a/src/or/circuituse.h +++ b/src/or/circuituse.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/command.c b/src/or/command.c index 39950f41bf..387fd49bd2 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -36,25 +36,30 @@ * callbacks registered in command_setup_channel(), * called when channels are created in circuitbuild.c */ -#include "or.h" -#include "channel.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "command.h" -#include "connection.h" -#include "connection_or.h" -#include "config.h" -#include "control.h" -#include "cpuworker.h" -#include "crypto_util.h" -#include "dos.h" -#include "hibernate.h" -#include "nodelist.h" -#include "onion.h" -#include "rephist.h" -#include "relay.h" -#include "router.h" -#include "routerlist.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/command.h" +#include "or/connection.h" +#include "or/connection_or.h" +#include "or/config.h" +#include "or/control.h" +#include "or/cpuworker.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/dos.h" +#include "or/hibernate.h" +#include "or/nodelist.h" +#include "or/onion.h" +#include "or/rephist.h" +#include "or/relay.h" +#include "or/router.h" +#include "or/routerlist.h" + +#include "or/cell_st.h" +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" +#include "or/var_cell_st.h" /** How many CELL_CREATE cells have we received, ever? */ uint64_t stats_n_create_cells_processed = 0; diff --git a/src/or/command.h b/src/or/command.h index c0d1996cbb..864a5b2fd0 100644 --- a/src/or/command.h +++ b/src/or/command.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #ifndef TOR_COMMAND_H #define TOR_COMMAND_H -#include "channel.h" +#include "or/channel.h" void command_process_cell(channel_t *chan, cell_t *cell); void command_process_var_cell(channel_t *chan, var_cell_t *cell); diff --git a/src/or/config.c b/src/or/config.c index 94a58f3488..e3a4faa311 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -2,7 +2,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -60,61 +60,75 @@ **/ #define CONFIG_PRIVATE -#include "or.h" -#include "bridges.h" -#include "compat.h" -#include "addressmap.h" -#include "channel.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitmux.h" -#include "circuitmux_ewma.h" -#include "circuitstats.h" -#include "compress.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "consdiffmgr.h" -#include "control.h" -#include "confparse.h" -#include "cpuworker.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "dirserv.h" -#include "dns.h" -#include "dos.h" -#include "entrynodes.h" -#include "git_revision.h" -#include "geoip.h" -#include "hibernate.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "relay.h" -#include "rendclient.h" -#include "rendservice.h" -#include "hs_config.h" -#include "rephist.h" -#include "router.h" -#include "sandbox.h" -#include "util.h" -#include "routerlist.h" -#include "routerset.h" -#include "scheduler.h" -#include "statefile.h" -#include "transports.h" -#include "ext_orport.h" -#include "voting_schedule.h" +#include "or/or.h" +#include "or/bridges.h" +#include "or/addressmap.h" +#include "or/channel.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuitmux.h" +#include "or/circuitmux_ewma.h" +#include "or/circuitstats.h" +#include "lib/compress/compress.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/connection_or.h" +#include "or/consdiffmgr.h" +#include "or/control.h" +#include "or/confparse.h" +#include "or/cpuworker.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/dirserv.h" +#include "or/dns.h" +#include "or/dos.h" +#include "or/entrynodes.h" +#include "or/git_revision.h" +#include "or/geoip.h" +#include "or/hibernate.h" +#include "or/main.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/relay.h" +#include "or/rendclient.h" +#include "or/rendservice.h" +#include "or/hs_config.h" +#include "or/rephist.h" +#include "or/router.h" +#include "lib/sandbox/sandbox.h" +#include "common/util.h" +#include "or/routerlist.h" +#include "or/routerset.h" +#include "or/scheduler.h" +#include "or/statefile.h" +#include "or/transports.h" +#include "or/ext_orport.h" +#include "or/voting_schedule.h" #ifdef _WIN32 #include <shlobj.h> #endif -#include "procmon.h" +#include "lib/meminfo/meminfo.h" +#include "lib/osinfo/uname.h" +#include "lib/process/daemon.h" +#include "lib/process/pidfile.h" +#include "lib/process/restrict.h" +#include "lib/process/setuid.h" +#include "lib/process/subprocess.h" +#include "lib/net/gethostname.h" +#include "lib/thread/numcpus.h" -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" +#include "lib/encoding/keyval.h" +#include "lib/fs/conffile.h" +#include "common/procmon.h" + +#include "or/dirauth/dirvote.h" +#include "or/dirauth/mode.h" + +#include "or/connection_st.h" +#include "or/port_cfg_st.h" #ifdef HAVE_SYSTEMD # if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__) @@ -2626,7 +2640,7 @@ print_usage(void) printf( "Copyright (c) 2001-2004, Roger Dingledine\n" "Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson\n" -"Copyright (c) 2007-2017, The Tor Project, Inc.\n\n" +"Copyright (c) 2007-2018, The Tor Project, Inc.\n\n" "tor -f <torrc> [args]\n" "See man page for options, or https://www.torproject.org/ for " "documentation.\n"); @@ -5635,6 +5649,23 @@ addressmap_register_auto(const char *from, const char *to, } /** + * As add_file_log, but open the file as appropriate. + */ +STATIC int +open_and_add_file_log(const log_severity_list_t *severity, + const char *filename, int truncate_log) +{ + int open_flags = O_WRONLY|O_CREAT; + open_flags |= truncate_log ? O_TRUNC : O_APPEND; + + int fd = tor_open_cloexec(filename, open_flags, 0640); + if (fd < 0) + return -1; + + return add_file_log(severity, filename, fd); +} + +/** * Initialize the logs based on the configuration file. */ static int @@ -5759,7 +5790,7 @@ options_init_logs(const or_options_t *old_options, or_options_t *options, } } } - if (add_file_log(severity, fname, truncate_log) < 0) { + if (open_and_add_file_log(severity, fname, truncate_log) < 0) { log_warn(LD_CONFIG, "Couldn't open file for 'Log %s': %s", opt->value, strerror(errno)); ok = 0; @@ -8449,4 +8480,3 @@ options_any_client_port_set(const or_options_t *options) options->DNSPort_set || options->HTTPTunnelPort_set); } - diff --git a/src/or/config.h b/src/or/config.h index 4b41274434..d2faf6c512 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #ifndef TOR_CONFIG_H #define TOR_CONFIG_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(DARWIN) #define KERNEL_MAY_SUPPORT_IPFW @@ -271,8 +271,10 @@ STATIC int check_bridge_distribution_setting(const char *bd); STATIC uint64_t compute_real_max_mem_in_queues(const uint64_t val, int log_guess); +STATIC int open_and_add_file_log(const log_severity_list_t *severity, + const char *fname, + int truncate_log); #endif /* defined(CONFIG_PRIVATE) */ #endif /* !defined(TOR_CONFIG_H) */ - diff --git a/src/or/confparse.c b/src/or/confparse.c index 6bab790945..b38e06c6a2 100644 --- a/src/or/confparse.c +++ b/src/or/confparse.c @@ -1,8 +1,7 @@ - /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -22,9 +21,11 @@ * specified, and a linked list of key-value pairs. */ -#include "or.h" -#include "confparse.h" -#include "routerset.h" +#include "or/or.h" +#include "or/confparse.h" +#include "or/routerset.h" + +#include "lib/container/bitarray.h" static uint64_t config_parse_memunit(const char *s, int *ok); static int config_parse_msec_interval(const char *s, int *ok); @@ -1186,4 +1187,3 @@ config_parse_interval(const char *s, int *ok) } return (int)r; } - diff --git a/src/or/confparse.h b/src/or/confparse.h index 4b4bf0adb4..be9785ac18 100644 --- a/src/or/confparse.h +++ b/src/or/confparse.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CONFPARSE_H diff --git a/src/or/connection.c b/src/or/connection.c index 5185b45b14..e3e9c313ae 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -55,54 +55,55 @@ **/ #define CONNECTION_PRIVATE -#include "or.h" -#include "bridges.h" -#include "buffers.h" -#include "buffers_tls.h" +#include "or/or.h" +#include "or/bridges.h" +#include "lib/container/buffers.h" +#include "lib/tls/buffers_tls.h" /* * Define this so we get channel internal functions, since we're implementing * part of a subclass (channel_tls_t). */ #define TOR_CHANNEL_INTERNAL_ #define CONNECTION_PRIVATE -#include "backtrace.h" -#include "channel.h" -#include "channeltls.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_util.h" -#include "directory.h" -#include "dirserv.h" -#include "dns.h" -#include "dnsserv.h" -#include "dos.h" -#include "entrynodes.h" -#include "ext_orport.h" -#include "geoip.h" -#include "main.h" -#include "hibernate.h" -#include "hs_common.h" -#include "hs_ident.h" -#include "nodelist.h" -#include "proto_http.h" -#include "proto_socks.h" -#include "policies.h" -#include "reasons.h" -#include "relay.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "transports.h" -#include "routerparse.h" -#include "sandbox.h" +#include "lib/err/backtrace.h" +#include "or/channel.h" +#include "or/channeltls.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/connection_or.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/directory.h" +#include "or/dirserv.h" +#include "or/dns.h" +#include "or/dnsserv.h" +#include "or/dos.h" +#include "or/entrynodes.h" +#include "or/ext_orport.h" +#include "or/geoip.h" +#include "or/main.h" +#include "or/hibernate.h" +#include "or/hs_common.h" +#include "or/hs_ident.h" +#include "or/nodelist.h" +#include "or/proto_http.h" +#include "or/proto_socks.h" +#include "or/policies.h" +#include "or/reasons.h" +#include "or/relay.h" +#include "or/rendclient.h" +#include "or/rendcommon.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/transports.h" +#include "or/routerparse.h" +#include "lib/sandbox/sandbox.h" +#include "lib/net/buffers_net.h" #ifdef HAVE_PWD_H #include <pwd.h> @@ -113,6 +114,15 @@ #include <sys/un.h> #endif +#include "or/dir_connection_st.h" +#include "or/control_connection_st.h" +#include "or/entry_connection_st.h" +#include "or/listener_connection_st.h" +#include "or/or_connection_st.h" +#include "or/port_cfg_st.h" +#include "or/routerinfo_st.h" +#include "or/socks_request_st.h" + static connection_t *connection_listener_new( const struct sockaddr *listensockaddr, socklen_t listensocklen, int type, @@ -167,6 +177,27 @@ static smartlist_t *outgoing_addrs = NULL; /**************************************************************/ +/** Convert a connection_t* to an listener_connection_t*; assert if the cast + * is invalid. */ +listener_connection_t * +TO_LISTENER_CONN(connection_t *c) +{ + tor_assert(c->magic == LISTENER_CONNECTION_MAGIC); + return DOWNCAST(listener_connection_t, c); +} + +size_t +connection_get_inbuf_len(connection_t *conn) +{ + return conn->inbuf ? buf_datalen(conn->inbuf) : 0; +} + +size_t +connection_get_outbuf_len(connection_t *conn) +{ + return conn->outbuf ? buf_datalen(conn->outbuf) : 0; +} + /** * Return the human-readable name for the connection type <b>type</b> */ @@ -4108,6 +4139,13 @@ connection_write_to_buf_impl_,(const char *string, size_t len, connection_write_to_buf_commit(conn, written); } +void +connection_buf_add_compress(const char *string, size_t len, + dir_connection_t *conn, int done) +{ + connection_write_to_buf_impl_(string, len, TO_CONN(conn), done ? -1 : 1); +} + /** * Add all bytes from <b>buf</b> to <b>conn</b>'s outbuf, draining them * from <b>buf</b>. (If the connection is marked and will soon be closed, @@ -4812,6 +4850,20 @@ kill_conn_list_for_oos, (smartlist_t *conns)) smartlist_len(conns)); } +/** Check if a connection is on the way out so the OOS handler doesn't try + * to kill more than it needs. */ +int +connection_is_moribund(connection_t *conn) +{ + if (conn != NULL && + (conn->conn_array_index < 0 || + conn->marked_for_close)) { + return 1; + } else { + return 0; + } +} + /** Out-of-Sockets handler; n_socks is the current number of open * sockets, and failed is non-zero if a socket exhaustion related * error immediately preceded this call. This is where to do @@ -5264,4 +5316,3 @@ clock_skew_warning, (const connection_t *conn, long apparent_skew, int trusted, tor_free(warn); tor_free(ext_source); } - diff --git a/src/or/connection.h b/src/or/connection.h index ad3129c9d8..1bbe17bffd 100644 --- a/src/or/connection.h +++ b/src/or/connection.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,10 @@ #ifndef TOR_CONNECTION_H #define TOR_CONNECTION_H +listener_connection_t *TO_LISTENER_CONN(connection_t *); + /* XXXX For buf_datalen in inline function */ -#include "buffers.h" +#include "lib/container/buffers.h" const char *conn_type_to_string(int type); const char *conn_state_to_string(int type, int state); @@ -150,39 +152,17 @@ MOCK_DECL(void, connection_write_to_buf_impl_, /* DOCDOC connection_write_to_buf */ static void connection_buf_add(const char *string, size_t len, connection_t *conn); -/* DOCDOC connection_write_to_buf_compress */ -static void connection_buf_add_compress(const char *string, size_t len, - dir_connection_t *conn, int done); static inline void connection_buf_add(const char *string, size_t len, connection_t *conn) { connection_write_to_buf_impl_(string, len, conn, 0); } -static inline void -connection_buf_add_compress(const char *string, size_t len, - dir_connection_t *conn, int done) -{ - connection_write_to_buf_impl_(string, len, TO_CONN(conn), done ? -1 : 1); -} +void connection_buf_add_compress(const char *string, size_t len, + dir_connection_t *conn, int done); void connection_buf_add_buf(connection_t *conn, buf_t *buf); -/* DOCDOC connection_get_inbuf_len */ -static size_t connection_get_inbuf_len(connection_t *conn); -/* DOCDOC connection_get_outbuf_len */ -static size_t connection_get_outbuf_len(connection_t *conn); - -static inline size_t -connection_get_inbuf_len(connection_t *conn) -{ - return conn->inbuf ? buf_datalen(conn->inbuf) : 0; -} - -static inline size_t -connection_get_outbuf_len(connection_t *conn) -{ - return conn->outbuf ? buf_datalen(conn->outbuf) : 0; -} - +size_t connection_get_inbuf_len(connection_t *conn); +size_t connection_get_outbuf_len(connection_t *conn); connection_t *connection_get_by_global_id(uint64_t id); connection_t *connection_get_by_type(int type); @@ -259,20 +239,7 @@ MOCK_DECL(void, clock_skew_warning, log_domain_mask_t domain, const char *received, const char *source)); -/** Check if a connection is on the way out so the OOS handler doesn't try - * to kill more than it needs. */ -static inline int -connection_is_moribund(connection_t *conn) -{ - if (conn != NULL && - (conn->conn_array_index < 0 || - conn->marked_for_close)) { - return 1; - } else { - return 0; - } -} - +int connection_is_moribund(connection_t *conn); void connection_check_oos(int n_socks, int failed); #ifdef CONNECTION_PRIVATE diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 046369af60..e8185a5faa 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -55,47 +55,57 @@ **/ #define CONNECTION_EDGE_PRIVATE -#include "or.h" - -#include "backtrace.h" - -#include "addressmap.h" -#include "buffers.h" -#include "channel.h" -#include "circpathbias.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_util.h" -#include "dns.h" -#include "dnsserv.h" -#include "directory.h" -#include "dirserv.h" -#include "hibernate.h" -#include "hs_common.h" -#include "hs_cache.h" -#include "hs_client.h" -#include "hs_circuit.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "proto_http.h" -#include "proto_socks.h" -#include "reasons.h" -#include "relay.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerset.h" -#include "circuitbuild.h" +#include "or/or.h" + +#include "lib/err/backtrace.h" + +#include "or/addressmap.h" +#include "lib/container/buffers.h" +#include "or/channel.h" +#include "or/circpathbias.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/connection_or.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/dns.h" +#include "or/dnsserv.h" +#include "or/directory.h" +#include "or/dirserv.h" +#include "or/hibernate.h" +#include "or/hs_common.h" +#include "or/hs_cache.h" +#include "or/hs_client.h" +#include "or/hs_circuit.h" +#include "or/main.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/proto_http.h" +#include "or/proto_socks.h" +#include "or/reasons.h" +#include "or/relay.h" +#include "or/rendclient.h" +#include "or/rendcommon.h" +#include "or/rendservice.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerset.h" +#include "or/circuitbuild.h" + +#include "or/cell_st.h" +#include "or/cpath_build_state_st.h" +#include "or/dir_connection_st.h" +#include "or/entry_connection_st.h" +#include "or/extend_info_st.h" +#include "or/node_st.h" +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" +#include "or/socks_request_st.h" #ifdef HAVE_LINUX_TYPES_H #include <linux/types.h> @@ -137,6 +147,30 @@ static int connection_exit_connect_dir(edge_connection_t *exitconn); static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port); static int connection_ap_supports_optimistic_data(const entry_connection_t *); +/** Convert a connection_t* to an edge_connection_t*; assert if the cast is + * invalid. */ +edge_connection_t * +TO_EDGE_CONN(connection_t *c) +{ + tor_assert(c->magic == EDGE_CONNECTION_MAGIC || + c->magic == ENTRY_CONNECTION_MAGIC); + return DOWNCAST(edge_connection_t, c); +} + +entry_connection_t * +TO_ENTRY_CONN(connection_t *c) +{ + tor_assert(c->magic == ENTRY_CONNECTION_MAGIC); + return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_.base_); +} + +entry_connection_t * +EDGE_TO_ENTRY_CONN(edge_connection_t *c) +{ + tor_assert(c->base_.magic == ENTRY_CONNECTION_MAGIC); + return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_); +} + /** An AP stream has failed/finished. If it hasn't already sent back * a socks reply, send one now (based on endreason). Also set * has_sent_end to 1, and mark the conn. diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h index c6583d3845..d6774668d8 100644 --- a/src/or/connection_edge.h +++ b/src/or/connection_edge.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,9 +12,13 @@ #ifndef TOR_CONNECTION_EDGE_H #define TOR_CONNECTION_EDGE_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" -#define connection_mark_unattached_ap(conn, endreason) \ +edge_connection_t *TO_EDGE_CONN(connection_t *); +entry_connection_t *TO_ENTRY_CONN(connection_t *); +entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *); + +#define connection_mark_unattached_ap(conn, endreason) \ connection_mark_unattached_ap_((conn), (endreason), __LINE__, SHORT_FILE__) MOCK_DECL(void,connection_mark_unattached_ap_, diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 7898fbd42e..9692e5d676 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -20,46 +20,54 @@ * * This module also implements the client side of the v3 Tor link handshake, **/ -#include "or.h" -#include "bridges.h" -#include "buffers.h" +#include "or/or.h" +#include "or/bridges.h" +#include "lib/container/buffers.h" /* * Define this so we get channel internal functions, since we're implementing * part of a subclass (channel_tls_t). */ #define TOR_CHANNEL_INTERNAL_ #define CONNECTION_OR_PRIVATE -#include "channel.h" -#include "channeltls.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitstats.h" -#include "command.h" -#include "config.h" -#include "connection.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "dirserv.h" -#include "entrynodes.h" -#include "geoip.h" -#include "main.h" -#include "link_handshake.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "proto_cell.h" -#include "reasons.h" -#include "relay.h" -#include "rephist.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "ext_orport.h" -#include "scheduler.h" -#include "torcert.h" -#include "channelpadding.h" +#include "or/channel.h" +#include "or/channeltls.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuitstats.h" +#include "or/command.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_or.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/dirserv.h" +#include "or/entrynodes.h" +#include "or/geoip.h" +#include "or/main.h" +#include "trunnel/link_handshake.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/proto_cell.h" +#include "or/reasons.h" +#include "or/relay.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerkeys.h" +#include "or/routerlist.h" +#include "or/ext_orport.h" +#include "or/scheduler.h" +#include "or/torcert.h" +#include "or/channelpadding.h" + +#include "or/cell_st.h" +#include "or/cell_queue_st.h" +#include "or/or_connection_st.h" +#include "or/or_handshake_certs_st.h" +#include "or/or_handshake_state_st.h" +#include "or/routerinfo_st.h" +#include "or/var_cell_st.h" static int connection_tls_finish_handshake(or_connection_t *conn); static int connection_or_launch_v3_or_handshake(or_connection_t *conn); @@ -86,6 +94,15 @@ static void connection_or_check_canonicity(or_connection_t *conn, /**************************************************************/ +/** Convert a connection_t* to an or_connection_t*; assert if the cast is + * invalid. */ +or_connection_t * +TO_OR_CONN(connection_t *c) +{ + tor_assert(c->magic == OR_CONNECTION_MAGIC); + return DOWNCAST(or_connection_t, c); +} + /** Global map between Extended ORPort identifiers and OR * connections. */ static digestmap_t *orconn_ext_or_id_map = NULL; diff --git a/src/or/connection_or.h b/src/or/connection_or.h index 158eb1fdad..41abc199d3 100644 --- a/src/or/connection_or.h +++ b/src/or/connection_or.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,6 +12,8 @@ #ifndef TOR_CONNECTION_OR_H #define TOR_CONNECTION_OR_H +or_connection_t *TO_OR_CONN(connection_t *); + void connection_or_clear_identity(or_connection_t *conn); void connection_or_clear_identity_map(void); void clear_broken_connection_map(int disable); diff --git a/src/or/connection_st.h b/src/or/connection_st.h new file mode 100644 index 0000000000..2e785c6e6e --- /dev/null +++ b/src/or/connection_st.h @@ -0,0 +1,131 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CONNECTION_ST_H +#define CONNECTION_ST_H + +struct buf_t; + +/** Description of a connection to another host or process, and associated + * data. + * + * A connection is named based on what it's connected to -- an "OR + * connection" has a Tor node on the other end, an "exit + * connection" has a website or other server on the other end, and an + * "AP connection" has an application proxy (and thus a user) on the + * other end. + * + * Every connection has a type and a state. Connections never change + * their type, but can go through many state changes in their lifetime. + * + * Every connection has two associated input and output buffers. + * Listeners don't use them. For non-listener connections, incoming + * data is appended to conn->inbuf, and outgoing data is taken from + * conn->outbuf. Connections differ primarily in the functions called + * to fill and drain these buffers. + */ +struct connection_t { + uint32_t magic; /**< For memory debugging: must equal one of + * *_CONNECTION_MAGIC. */ + + uint8_t state; /**< Current state of this connection. */ + unsigned int type:5; /**< What kind of connection is this? */ + unsigned int purpose:5; /**< Only used for DIR and EXIT types currently. */ + + /* The next fields are all one-bit booleans. Some are only applicable to + * connection subtypes, but we hold them here anyway, to save space. + */ + unsigned int read_blocked_on_bw:1; /**< Boolean: should we start reading + * again once the bandwidth throttler allows it? */ + unsigned int write_blocked_on_bw:1; /**< Boolean: should we start writing + * again once the bandwidth throttler allows + * writes? */ + unsigned int hold_open_until_flushed:1; /**< Despite this connection's being + * marked for close, do we flush it + * before closing it? */ + unsigned int inbuf_reached_eof:1; /**< Boolean: did read() return 0 on this + * conn? */ + /** Set to 1 when we're inside connection_flushed_some to keep us from + * calling connection_handle_write() recursively. */ + unsigned int in_flushed_some:1; + /** True if connection_handle_write is currently running on this connection. + */ + unsigned int in_connection_handle_write:1; + + /* For linked connections: + */ + unsigned int linked:1; /**< True if there is, or has been, a linked_conn. */ + /** True iff we'd like to be notified about read events from the + * linked conn. */ + unsigned int reading_from_linked_conn:1; + /** True iff we're willing to write to the linked conn. */ + unsigned int writing_to_linked_conn:1; + /** True iff we're currently able to read on the linked conn, and our + * read_event should be made active with libevent. */ + unsigned int active_on_link:1; + /** True iff we've called connection_close_immediate() on this linked + * connection. */ + unsigned int linked_conn_is_closed:1; + + /** CONNECT/SOCKS proxy client handshake state (for outgoing connections). */ + unsigned int proxy_state:4; + + /** Our socket; set to TOR_INVALID_SOCKET if this connection is closed, + * or has no socket. */ + tor_socket_t s; + int conn_array_index; /**< Index into the global connection array. */ + + struct event *read_event; /**< Libevent event structure. */ + struct event *write_event; /**< Libevent event structure. */ + struct buf_t *inbuf; /**< Buffer holding data read over this connection. */ + struct buf_t *outbuf; /**< Buffer holding data to write over this + * connection. */ + size_t outbuf_flushlen; /**< How much data should we try to flush from the + * outbuf? */ + time_t timestamp_last_read_allowed; /**< When was the last time libevent said + * we could read? */ + time_t timestamp_last_write_allowed; /**< When was the last time libevent + * said we could write? */ + + time_t timestamp_created; /**< When was this connection_t created? */ + + int socket_family; /**< Address family of this connection's socket. Usually + * AF_INET, but it can also be AF_UNIX, or AF_INET6 */ + tor_addr_t addr; /**< IP that socket "s" is directly connected to; + * may be the IP address for a proxy or pluggable transport, + * see "address" for the address of the final destination. + */ + uint16_t port; /**< If non-zero, port that socket "s" is directly connected + * to; may be the port for a proxy or pluggable transport, + * see "address" for the port at the final destination. */ + uint16_t marked_for_close; /**< Should we close this conn on the next + * iteration of the main loop? (If true, holds + * the line number where this connection was + * marked.) */ + const char *marked_for_close_file; /**< For debugging: in which file were + * we marked for close? */ + char *address; /**< FQDN (or IP) and port of the final destination for this + * connection; this is always the remote address, it is + * passed to a proxy or pluggable transport if one in use. + * See "addr" and "port" for the address that socket "s" is + * directly connected to. + * strdup into this, because free_connection() frees it. */ + /** Another connection that's connected to this one in lieu of a socket. */ + struct connection_t *linked_conn; + + /** Unique identifier for this connection on this Tor instance. */ + uint64_t global_identifier; + + /** Bytes read since last call to control_event_conn_bandwidth_used(). + * Only used if we're configured to emit CONN_BW events. */ + uint32_t n_read_conn_bw; + + /** Bytes written since last call to control_event_conn_bandwidth_used(). + * Only used if we're configured to emit CONN_BW events. */ + uint32_t n_written_conn_bw; +}; + +#endif diff --git a/src/or/conscache.c b/src/or/conscache.c index 51dc9d621f..bc3a09509d 100644 --- a/src/or/conscache.c +++ b/src/or/conscache.c @@ -1,12 +1,12 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" +#include "or/or.h" -#include "config.h" -#include "conscache.h" -#include "crypto_util.h" -#include "storagedir.h" +#include "or/config.h" +#include "or/conscache.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/fs/storagedir.h" #define CCE_MAGIC 0x17162253 diff --git a/src/or/conscache.h b/src/or/conscache.h index 08a5c5a37b..20af6402c5 100644 --- a/src/or/conscache.h +++ b/src/or/conscache.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CONSCACHE_H #define TOR_CONSCACHE_H -#include "handles.h" +#include "common/handles.h" typedef struct consensus_cache_entry_t consensus_cache_entry_t; typedef struct consensus_cache_t consensus_cache_t; diff --git a/src/or/consdiff.c b/src/or/consdiff.c index deaf465fe7..88edda716e 100644 --- a/src/or/consdiff.c +++ b/src/or/consdiff.c @@ -1,5 +1,5 @@ /* Copyright (c) 2014, Daniel Martà - * Copyright (c) 2014, The Tor Project, Inc. */ + * Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -38,10 +38,10 @@ #define CONSDIFF_PRIVATE -#include "or.h" -#include "consdiff.h" -#include "memarea.h" -#include "routerparse.h" +#include "or/or.h" +#include "or/consdiff.h" +#include "lib/memarea/memarea.h" +#include "or/routerparse.h" static const char* ns_diff_version = "network-status-diff-version 1"; static const char* hash_token = "hash"; @@ -1412,4 +1412,3 @@ looks_like_a_consensus_diff(const char *document, size_t len) return (len >= strlen(ns_diff_version) && fast_memeq(document, ns_diff_version, strlen(ns_diff_version))); } - diff --git a/src/or/consdiff.h b/src/or/consdiff.h index eb772c0b2b..1cae59a1a5 100644 --- a/src/or/consdiff.h +++ b/src/or/consdiff.h @@ -1,11 +1,11 @@ /* Copyright (c) 2014, Daniel Martà - * Copyright (c) 2014, The Tor Project, Inc. */ + * Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CONSDIFF_H #define TOR_CONSDIFF_H -#include "or.h" +#include "or/or.h" char *consensus_diff_generate(const char *cons1, const char *cons2); @@ -15,6 +15,8 @@ char *consensus_diff_apply(const char *consensus, int looks_like_a_consensus_diff(const char *document, size_t len); #ifdef CONSDIFF_PRIVATE +#include "lib/container/bitarray.h" + struct memarea_t; /** Line type used for constructing consensus diffs. Each of these lines @@ -95,4 +97,3 @@ MOCK_DECL(STATIC int, #endif /* defined(CONSDIFF_PRIVATE) */ #endif /* !defined(TOR_CONSDIFF_H) */ - diff --git a/src/or/consdiffmgr.c b/src/or/consdiffmgr.c index 323f4f9ca0..7732cd1093 100644 --- a/src/or/consdiffmgr.c +++ b/src/or/consdiffmgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,15 +13,18 @@ #define CONSDIFFMGR_PRIVATE -#include "or.h" -#include "config.h" -#include "conscache.h" -#include "consdiff.h" -#include "consdiffmgr.h" -#include "cpuworker.h" -#include "networkstatus.h" -#include "routerparse.h" -#include "workqueue.h" +#include "or/or.h" +#include "or/config.h" +#include "or/conscache.h" +#include "or/consdiff.h" +#include "or/consdiffmgr.h" +#include "or/cpuworker.h" +#include "or/networkstatus.h" +#include "or/routerparse.h" +#include "common/workqueue.h" + +#include "or/networkstatus_st.h" +#include "or/networkstatus_voter_info_st.h" /** * Labels to apply to items in the conscache object. diff --git a/src/or/consdiffmgr.h b/src/or/consdiffmgr.h index df569c8e23..d793a7ef1d 100644 --- a/src/or/consdiffmgr.h +++ b/src/or/consdiffmgr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CONSDIFFMGR_H diff --git a/src/or/control.c b/src/or/control.c index bb68925f8c..7063b4cb3b 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -35,59 +35,77 @@ #define CONTROL_PRIVATE -#include "or.h" -#include "addressmap.h" -#include "bridges.h" -#include "buffers.h" -#include "channel.h" -#include "channeltls.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitstats.h" -#include "circuituse.h" -#include "command.h" -#include "compat_libevent.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "dirserv.h" -#include "dnsserv.h" -#include "entrynodes.h" -#include "geoip.h" -#include "hibernate.h" -#include "hs_cache.h" -#include "hs_common.h" -#include "hs_control.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "proto_control0.h" -#include "proto_http.h" -#include "reasons.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "shared_random_client.h" +#include "or/or.h" +#include "or/addressmap.h" +#include "or/bridges.h" +#include "lib/container/buffers.h" +#include "or/channel.h" +#include "or/channeltls.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuitstats.h" +#include "or/circuituse.h" +#include "or/command.h" +#include "common/compat_libevent.h" +#include "or/config.h" +#include "or/confparse.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/connection_or.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/directory.h" +#include "or/dirserv.h" +#include "or/dnsserv.h" +#include "or/entrynodes.h" +#include "or/geoip.h" +#include "or/hibernate.h" +#include "or/hs_cache.h" +#include "or/hs_common.h" +#include "or/hs_control.h" +#include "or/main.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/proto_control0.h" +#include "or/proto_http.h" +#include "or/reasons.h" +#include "or/rendclient.h" +#include "or/rendcommon.h" +#include "or/rendservice.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/shared_random_client.h" + +#include "or/cached_dir_st.h" +#include "or/control_connection_st.h" +#include "or/cpath_build_state_st.h" +#include "or/entry_connection_st.h" +#include "or/extrainfo_st.h" +#include "or/networkstatus_st.h" +#include "or/node_st.h" +#include "or/or_connection_st.h" +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" +#include "or/microdesc_st.h" +#include "or/rend_authorized_client_st.h" +#include "or/rend_encoded_v2_service_descriptor_st.h" +#include "or/rend_service_descriptor_st.h" +#include "or/routerinfo_st.h" +#include "or/routerlist_st.h" +#include "or/socks_request_st.h" #ifndef _WIN32 #include <pwd.h> #include <sys/resource.h> #endif -#include "crypto_s2k.h" -#include "procmon.h" +#include "lib/crypt_ops/crypto_s2k.h" +#include "common/procmon.h" /** Yield true iff <b>s</b> is the state of a control_connection_t that has * finished authentication and is accepting commands. */ @@ -226,6 +244,15 @@ static void flush_queued_events_cb(mainloop_event_t *event, void *arg); static char * download_status_to_string(const download_status_t *dl); static void control_get_bytes_rw_last_sec(uint64_t *r, uint64_t *w); +/** Convert a connection_t* to an control_connection_t*; assert if the cast is + * invalid. */ +control_connection_t * +TO_CONTROL_CONN(connection_t *c) +{ + tor_assert(c->magic == CONTROL_CONNECTION_MAGIC); + return DOWNCAST(control_connection_t, c); +} + /** Given a control event code for a message event, return the corresponding * log severity. */ static inline int @@ -2207,6 +2234,27 @@ getinfo_helper_dir(control_connection_t *control_conn, return -1; } } + } else if (!strcmp(question, "md/all")) { + const smartlist_t *nodes = nodelist_get_list(); + tor_assert(nodes); + + if (smartlist_len(nodes) == 0) { + *answer = tor_strdup(""); + return 0; + } + + smartlist_t *microdescs = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(nodes, node_t *, n) { + if (n->md && n->md->body) { + char *copy = tor_strndup(n->md->body, n->md->bodylen); + smartlist_add(microdescs, copy); + } + } SMARTLIST_FOREACH_END(n); + + *answer = smartlist_join_strings(microdescs, "", 0, NULL); + SMARTLIST_FOREACH(microdescs, char *, md, tor_free(md)); + smartlist_free(microdescs); } else if (!strcmpstart(question, "md/id/")) { const node_t *node = node_get_by_hex_id(question+strlen("md/id/"), 0); const microdesc_t *md = NULL; @@ -3241,6 +3289,7 @@ static const getinfo_item_t getinfo_items[] = { ITEM("desc/download-enabled", dir, "Do we try to download router descriptors?"), ITEM("desc/all-recent-extrainfo-hack", dir, NULL), /* Hack. */ + ITEM("md/all", dir, "All known microdescriptors."), PREFIX("md/id/", dir, "Microdescriptors by ID"), PREFIX("md/name/", dir, "Microdescriptors by name"), ITEM("md/download-enabled", dir, @@ -3400,6 +3449,7 @@ handle_control_getinfo(control_connection_t *conn, uint32_t len, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(questions, const char *, q) { const char *errmsg = NULL; + if (handle_getinfo_helper(conn, q, &ans, &errmsg) < 0) { if (!errmsg) errmsg = "Internal error"; @@ -4624,7 +4674,7 @@ handle_control_add_onion(control_connection_t *conn, static const char *max_s_prefix = "MaxStreams="; static const char *auth_prefix = "ClientAuth="; - const char *arg = smartlist_get(args, i); + const char *arg = smartlist_get(args, (int)i); if (!strcasecmpstart(arg, port_prefix)) { /* "Port=VIRTPORT[,TARGET]". */ const char *port_str = arg + strlen(port_prefix); diff --git a/src/or/control.h b/src/or/control.h index 92cbf866dd..200a88bf62 100644 --- a/src/or/control.h +++ b/src/or/control.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,6 +12,8 @@ #ifndef TOR_CONTROL_H #define TOR_CONTROL_H +control_connection_t *TO_CONTROL_CONN(connection_t *); + void control_initialize_event_queue(void); void control_update_global_event_mask(void); diff --git a/src/or/control_connection_st.h b/src/or/control_connection_st.h new file mode 100644 index 0000000000..4f8ab25d99 --- /dev/null +++ b/src/or/control_connection_st.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CONTROL_CONNECTION_ST_H +#define CONTROL_CONNECTION_ST_H + +#include "or/or.h" +#include "or/connection_st.h" + +/** Subtype of connection_t for an connection to a controller. */ +struct control_connection_t { + connection_t base_; + + uint64_t event_mask; /**< Bitfield: which events does this controller + * care about? + * EVENT_MAX_ is >31, so we need a 64 bit mask */ + + /** True if we have sent a protocolinfo reply on this connection. */ + unsigned int have_sent_protocolinfo:1; + /** True if we have received a takeownership command on this + * connection. */ + unsigned int is_owning_control_connection:1; + + /** List of ephemeral onion services belonging to this connection. */ + smartlist_t *ephemeral_onion_services; + + /** If we have sent an AUTHCHALLENGE reply on this connection and + * have not received a successful AUTHENTICATE command, points to + * the value which the client must send to authenticate itself; + * otherwise, NULL. */ + char *safecookie_client_hash; + + /** Amount of space allocated in incoming_cmd. */ + uint32_t incoming_cmd_len; + /** Number of bytes currently stored in incoming_cmd. */ + uint32_t incoming_cmd_cur_len; + /** A control command that we're reading from the inbuf, but which has not + * yet arrived completely. */ + char *incoming_cmd; +}; + +#endif + diff --git a/src/or/cpath_build_state_st.h b/src/or/cpath_build_state_st.h new file mode 100644 index 0000000000..1db7251132 --- /dev/null +++ b/src/or/cpath_build_state_st.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CIRCUIT_BUILD_STATE_ST_ST_H +#define CIRCUIT_BUILD_STATE_ST_ST_H + +/** Information used to build a circuit. */ +struct cpath_build_state_t { + /** Intended length of the final circuit. */ + int desired_path_len; + /** How to extend to the planned exit node. */ + extend_info_t *chosen_exit; + /** Whether every node in the circ must have adequate uptime. */ + unsigned int need_uptime : 1; + /** Whether every node in the circ must have adequate capacity. */ + unsigned int need_capacity : 1; + /** Whether the last hop was picked with exiting in mind. */ + unsigned int is_internal : 1; + /** Did we pick this as a one-hop tunnel (not safe for other streams)? + * These are for encrypted dir conns that exit to this router, not + * for arbitrary exits from the circuit. */ + unsigned int onehop_tunnel : 1; + /** The crypt_path_t to append after rendezvous: used for rendezvous. */ + crypt_path_t *pending_final_cpath; + /** A ref-counted reference to the crypt_path_t to append after + * rendezvous; used on the service side. */ + crypt_path_reference_t *service_pending_final_cpath_ref; + /** How many times has building a circuit for this task failed? */ + int failure_count; + /** At what time should we give up on this task? */ + time_t expiry_time; +}; + +#endif + diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c index 15ef6869cf..6750790205 100644 --- a/src/or/cpuworker.c +++ b/src/or/cpuworker.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,20 +17,23 @@ * <li>and for calculating diffs and compressing them in consdiffmgr.c. * </ul> **/ -#include "or.h" -#include "channel.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "connection_or.h" -#include "config.h" -#include "cpuworker.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "main.h" -#include "onion.h" -#include "rephist.h" -#include "router.h" -#include "workqueue.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/connection_or.h" +#include "or/config.h" +#include "or/cpuworker.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/main.h" +#include "or/onion.h" +#include "or/rephist.h" +#include "or/router.h" +#include "common/workqueue.h" + +#include "or/or_circuit_st.h" +#include "lib/intmath/weakrng.h" static void queue_pending_tasks(void); @@ -594,4 +597,3 @@ cpuworker_cancel_circ_handshake(or_circuit_t *circ) circ->workqueue_entry = NULL; } } - diff --git a/src/or/cpuworker.h b/src/or/cpuworker.h index d39851325f..50812b2dab 100644 --- a/src/or/cpuworker.h +++ b/src/or/cpuworker.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/crypt_path_reference_st.h b/src/or/crypt_path_reference_st.h new file mode 100644 index 0000000000..bb0e519233 --- /dev/null +++ b/src/or/crypt_path_reference_st.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CRYPT_PATH_REFERENCE_ST_H +#define CRYPT_PATH_REFERENCE_ST_H + +/** A reference-counted pointer to a crypt_path_t, used only to share + * the final rendezvous cpath to be used on a service-side rendezvous + * circuit among multiple circuits built in parallel to the same + * destination rendezvous point. */ +struct crypt_path_reference_t { + /** The reference count. */ + unsigned int refcount; + /** The pointer. Set to NULL when the crypt_path_t is put into use + * on an opened rendezvous circuit. */ + crypt_path_t *cpath; +}; + +#endif + diff --git a/src/or/crypt_path_st.h b/src/or/crypt_path_st.h new file mode 100644 index 0000000000..88b4085acb --- /dev/null +++ b/src/or/crypt_path_st.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CRYPT_PATH_ST_H +#define CRYPT_PATH_ST_H + +#include "or/relay_crypto_st.h" + +/** Holds accounting information for a single step in the layered encryption + * performed by a circuit. Used only at the client edge of a circuit. */ +struct crypt_path_t { + uint32_t magic; + + /** Cryptographic state used for encrypting and authenticating relay + * cells to and from this hop. */ + relay_crypto_t crypto; + + /** Current state of the handshake as performed with the OR at this + * step. */ + onion_handshake_state_t handshake_state; + /** Diffie-hellman handshake state for performing an introduction + * operations */ + crypto_dh_t *rend_dh_handshake_state; + + /** Negotiated key material shared with the OR at this step. */ + char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */ + + /** Information to extend to the OR at this step. */ + extend_info_t *extend_info; + + /** Is the circuit built to this step? Must be one of: + * - CPATH_STATE_CLOSED (The circuit has not been extended to this step) + * - CPATH_STATE_AWAITING_KEYS (We have sent an EXTEND/CREATE to this step + * and not received an EXTENDED/CREATED) + * - CPATH_STATE_OPEN (The circuit has been extended to this step) */ + uint8_t state; +#define CPATH_STATE_CLOSED 0 +#define CPATH_STATE_AWAITING_KEYS 1 +#define CPATH_STATE_OPEN 2 + struct crypt_path_t *next; /**< Link to next crypt_path_t in the circuit. + * (The list is circular, so the last node + * links to the first.) */ + struct crypt_path_t *prev; /**< Link to previous crypt_path_t in the + * circuit. */ + + int package_window; /**< How many cells are we allowed to originate ending + * at this step? */ + int deliver_window; /**< How many cells are we willing to deliver originating + * at this step? */ +}; + +#endif + diff --git a/src/or/desc_store_st.h b/src/or/desc_store_st.h new file mode 100644 index 0000000000..c070e354c5 --- /dev/null +++ b/src/or/desc_store_st.h @@ -0,0 +1,34 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DESC_STORE_ST_H +#define DESC_STORE_ST_H + +/** A 'store' is a set of descriptors saved on disk, with accompanying + * journal, mmaped as needed, rebuilt as needed. */ +struct desc_store_t { + /** Filename (within DataDir) for the store. We append .tmp to this + * filename for a temporary file when rebuilding the store, and .new to this + * filename for the journal. */ + const char *fname_base; + /** Human-readable description of what this store contains. */ + const char *description; + + tor_mmap_t *mmap; /**< A mmap for the main file in the store. */ + + store_type_t type; /**< What's stored in this store? */ + + /** The size of the router log, in bytes. */ + size_t journal_len; + /** The size of the router store, in bytes. */ + size_t store_len; + /** Total bytes dropped since last rebuild: this is space currently + * used in the cache and the journal that could be freed by a rebuild. */ + size_t bytes_dropped; +}; + +#endif + diff --git a/src/or/destroy_cell_queue_st.h b/src/or/destroy_cell_queue_st.h new file mode 100644 index 0000000000..2839b0bd11 --- /dev/null +++ b/src/or/destroy_cell_queue_st.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DESTROY_CELL_QUEUE_ST_H +#define DESTROY_CELL_QUEUE_ST_H + +/** A single queued destroy cell. */ +struct destroy_cell_t { + TOR_SIMPLEQ_ENTRY(destroy_cell_t) next; + circid_t circid; + uint32_t inserted_timestamp; /**< Time (in timestamp units) when this cell + * was inserted */ + uint8_t reason; +}; + +/** A queue of destroy cells on a channel. */ +struct destroy_cell_queue_t { + /** Linked list of packed_cell_t */ + TOR_SIMPLEQ_HEAD(dcell_simpleq, destroy_cell_t) head; + int n; /**< The number of cells in the queue. */ +}; + +#endif + diff --git a/src/or/dir_connection_st.h b/src/or/dir_connection_st.h new file mode 100644 index 0000000000..f68266ca2e --- /dev/null +++ b/src/or/dir_connection_st.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DIR_CONNECTION_ST_H +#define DIR_CONNECTION_ST_H + +#include "or/connection_st.h" + +/** Subtype of connection_t for an "directory connection" -- that is, an HTTP + * connection to retrieve or serve directory material. */ +struct dir_connection_t { + connection_t base_; + + /** Which 'resource' did we ask the directory for? This is typically the part + * of the URL string that defines, relative to the directory conn purpose, + * what thing we want. For example, in router descriptor downloads by + * descriptor digest, it contains "d/", then one or more +-separated + * fingerprints. + **/ + char *requested_resource; + unsigned int dirconn_direct:1; /**< Is this dirconn direct, or via Tor? */ + + /** If we're fetching descriptors, what router purpose shall we assign + * to them? */ + uint8_t router_purpose; + + /** List of spooled_resource_t for objects that we're spooling. We use + * it from back to front. */ + smartlist_t *spool; + /** The compression object doing on-the-fly compression for spooled data. */ + tor_compress_state_t *compress_state; + + /** What rendezvous service are we querying for? */ + rend_data_t *rend_data; + + /* Hidden service connection identifier for dir connections: Used by HS + client-side code to fetch HS descriptors, and by the service-side code to + upload descriptors. */ + struct hs_ident_dir_conn_t *hs_ident; + + /** If this is a one-hop connection, tracks the state of the directory guard + * for this connection (if any). */ + struct circuit_guard_state_t *guard_state; + + char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for + * the directory server's signing key. */ + + /** Unique ID for directory requests; this used to be in connection_t, but + * that's going away and being used on channels instead. The dirserver still + * needs this for the incoming side, so it's moved here. */ + uint64_t dirreq_id; + +#ifdef MEASUREMENTS_21206 + /** Number of RELAY_DATA cells received. */ + uint32_t data_cells_received; + + /** Number of RELAY_DATA cells sent. */ + uint32_t data_cells_sent; +#endif /* defined(MEASUREMENTS_21206) */ +}; + +#endif + diff --git a/src/or/dir_server_st.h b/src/or/dir_server_st.h new file mode 100644 index 0000000000..fe1f5c3d5f --- /dev/null +++ b/src/or/dir_server_st.h @@ -0,0 +1,54 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DIR_SERVER_ST_H +#define DIR_SERVER_ST_H + +#include "lib/cc/torint.h" +#include "or/or.h" +#include "or/routerstatus_st.h" + +/** Represents information about a single trusted or fallback directory + * server. */ +struct dir_server_t { + char *description; + char *nickname; + char *address; /**< Hostname. */ + /* XX/teor - why do we duplicate the address and port fields here and in + * fake_status? Surely we could just use fake_status (#17867). */ + tor_addr_t ipv6_addr; /**< IPv6 address if present; AF_UNSPEC if not */ + uint32_t addr; /**< IPv4 address. */ + uint16_t dir_port; /**< Directory port. */ + uint16_t or_port; /**< OR port: Used for tunneling connections. */ + uint16_t ipv6_orport; /**< OR port corresponding to ipv6_addr. */ + double weight; /** Weight used when selecting this node at random */ + char digest[DIGEST_LEN]; /**< Digest of identity key. */ + char v3_identity_digest[DIGEST_LEN]; /**< Digest of v3 (authority only, + * high-security) identity key. */ + + unsigned int is_running:1; /**< True iff we think this server is running. */ + unsigned int is_authority:1; /**< True iff this is a directory authority + * of some kind. */ + + /** True iff this server has accepted the most recent server descriptor + * we tried to upload to it. */ + unsigned int has_accepted_serverdesc:1; + + /** What kind of authority is this? (Bitfield.) */ + dirinfo_type_t type; + + time_t addr_current_at; /**< When was the document that we derived the + * address information from published? */ + + routerstatus_t fake_status; /**< Used when we need to pass this trusted + * dir_server_t to + * directory_request_set_routerstatus. + * as a routerstatus_t. Not updated by the + * router-status management code! + **/ +}; + +#endif diff --git a/src/or/dirauth/dircollate.c b/src/or/dirauth/dircollate.c index dec6f75154..246977dcc8 100644 --- a/src/or/dirauth/dircollate.c +++ b/src/or/dirauth/dircollate.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -22,8 +22,11 @@ */ #define DIRCOLLATE_PRIVATE -#include "dircollate.h" -#include "dirvote.h" +#include "or/dirauth/dircollate.h" +#include "or/dirauth/dirvote.h" + +#include "or/networkstatus_st.h" +#include "or/vote_routerstatus_st.h" static void dircollator_collate_by_ed25519(dircollator_t *dc); diff --git a/src/or/dirauth/dircollate.h b/src/or/dirauth/dircollate.h index 0584b2fe06..aae7829786 100644 --- a/src/or/dirauth/dircollate.h +++ b/src/or/dirauth/dircollate.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,8 @@ #ifndef TOR_DIRCOLLATE_H #define TOR_DIRCOLLATE_H -#include "testsupport.h" -#include "or.h" +#include "lib/testsupport/testsupport.h" +#include "or/or.h" typedef struct dircollator_s dircollator_t; diff --git a/src/or/dirauth/dirvote.c b/src/or/dirauth/dirvote.c index b097b10cf9..85a0d3e707 100644 --- a/src/or/dirauth/dirvote.c +++ b/src/or/dirauth/dirvote.c @@ -1,32 +1,49 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DIRVOTE_PRIVATE -#include "or.h" -#include "config.h" -#include "dircollate.h" -#include "directory.h" -#include "dirserv.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "parsecommon.h" -#include "policies.h" -#include "protover.h" -#include "rephist.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "routerparse.h" -#include "entrynodes.h" /* needed for guardfraction methods */ -#include "torcert.h" -#include "voting_schedule.h" - -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" -#include "dirauth/shared_random_state.h" +#include "or/or.h" +#include "or/config.h" +#include "or/dirauth/dircollate.h" +#include "or/directory.h" +#include "or/dirserv.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/parsecommon.h" +#include "or/policies.h" +#include "or/protover.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerkeys.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/entrynodes.h" /* needed for guardfraction methods */ +#include "or/torcert.h" +#include "or/voting_schedule.h" + +#include "or/dirauth/dirvote.h" +#include "or/dirauth/mode.h" +#include "or/dirauth/shared_random_state.h" + +#include "or/authority_cert_st.h" +#include "or/cached_dir_st.h" +#include "or/dir_server_st.h" +#include "or/document_signature_st.h" +#include "or/microdesc_st.h" +#include "or/networkstatus_st.h" +#include "or/networkstatus_voter_info_st.h" +#include "or/node_st.h" +#include "or/ns_detached_signatures_st.h" +#include "or/routerinfo_st.h" +#include "or/routerlist_st.h" +#include "or/vote_microdesc_hash_st.h" +#include "or/vote_routerstatus_st.h" +#include "or/vote_timing_st.h" + +#include "lib/container/order.h" /** * \file dirvote.c @@ -4220,7 +4237,7 @@ routers_make_ed_keys_unique(smartlist_t *routers) if (ri2_pub < ri_pub || (ri2_pub == ri_pub && fast_memcmp(ri->cache_info.signed_descriptor_digest, - ri2->cache_info.signed_descriptor_digest,DIGEST_LEN)<0)) { + ri2->cache_info.signed_descriptor_digest,DIGEST_LEN)<0)) { digest256map_set(by_ed_key, pk, ri); ri2->omit_from_vote = 1; } else { @@ -4393,10 +4410,10 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, vrs->protocols = tor_strdup(ri->protocol_list); } else { vrs->protocols = tor_strdup( - protover_compute_for_old_tor(vrs->version)); + protover_compute_for_old_tor(vrs->version)); } vrs->microdesc = dirvote_format_all_microdesc_vote_lines(ri, now, - microdescriptors); + microdescriptors); smartlist_add(routerstatuses, vrs); } @@ -4489,9 +4506,9 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, /* We should not recommend anything we don't have. */ tor_assert_nonfatal(protover_all_supported( - v3_out->recommended_relay_protocols, NULL)); + v3_out->recommended_relay_protocols, NULL)); tor_assert_nonfatal(protover_all_supported( - v3_out->recommended_client_protocols, NULL)); + v3_out->recommended_client_protocols, NULL)); v3_out->package_lines = smartlist_new(); { @@ -4547,4 +4564,3 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, return v3_out; } - diff --git a/src/or/dirauth/dirvote.h b/src/or/dirauth/dirvote.h index b69bbbf5d9..7ce8e4a699 100644 --- a/src/or/dirauth/dirvote.h +++ b/src/or/dirauth/dirvote.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -164,7 +164,8 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out) } static inline int -dirvote_add_signatures(const char *detached_signatures_body, const char *source, +dirvote_add_signatures(const char *detached_signatures_body, + const char *source, const char **msg_out) { (void) detached_signatures_body; @@ -244,4 +245,3 @@ STATIC microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri, #endif /* defined(DIRVOTE_PRIVATE) */ #endif /* !defined(TOR_DIRVOTE_H) */ - diff --git a/src/or/dirauth/mode.h b/src/or/dirauth/mode.h index 8a0d3142f1..17c35aff64 100644 --- a/src/or/dirauth/mode.h +++ b/src/or/dirauth/mode.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,7 +11,7 @@ #ifdef HAVE_MODULE_DIRAUTH -#include "router.h" +#include "or/router.h" /* Return true iff we believe ourselves to be a v3 authoritative directory * server. */ diff --git a/src/or/dirauth/shared_random.c b/src/or/dirauth/shared_random.c index 6dd1f330e0..8b53c1e743 100644 --- a/src/or/dirauth/shared_random.c +++ b/src/or/dirauth/shared_random.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -87,23 +87,26 @@ #define SHARED_RANDOM_PRIVATE -#include "or.h" -#include "shared_random.h" -#include "config.h" -#include "confparse.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "networkstatus.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "shared_random_client.h" -#include "shared_random_state.h" -#include "util.h" -#include "voting_schedule.h" - -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" +#include "or/or.h" +#include "or/dirauth/shared_random.h" +#include "or/config.h" +#include "or/confparse.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/networkstatus.h" +#include "or/router.h" +#include "or/routerkeys.h" +#include "or/routerlist.h" +#include "or/shared_random_client.h" +#include "or/dirauth/shared_random_state.h" +#include "common/util.h" +#include "or/voting_schedule.h" + +#include "or/dirauth/dirvote.h" +#include "or/dirauth/mode.h" + +#include "or/authority_cert_st.h" +#include "or/networkstatus_st.h" /* String prefix of shared random values in votes/consensuses. */ static const char previous_srv_str[] = "shared-rand-previous-value"; diff --git a/src/or/dirauth/shared_random.h b/src/or/dirauth/shared_random.h index 1778ce8f09..93bab99f71 100644 --- a/src/or/dirauth/shared_random.h +++ b/src/or/dirauth/shared_random.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_SHARED_RANDOM_H @@ -10,7 +10,7 @@ * with "sr_" which stands for shared random. */ -#include "or.h" +#include "or/or.h" /* Protocol version */ #define SR_PROTO_VERSION 1 diff --git a/src/or/dirauth/shared_random_state.c b/src/or/dirauth/shared_random_state.c index fc0e4e5630..c30a024425 100644 --- a/src/or/dirauth/shared_random_state.c +++ b/src/or/dirauth/shared_random_state.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,17 +10,17 @@ #define SHARED_RANDOM_STATE_PRIVATE -#include "or.h" -#include "config.h" -#include "confparse.h" -#include "crypto_util.h" -#include "dirauth/dirvote.h" -#include "networkstatus.h" -#include "router.h" -#include "shared_random.h" -#include "shared_random_client.h" -#include "shared_random_state.h" -#include "voting_schedule.h" +#include "or/or.h" +#include "or/config.h" +#include "or/confparse.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/dirauth/dirvote.h" +#include "or/networkstatus.h" +#include "or/router.h" +#include "or/dirauth/shared_random.h" +#include "or/shared_random_client.h" +#include "or/dirauth/shared_random_state.h" +#include "or/voting_schedule.h" /* Default filename of the shared random state on disk. */ static const char default_fname[] = "sr-state"; diff --git a/src/or/dirauth/shared_random_state.h b/src/or/dirauth/shared_random_state.h index 60a326f86c..a8ac0134cc 100644 --- a/src/or/dirauth/shared_random_state.h +++ b/src/or/dirauth/shared_random_state.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_SHARED_RANDOM_STATE_H #define TOR_SHARED_RANDOM_STATE_H -#include "shared_random.h" +#include "or/dirauth/shared_random.h" /* Action that can be performed on the state for any objects. */ typedef enum { diff --git a/src/or/directory.c b/src/or/directory.c index e763de268f..6b8885e121 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -1,47 +1,47 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DIRECTORY_PRIVATE -#include "or.h" -#include "backtrace.h" -#include "bridges.h" -#include "buffers.h" -#include "circuitbuild.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "conscache.h" -#include "consdiff.h" -#include "consdiffmgr.h" -#include "control.h" -#include "compat.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "dirserv.h" -#include "entrynodes.h" -#include "geoip.h" -#include "hs_cache.h" -#include "hs_common.h" -#include "hs_control.h" -#include "hs_client.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "relay.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" +#include "or/or.h" +#include "lib/err/backtrace.h" +#include "or/bridges.h" +#include "lib/container/buffers.h" +#include "or/circuitbuild.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/conscache.h" +#include "or/consdiff.h" +#include "or/consdiffmgr.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/directory.h" +#include "or/dirserv.h" +#include "or/entrynodes.h" +#include "or/fp_pair.h" +#include "or/geoip.h" +#include "or/hs_cache.h" +#include "or/hs_common.h" +#include "or/hs_control.h" +#include "or/hs_client.h" +#include "or/main.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/relay.h" +#include "or/rendclient.h" +#include "or/rendcommon.h" +#include "or/rendservice.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/routerset.h" #if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) #if !defined(OpenBSD) @@ -49,9 +49,19 @@ #endif #endif -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" -#include "dirauth/shared_random.h" +#include "or/dirauth/dirvote.h" +#include "or/dirauth/mode.h" +#include "or/dirauth/shared_random.h" + +#include "or/authority_cert_st.h" +#include "or/cached_dir_st.h" +#include "or/dir_connection_st.h" +#include "or/dir_server_st.h" +#include "or/entry_connection_st.h" +#include "or/networkstatus_st.h" +#include "or/node_st.h" +#include "or/rend_service_descriptor_st.h" +#include "or/routerinfo_st.h" /** * \file directory.c @@ -151,6 +161,15 @@ static void connection_dir_close_consensus_fetches( /********* END VARIABLES ************/ +/** Convert a connection_t* to a dir_connection_t*; assert if the cast is + * invalid. */ +dir_connection_t * +TO_DIR_CONN(connection_t *c) +{ + tor_assert(c->magic == DIR_CONNECTION_MAGIC); + return DOWNCAST(dir_connection_t, c); +} + /** Return false if the directory purpose <b>dir_purpose</b> * does not require an anonymous (three-hop) connection. * @@ -5614,6 +5633,27 @@ download_status_reset(download_status_t *dls) /* Don't reset dls->want_authority or dls->increment_on */ } +/** Return true iff, as of <b>now</b>, the resource tracked by <b>dls</b> is + * ready to get its download reattempted. */ +int +download_status_is_ready(download_status_t *dls, time_t now) +{ + /* dls wasn't reset before it was used */ + if (dls->next_attempt_at == 0) { + download_status_reset(dls); + } + + return download_status_get_next_attempt_at(dls) <= now; +} + +/** Mark <b>dl</b> as never downloadable. */ +void +download_status_mark_impossible(download_status_t *dl) +{ + dl->n_download_failures = IMPOSSIBLE_TO_DOWNLOAD; + dl->n_download_attempts = IMPOSSIBLE_TO_DOWNLOAD; +} + /** Return the number of failures on <b>dls</b> since the last success (if * any). */ int diff --git a/src/or/directory.h b/src/or/directory.h index 5f5ff7eca6..5cf8892ace 100644 --- a/src/or/directory.h +++ b/src/or/directory.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,9 @@ #ifndef TOR_DIRECTORY_H #define TOR_DIRECTORY_H -#include "hs_ident.h" +#include "or/hs_ident.h" +dir_connection_t *TO_DIR_CONN(connection_t *c); int directories_have_accepted_server_descriptor(void); void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, dirinfo_type_t type, const char *payload, @@ -60,6 +61,7 @@ void directory_request_set_dir_addr_port(directory_request_t *req, const tor_addr_port_t *p); void directory_request_set_directory_id_digest(directory_request_t *req, const char *digest); +struct circuit_guard_state_t; void directory_request_set_guard_state(directory_request_t *req, struct circuit_guard_state_t *state); void directory_request_set_router_purpose(directory_request_t *req, @@ -132,30 +134,9 @@ time_t download_status_increment_attempt(download_status_t *dls, time(NULL)) void download_status_reset(download_status_t *dls); -static int download_status_is_ready(download_status_t *dls, time_t now); +int download_status_is_ready(download_status_t *dls, time_t now); time_t download_status_get_next_attempt_at(const download_status_t *dls); - -/** Return true iff, as of <b>now</b>, the resource tracked by <b>dls</b> is - * ready to get its download reattempted. */ -static inline int -download_status_is_ready(download_status_t *dls, time_t now) -{ - /* dls wasn't reset before it was used */ - if (dls->next_attempt_at == 0) { - download_status_reset(dls); - } - - return download_status_get_next_attempt_at(dls) <= now; -} - -static void download_status_mark_impossible(download_status_t *dl); -/** Mark <b>dl</b> as never downloadable. */ -static inline void -download_status_mark_impossible(download_status_t *dl) -{ - dl->n_download_failures = IMPOSSIBLE_TO_DOWNLOAD; - dl->n_download_attempts = IMPOSSIBLE_TO_DOWNLOAD; -} +void download_status_mark_impossible(download_status_t *dl); int download_status_get_n_failures(const download_status_t *dls); int download_status_get_n_attempts(const download_status_t *dls); diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 2362089d32..62d4e73223 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -1,45 +1,57 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DIRSERV_PRIVATE -#include "or.h" -#include "buffers.h" -#include "config.h" -#include "confparse.h" -#include "channel.h" -#include "channeltls.h" -#include "command.h" -#include "connection.h" -#include "connection_or.h" -#include "conscache.h" -#include "consdiffmgr.h" -#include "control.h" -#include "directory.h" -#include "dirserv.h" -#include "hibernate.h" -#include "keypin.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "protover.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "torcert.h" -#include "voting_schedule.h" - -#include "dirauth/dirvote.h" +#include "or/or.h" +#include "lib/container/buffers.h" +#include "or/config.h" +#include "or/confparse.h" +#include "or/channel.h" +#include "or/channeltls.h" +#include "or/command.h" +#include "or/connection.h" +#include "or/connection_or.h" +#include "or/conscache.h" +#include "or/consdiffmgr.h" +#include "or/control.h" +#include "or/directory.h" +#include "or/dirserv.h" +#include "or/hibernate.h" +#include "or/keypin.h" +#include "or/main.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/protover.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/routerset.h" +#include "or/torcert.h" +#include "or/voting_schedule.h" + +#include "or/dirauth/dirvote.h" + +#include "or/cached_dir_st.h" +#include "or/dir_connection_st.h" +#include "or/extrainfo_st.h" +#include "or/microdesc_st.h" +#include "or/node_st.h" +#include "or/routerinfo_st.h" +#include "or/routerlist_st.h" +#include "or/tor_version_st.h" +#include "or/vote_routerstatus_st.h" + +#include "lib/container/order.h" /** * \file dirserv.c * \brief Directory server core implementation. Manages directory - * contents and generates directories. + * contents and generates directory documents. * * This module implements most of directory cache functionality, and some of * the directory authority functionality. The directory.c module delegates @@ -3581,4 +3593,3 @@ dirserv_free_all(void) dirserv_clear_measured_bw_cache(); } - diff --git a/src/or/dirserv.h b/src/or/dirserv.h index 9026f332bc..757eba7ba2 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #ifndef TOR_DIRSERV_H #define TOR_DIRSERV_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" /** What fraction (1 over this number) of the relay ID space do we * (as a directory authority) launch connections to at each reachability @@ -87,6 +87,14 @@ typedef struct spooled_resource_t { off_t cached_dir_offset; } spooled_resource_t; +#ifdef DIRSERV_PRIVATE +typedef struct measured_bw_line_t { + char node_id[DIGEST_LEN]; + char node_hex[MAX_HEX_NICKNAME_LEN+1]; + long int bw_kb; +} measured_bw_line_t; +#endif /* defined(DIRSERV_PRIVATE) */ + int connection_dirserv_flushed_some(dir_connection_t *conn); int dirserv_add_own_fingerprint(crypto_pk_t *pk); diff --git a/src/or/dns.c b/src/or/dns.c index ba734ed900..ddb50d1964 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -49,21 +49,25 @@ #define DNS_PRIVATE -#include "or.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "control.h" -#include "crypto_rand.h" -#include "dns.h" -#include "main.h" -#include "policies.h" -#include "relay.h" -#include "router.h" +#include "or/or.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/dns.h" +#include "or/main.h" +#include "or/policies.h" +#include "or/relay.h" +#include "or/router.h" #include "ht.h" -#include "sandbox.h" +#include "lib/sandbox/sandbox.h" + +#include "or/edge_connection_st.h" +#include "or/or_circuit_st.h" + #include <event2/event.h> #include <event2/dns.h> diff --git a/src/or/dns.h b/src/or/dns.h index 28d9f947b4..12853205ff 100644 --- a/src/or/dns.h +++ b/src/or/dns.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -41,7 +41,7 @@ void dns_reset_correctness_checks(void); void dump_dns_mem_usage(int severity); #ifdef DNS_PRIVATE -#include "dns_structs.h" +#include "or/dns_structs.h" MOCK_DECL(STATIC int,dns_resolve_impl,(edge_connection_t *exitconn, int is_resolve,or_circuit_t *oncirc, char **hostname_out, diff --git a/src/or/dns_structs.h b/src/or/dns_structs.h index e22f23ac15..28c48ca0bc 100644 --- a/src/or/dns_structs.h +++ b/src/or/dns_structs.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c index 7e344deeab..ce1746fe27 100644 --- a/src/or/dnsserv.c +++ b/src/or/dnsserv.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,14 +21,20 @@ * DNS client. **/ -#include "or.h" -#include "dnsserv.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "control.h" -#include "main.h" -#include "policies.h" +#include "or/or.h" +#include "or/dnsserv.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/control.h" +#include "or/main.h" +#include "or/policies.h" + +#include "or/control_connection_st.h" +#include "or/entry_connection_st.h" +#include "or/listener_connection_st.h" +#include "or/socks_request_st.h" + #include <event2/dns.h> #include <event2/dns_compat.h> /* XXXX this implies we want an improved evdns */ diff --git a/src/or/dnsserv.h b/src/or/dnsserv.h index 2af366eee5..afdde3a342 100644 --- a/src/or/dnsserv.h +++ b/src/or/dnsserv.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/document_signature_st.h b/src/or/document_signature_st.h new file mode 100644 index 0000000000..0291e099bf --- /dev/null +++ b/src/or/document_signature_st.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DOCUMENT_SIGNATURE_ST_H +#define DOCUMENT_SIGNATURE_ST_H + +/** A signature of some document by an authority. */ +struct document_signature_t { + /** Declared SHA-1 digest of this voter's identity key */ + char identity_digest[DIGEST_LEN]; + /** Declared SHA-1 digest of signing key used by this voter. */ + char signing_key_digest[DIGEST_LEN]; + /** Algorithm used to compute the digest of the document. */ + digest_algorithm_t alg; + /** Signature of the signed thing. */ + char *signature; + /** Length of <b>signature</b> */ + int signature_len; + unsigned int bad_signature : 1; /**< Set to true if we've tried to verify + * the sig, and we know it's bad. */ + unsigned int good_signature : 1; /**< Set to true if we've verified the sig + * as good. */ +}; + +#endif + diff --git a/src/or/dos.c b/src/or/dos.c index ee731accea..02bdbcf35d 100644 --- a/src/or/dos.c +++ b/src/or/dos.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* @@ -8,18 +8,21 @@ #define DOS_PRIVATE -#include "or.h" -#include "channel.h" -#include "config.h" -#include "crypto_rand.h" -#include "geoip.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "relay.h" -#include "router.h" - -#include "dos.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/config.h" +#include "or/connection_or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/geoip.h" +#include "or/main.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/relay.h" +#include "or/router.h" + +#include "or/dos.h" + +#include "or/or_connection_st.h" /* * Circuit creation denial of service mitigation. diff --git a/src/or/dos.h b/src/or/dos.h index 5d35a2b12e..760ef11057 100644 --- a/src/or/dos.h +++ b/src/or/dos.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* diff --git a/src/or/download_status_st.h b/src/or/download_status_st.h new file mode 100644 index 0000000000..3f18f754a1 --- /dev/null +++ b/src/or/download_status_st.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DOWNLOAD_STATUS_ST_H +#define DOWNLOAD_STATUS_ST_H + +/** Information about our plans for retrying downloads for a downloadable + * directory object. + * Each type of downloadable directory object has a corresponding retry + * <b>schedule</b>, which can be different depending on whether the object is + * being downloaded from an authority or a mirror (<b>want_authority</b>). + * <b>next_attempt_at</b> contains the next time we will attempt to download + * the object. + * For schedules that <b>increment_on</b> failure, <b>n_download_failures</b> + * is used to determine the position in the schedule. (Each schedule is a + * smartlist of integer delays, parsed from a CSV option.) Every time a + * connection attempt fails, <b>n_download_failures</b> is incremented, + * the new delay value is looked up from the schedule, and + * <b>next_attempt_at</b> is set delay seconds from the time the previous + * connection failed. Therefore, at most one failure-based connection can be + * in progress for each download_status_t. + * For schedules that <b>increment_on</b> attempt, <b>n_download_attempts</b> + * is used to determine the position in the schedule. Every time a + * connection attempt is made, <b>n_download_attempts</b> is incremented, + * the new delay value is looked up from the schedule, and + * <b>next_attempt_at</b> is set delay seconds from the time the previous + * connection was attempted. Therefore, multiple concurrent attempted-based + * connections can be in progress for each download_status_t. + * After an object is successfully downloaded, any other concurrent connections + * are terminated. A new schedule which starts at position 0 is used for + * subsequent downloads of the same object. + */ +struct download_status_t { + time_t next_attempt_at; /**< When should we try downloading this object + * again? */ + uint8_t n_download_failures; /**< Number of failed downloads of the most + * recent object, since the last success. */ + uint8_t n_download_attempts; /**< Number of (potentially concurrent) attempts + * to download the most recent object, since + * the last success. */ + download_schedule_bitfield_t schedule : 8; /**< What kind of object is being + * downloaded? This determines the + * schedule used for the download. + */ + download_want_authority_bitfield_t want_authority : 1; /**< Is the download + * happening from an authority + * or a mirror? This determines + * the schedule used for the + * download. */ + download_schedule_increment_bitfield_t increment_on : 1; /**< does this + * schedule increment on each attempt, + * or after each failure? */ + uint8_t last_backoff_position; /**< number of attempts/failures, depending + * on increment_on, when we last recalculated + * the delay. Only updated if backoff + * == 1. */ + int last_delay_used; /**< last delay used for random exponential backoff; + * only updated if backoff == 1 */ +}; + +#endif + diff --git a/src/or/edge_connection_st.h b/src/or/edge_connection_st.h new file mode 100644 index 0000000000..d58e1c2b8c --- /dev/null +++ b/src/or/edge_connection_st.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef EDGE_CONNECTION_ST_H +#define EDGE_CONNECTION_ST_H + +#include "or/or.h" + +#include "or/connection_st.h" + +/** Subtype of connection_t for an "edge connection" -- that is, an entry (ap) + * connection, or an exit. */ +struct edge_connection_t { + connection_t base_; + + struct edge_connection_t *next_stream; /**< Points to the next stream at this + * edge, if any */ + int package_window; /**< How many more relay cells can I send into the + * circuit? */ + int deliver_window; /**< How many more relay cells can end at me? */ + + struct circuit_t *on_circuit; /**< The circuit (if any) that this edge + * connection is using. */ + + /** A pointer to which node in the circ this conn exits at. Set for AP + * connections and for hidden service exit connections. */ + struct crypt_path_t *cpath_layer; + /** What rendezvous service are we querying for (if an AP) or providing (if + * an exit)? */ + rend_data_t *rend_data; + + /* Hidden service connection identifier for edge connections. Used by the HS + * client-side code to identify client SOCKS connections and by the + * service-side code to match HS circuits with their streams. */ + struct hs_ident_edge_conn_t *hs_ident; + + uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit + * connection. Exit connections only. */ + uint32_t begincell_flags; /** Flags sent or received in the BEGIN cell + * for this connection */ + + streamid_t stream_id; /**< The stream ID used for this edge connection on its + * circuit */ + + /** The reason why this connection is closing; passed to the controller. */ + uint16_t end_reason; + + /** Bytes read since last call to control_event_stream_bandwidth_used() */ + uint32_t n_read; + + /** Bytes written since last call to control_event_stream_bandwidth_used() */ + uint32_t n_written; + + /** True iff this connection is for a DNS request only. */ + unsigned int is_dns_request:1; + /** True iff this connection is for a PTR DNS request. (exit only) */ + unsigned int is_reverse_dns_lookup:1; + + unsigned int edge_has_sent_end:1; /**< For debugging; only used on edge + * connections. Set once we've set the stream end, + * and check in connection_about_to_close_connection(). + */ + /** True iff we've blocked reading until the circuit has fewer queued + * cells. */ + unsigned int edge_blocked_on_circ:1; + + /** Unique ID for directory requests; this used to be in connection_t, but + * that's going away and being used on channels instead. We still tag + * edge connections with dirreq_id from circuits, so it's copied here. */ + uint64_t dirreq_id; +}; + +#endif + diff --git a/src/or/entry_connection_st.h b/src/or/entry_connection_st.h new file mode 100644 index 0000000000..2f9676088c --- /dev/null +++ b/src/or/entry_connection_st.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef ENTRY_CONNECTION_ST_H +#define ENTRY_CONNECTION_ST_H + +#include "or/edge_connection_st.h" + +/** Subtype of edge_connection_t for an "entry connection" -- that is, a SOCKS + * connection, a DNS request, a TransPort connection or a NATD connection */ +struct entry_connection_t { + struct edge_connection_t edge_; + + /** Nickname of planned exit node -- used with .exit support. */ + /* XXX prop220: we need to make chosen_exit_name able to encode Ed IDs too. + * That's logically part of the UI parts for prop220 though. */ + char *chosen_exit_name; + + socks_request_t *socks_request; /**< SOCKS structure describing request (AP + * only.) */ + + /* === Isolation related, AP only. === */ + entry_port_cfg_t entry_cfg; + /** AP only: The newnym epoch in which we created this connection. */ + unsigned nym_epoch; + + /** AP only: The original requested address before we rewrote it. */ + char *original_dest_address; + /* Other fields to isolate on already exist. The ClientAddr is addr. The + ClientProtocol is a combination of type and socks_request-> + socks_version. SocksAuth is socks_request->username/password. + DestAddr is in socks_request->address. */ + + /** Number of times we've reassigned this application connection to + * a new circuit. We keep track because the timeout is longer if we've + * already retried several times. */ + uint8_t num_socks_retries; + + /** For AP connections only: buffer for data that we have sent + * optimistically, which we might need to re-send if we have to + * retry this connection. */ + struct buf_t *pending_optimistic_data; + /* For AP connections only: buffer for data that we previously sent + * optimistically which we are currently re-sending as we retry this + * connection. */ + struct buf_t *sending_optimistic_data; + + /** If this is a DNSPort connection, this field holds the pending DNS + * request that we're going to try to answer. */ + struct evdns_server_request *dns_server_request; + +#define DEBUGGING_17659 + +#ifdef DEBUGGING_17659 + uint16_t marked_pending_circ_line; + const char *marked_pending_circ_file; +#endif + +#define NUM_CIRCUITS_LAUNCHED_THRESHOLD 10 + /** Number of times we've launched a circuit to handle this stream. If + * it gets too high, that could indicate an inconsistency between our + * "launch a circuit to handle this stream" logic and our "attach our + * stream to one of the available circuits" logic. */ + unsigned int num_circuits_launched:4; + + /** True iff this stream must attach to a one-hop circuit (e.g. for + * begin_dir). */ + unsigned int want_onehop:1; + /** True iff this stream should use a BEGIN_DIR relay command to establish + * itself rather than BEGIN (either via onehop or via a whole circuit). */ + unsigned int use_begindir:1; + + /** For AP connections only. If 1, and we fail to reach the chosen exit, + * stop requiring it. */ + unsigned int chosen_exit_optional:1; + /** For AP connections only. If non-zero, this exit node was picked as + * a result of the TrackHostExit, and the value decrements every time + * we fail to complete a circuit to our chosen exit -- if it reaches + * zero, abandon the associated mapaddress. */ + unsigned int chosen_exit_retries:3; + + /** True iff this is an AP connection that came from a transparent or + * NATd connection */ + unsigned int is_transparent_ap:1; + + /** For AP connections only: Set if this connection's target exit node + * allows optimistic data (that is, data sent on this stream before + * the exit has sent a CONNECTED cell) and we have chosen to use it. + */ + unsigned int may_use_optimistic_data : 1; +}; + +/** Cast a entry_connection_t subtype pointer to a edge_connection_t **/ +#define ENTRY_TO_EDGE_CONN(c) (&(((c))->edge_)) + +#endif + diff --git a/src/or/entry_port_cfg_st.h b/src/or/entry_port_cfg_st.h new file mode 100644 index 0000000000..9b07ccb067 --- /dev/null +++ b/src/or/entry_port_cfg_st.h @@ -0,0 +1,54 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef ENTRY_PORT_CFG_ST_H +#define ENTRY_PORT_CFG_ST_H + +#include "lib/cc/torint.h" +#include "or/or.h" + +struct entry_port_cfg_t { + /* Client port types (socks, dns, trans, natd) only: */ + uint8_t isolation_flags; /**< Zero or more isolation flags */ + int session_group; /**< A session group, or -1 if this port is not in a + * session group. */ + + /* Socks only: */ + /** When both no-auth and user/pass are advertised by a SOCKS client, select + * no-auth. */ + unsigned int socks_prefer_no_auth : 1; + /** When ISO_SOCKSAUTH is in use, Keep-Alive circuits indefinitely. */ + unsigned int socks_iso_keep_alive : 1; + + /* Client port types only: */ + unsigned int ipv4_traffic : 1; + unsigned int ipv6_traffic : 1; + unsigned int prefer_ipv6 : 1; + unsigned int dns_request : 1; + unsigned int onion_traffic : 1; + + /** For a socks listener: should we cache IPv4/IPv6 DNS information that + * exit nodes tell us? + * + * @{ */ + unsigned int cache_ipv4_answers : 1; + unsigned int cache_ipv6_answers : 1; + /** @} */ + /** For a socks listeners: if we find an answer in our client-side DNS cache, + * should we use it? + * + * @{ */ + unsigned int use_cached_ipv4_answers : 1; + unsigned int use_cached_ipv6_answers : 1; + /** @} */ + /** For socks listeners: When we can automap an address to IPv4 or IPv6, + * do we prefer IPv6? */ + unsigned int prefer_ipv6_virtaddr : 1; + +}; + +#endif + diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index 27d760f1a8..1919336223 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -112,32 +112,38 @@ #define ENTRYNODES_PRIVATE -#include "or.h" -#include "channel.h" -#include "bridges.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "circuitstats.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "control.h" -#include "crypto_rand.h" -#include "directory.h" -#include "entrynodes.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "transports.h" -#include "statefile.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/bridges.h" +#include "or/circpathbias.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/circuitstats.h" +#include "or/config.h" +#include "or/confparse.h" +#include "or/connection.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/directory.h" +#include "or/entrynodes.h" +#include "or/main.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/routerset.h" +#include "or/transports.h" +#include "or/statefile.h" +#include "lib/math/fp.h" + +#include "or/node_st.h" +#include "or/origin_circuit_st.h" + +#include "lib/crypt_ops/digestset.h" /** A list of existing guard selection contexts. */ static smartlist_t *guard_contexts = NULL; @@ -1060,7 +1066,7 @@ get_eligible_guards(const or_options_t *options, continue; } ++n_guards; - if (digestset_contains(sampled_guard_ids, node->identity)) + if (digestset_probably_contains(sampled_guard_ids, node->identity)) continue; smartlist_add(eligible_guards, (node_t*)node); } SMARTLIST_FOREACH_END(node); @@ -3684,4 +3690,3 @@ entry_guards_free_all(void) } circuit_build_times_free_timeouts(get_circuit_build_times_mutable()); } - diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h index e8c91da41b..e56d4632b6 100644 --- a/src/or/entrynodes.h +++ b/src/or/entrynodes.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #ifndef TOR_ENTRYNODES_H #define TOR_ENTRYNODES_H -#include "handles.h" +#include "common/handles.h" /* Forward declare for guard_selection_t; entrynodes.c has the real struct */ typedef struct guard_selection_s guard_selection_t; diff --git a/src/or/ext_orport.c b/src/or/ext_orport.c index b842442caf..701dc45288 100644 --- a/src/or/ext_orport.c +++ b/src/or/ext_orport.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,17 +17,19 @@ */ #define EXT_ORPORT_PRIVATE -#include "or.h" -#include "connection.h" -#include "connection_or.h" -#include "control.h" -#include "config.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "ext_orport.h" -#include "main.h" -#include "proto_ext_or.h" -#include "util.h" +#include "or/or.h" +#include "or/connection.h" +#include "or/connection_or.h" +#include "or/control.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/ext_orport.h" +#include "or/main.h" +#include "or/proto_ext_or.h" +#include "common/util.h" + +#include "or/or_connection_st.h" /** Allocate and return a structure capable of holding an Extended * ORPort message of body length <b>len</b>. */ diff --git a/src/or/ext_orport.h b/src/or/ext_orport.h index 09acbc407e..c235b076e7 100644 --- a/src/or/ext_orport.h +++ b/src/or/ext_orport.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef EXT_ORPORT_H diff --git a/src/or/extend_info_st.h b/src/or/extend_info_st.h new file mode 100644 index 0000000000..36eb3cd135 --- /dev/null +++ b/src/or/extend_info_st.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef EXTEND_INFO_ST_H +#define EXTEND_INFO_ST_H + +/** Information on router used when extending a circuit. We don't need a + * full routerinfo_t to extend: we only need addr:port:keyid to build an OR + * connection, and onion_key to create the onionskin. Note that for onehop + * general-purpose tunnels, the onion_key is NULL. */ +struct extend_info_t { + char nickname[MAX_HEX_NICKNAME_LEN+1]; /**< This router's nickname for + * display. */ + /** Hash of this router's RSA identity key. */ + char identity_digest[DIGEST_LEN]; + /** Ed25519 identity for this router, if any. */ + ed25519_public_key_t ed_identity; + uint16_t port; /**< OR port. */ + tor_addr_t addr; /**< IP address. */ + crypto_pk_t *onion_key; /**< Current onionskin key. */ + curve25519_public_key_t curve25519_onion_key; +}; + +#endif + diff --git a/src/or/extrainfo_st.h b/src/or/extrainfo_st.h new file mode 100644 index 0000000000..f91bba7b68 --- /dev/null +++ b/src/or/extrainfo_st.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef EXTRAINFO_ST_H +#define EXTRAINFO_ST_H + +#include "or/signed_descriptor_st.h" + +/** Information needed to keep and cache a signed extra-info document. */ +struct extrainfo_t { + signed_descriptor_t cache_info; + /** SHA256 digest of this document */ + uint8_t digest256[DIGEST256_LEN]; + /** The router's nickname. */ + char nickname[MAX_NICKNAME_LEN+1]; + /** True iff we found the right key for this extra-info, verified the + * signature, and found it to be bad. */ + unsigned int bad_sig : 1; + /** If present, we didn't have the right key to verify this extra-info, + * so this is a copy of the signature in the document. */ + char *pending_sig; + /** Length of pending_sig. */ + size_t pending_sig_len; +}; + +#endif + diff --git a/src/or/fp_pair.c b/src/or/fp_pair.c index c938e76678..1d7b751c23 100644 --- a/src/or/fp_pair.c +++ b/src/or/fp_pair.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,8 +17,8 @@ * certificate for any (ID key, signing key) pair. **/ -#include "or.h" -#include "fp_pair.h" +#include "or/or.h" +#include "or/fp_pair.h" /* Define fp_pair_map_t structures */ diff --git a/src/or/fp_pair.h b/src/or/fp_pair.h index 4498a16101..500c7c9928 100644 --- a/src/or/fp_pair.h +++ b/src/or/fp_pair.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,6 +9,12 @@ #ifndef _TOR_FP_PAIR_H #define _TOR_FP_PAIR_H +/** A pair of digests created by dir_split_resource_info_fingerprint_pairs() */ +typedef struct { + char first[DIGEST_LEN]; + char second[DIGEST_LEN]; +} fp_pair_t; + /* * Declare fp_pair_map_t functions and structs */ diff --git a/src/or/geoip.c b/src/or/geoip.c index d59043a7f6..fac35d3983 100644 --- a/src/or/geoip.c +++ b/src/or/geoip.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -28,15 +28,18 @@ */ #define GEOIP_PRIVATE -#include "or.h" +#include "or/or.h" #include "ht.h" -#include "buffers.h" -#include "config.h" -#include "control.h" -#include "dnsserv.h" -#include "dos.h" -#include "geoip.h" -#include "routerlist.h" +#include "lib/container/buffers.h" +#include "or/config.h" +#include "or/control.h" +#include "or/dnsserv.h" +#include "or/dos.h" +#include "or/geoip.h" +#include "or/routerlist.h" + +#include "lib/container/order.h" +#include "lib/time/tvdiff.h" static void init_geoip_countries(void); @@ -1884,4 +1887,3 @@ geoip_free_all(void) memset(geoip_digest, 0, sizeof(geoip_digest)); memset(geoip6_digest, 0, sizeof(geoip6_digest)); } - diff --git a/src/or/geoip.h b/src/or/geoip.h index 753bdbf82a..3a991038af 100644 --- a/src/or/geoip.h +++ b/src/or/geoip.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,8 @@ #ifndef TOR_GEOIP_H #define TOR_GEOIP_H -#include "testsupport.h" -#include "dos.h" +#include "lib/testsupport/testsupport.h" +#include "or/dos.h" #ifdef GEOIP_PRIVATE STATIC int geoip_parse_entry(const char *line, sa_family_t family); diff --git a/src/or/git_revision.c b/src/or/git_revision.c index 8f326b8751..be6f67423c 100644 --- a/src/or/git_revision.c +++ b/src/or/git_revision.c @@ -1,9 +1,9 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "git_revision.h" +#include "or/git_revision.h" /** String describing which Tor Git repository version the source was * built from. This string is generated by a bit of shell kludging in diff --git a/src/or/git_revision.h b/src/or/git_revision.h index 5613cb4335..02070cfd5e 100644 --- a/src/or/git_revision.h +++ b/src/or/git_revision.h @@ -1,6 +1,6 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_GIT_REVISION_H diff --git a/src/or/hibernate.c b/src/or/hibernate.c index d7d259470f..12264f758f 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -28,19 +28,21 @@ hibernating, phase 2: */ #define HIBERNATE_PRIVATE -#include "or.h" -#include "channel.h" -#include "channeltls.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_rand.h" -#include "hibernate.h" -#include "main.h" -#include "router.h" -#include "statefile.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/channeltls.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/connection_or.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/hibernate.h" +#include "or/main.h" +#include "or/router.h" +#include "or/statefile.h" + +#include "or/or_connection_st.h" /** Are we currently awake, asleep, running out of bandwidth, or shutting * down? */ diff --git a/src/or/hibernate.h b/src/or/hibernate.h index 453969d052..bfd8571cd6 100644 --- a/src/or/hibernate.h +++ b/src/or/hibernate.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #ifndef TOR_HIBERNATE_H #define TOR_HIBERNATE_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" int accounting_parse_options(const or_options_t *options, int validate_only); MOCK_DECL(int, accounting_is_enabled, (const or_options_t *options)); diff --git a/src/or/hs_cache.c b/src/or/hs_cache.c index ecc845d17f..a42fe6b1a3 100644 --- a/src/or/hs_cache.c +++ b/src/or/hs_cache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,17 +9,19 @@ /* For unit tests.*/ #define HS_CACHE_PRIVATE -#include "or.h" -#include "config.h" -#include "crypto_util.h" -#include "hs_ident.h" -#include "hs_common.h" -#include "hs_client.h" -#include "hs_descriptor.h" -#include "networkstatus.h" -#include "rendcache.h" - -#include "hs_cache.h" +#include "or/or.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/hs_ident.h" +#include "or/hs_common.h" +#include "or/hs_client.h" +#include "or/hs_descriptor.h" +#include "or/networkstatus.h" +#include "or/rendcache.h" + +#include "or/hs_cache.h" + +#include "or/networkstatus_st.h" static int cached_client_descriptor_has_expired(time_t now, const hs_cache_client_descriptor_t *cached_desc); diff --git a/src/or/hs_cache.h b/src/or/hs_cache.h index 0d0085ffdc..78ed81b6e0 100644 --- a/src/or/hs_cache.h +++ b/src/or/hs_cache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,11 +11,11 @@ #include <stdint.h> -#include "crypto_ed25519.h" -#include "hs_common.h" -#include "hs_descriptor.h" -#include "rendcommon.h" -#include "torcert.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "or/hs_common.h" +#include "or/hs_descriptor.h" +#include "or/rendcommon.h" +#include "or/torcert.h" /* This is the maximum time an introduction point state object can stay in the * client cache in seconds (2 mins or 120 seconds). */ diff --git a/src/or/hs_cell.c b/src/or/hs_cell.c index 03273a44f9..b50c87dfa3 100644 --- a/src/or/hs_cell.c +++ b/src/or/hs_cell.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,22 +6,24 @@ * \brief Hidden service API for cell creation and handling. **/ -#include "or.h" -#include "config.h" -#include "crypto_util.h" -#include "rendservice.h" -#include "replaycache.h" -#include "util.h" +#include "or/or.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/rendservice.h" +#include "or/replaycache.h" +#include "common/util.h" -#include "hs_cell.h" -#include "hs_ntor.h" +#include "or/hs_cell.h" +#include "or/hs_ntor.h" + +#include "or/origin_circuit_st.h" /* Trunnel. */ -#include "ed25519_cert.h" -#include "hs/cell_common.h" -#include "hs/cell_establish_intro.h" -#include "hs/cell_introduce1.h" -#include "hs/cell_rendezvous.h" +#include "trunnel/ed25519_cert.h" +#include "trunnel/hs/cell_common.h" +#include "trunnel/hs/cell_establish_intro.h" +#include "trunnel/hs/cell_introduce1.h" +#include "trunnel/hs/cell_rendezvous.h" /* Compute the MAC of an INTRODUCE cell in mac_out. The encoded_cell param is * the cell content up to the ENCRYPTED section of length encoded_cell_len. diff --git a/src/or/hs_cell.h b/src/or/hs_cell.h index 958dde4ffc..4a522810c6 100644 --- a/src/or/hs_cell.h +++ b/src/or/hs_cell.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,8 @@ #ifndef TOR_HS_CELL_H #define TOR_HS_CELL_H -#include "or.h" -#include "hs_service.h" +#include "or/or.h" +#include "or/hs_service.h" /* An INTRODUCE1 cell requires at least this amount of bytes (see section * 3.2.2 of the specification). Below this value, the cell must be padded. */ diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c index a35d2af8ba..9fcb30ecc6 100644 --- a/src/or/hs_circuit.c +++ b/src/or/hs_circuit.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,31 +7,36 @@ #define HS_CIRCUIT_PRIVATE -#include "or.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "nodelist.h" -#include "policies.h" -#include "relay.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" - -#include "hs_cell.h" -#include "hs_ident.h" -#include "hs_ntor.h" -#include "hs_service.h" -#include "hs_circuit.h" +#include "or/or.h" +#include "or/circpathbias.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/relay.h" +#include "or/rendservice.h" +#include "or/rephist.h" +#include "or/router.h" + +#include "or/hs_cell.h" +#include "or/hs_ident.h" +#include "or/hs_ntor.h" +#include "or/hs_service.h" +#include "or/hs_circuit.h" /* Trunnel. */ -#include "ed25519_cert.h" -#include "hs/cell_common.h" -#include "hs/cell_establish_intro.h" +#include "trunnel/ed25519_cert.h" +#include "trunnel/hs/cell_common.h" +#include "trunnel/hs/cell_establish_intro.h" + +#include "or/cpath_build_state_st.h" +#include "or/crypt_path_st.h" +#include "or/node_st.h" +#include "or/origin_circuit_st.h" /* A circuit is about to become an e2e rendezvous circuit. Check * <b>circ_purpose</b> and ensure that it's properly set. Return true iff diff --git a/src/or/hs_circuit.h b/src/or/hs_circuit.h index f69137e1d5..425070f4ca 100644 --- a/src/or/hs_circuit.h +++ b/src/or/hs_circuit.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,10 +9,10 @@ #ifndef TOR_HS_CIRCUIT_H #define TOR_HS_CIRCUIT_H -#include "or.h" -#include "crypto_ed25519.h" +#include "or/or.h" +#include "lib/crypt_ops/crypto_ed25519.h" -#include "hs_service.h" +#include "or/hs_service.h" /* Cleanup function when the circuit is closed or/and freed. */ void hs_circ_cleanup(circuit_t *circ); diff --git a/src/or/hs_circuitmap.c b/src/or/hs_circuitmap.c index 112c8bdced..21db652492 100644 --- a/src/or/hs_circuitmap.c +++ b/src/or/hs_circuitmap.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,10 +13,13 @@ #define HS_CIRCUITMAP_PRIVATE -#include "or.h" -#include "config.h" -#include "circuitlist.h" -#include "hs_circuitmap.h" +#include "or/or.h" +#include "or/config.h" +#include "or/circuitlist.h" +#include "or/hs_circuitmap.h" + +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" /************************** HS circuitmap code *******************************/ diff --git a/src/or/hs_circuitmap.h b/src/or/hs_circuitmap.h index 9e653480b5..2118a6414a 100644 --- a/src/or/hs_circuitmap.h +++ b/src/or/hs_circuitmap.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/hs_client.c b/src/or/hs_client.c index b39bb2cad0..8fddd51a47 100644 --- a/src/or/hs_client.c +++ b/src/or/hs_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,32 +8,37 @@ #define HS_CLIENT_PRIVATE -#include "or.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "container.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "hs_cache.h" -#include "hs_cell.h" -#include "hs_circuit.h" -#include "hs_client.h" -#include "hs_control.h" -#include "hs_descriptor.h" -#include "hs_ident.h" -#include "hs_ntor.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "reasons.h" -#include "rendclient.h" -#include "router.h" -#include "routerset.h" +#include "or/or.h" +#include "or/circpathbias.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/directory.h" +#include "or/hs_cache.h" +#include "or/hs_cell.h" +#include "or/hs_circuit.h" +#include "or/hs_client.h" +#include "or/hs_control.h" +#include "or/hs_descriptor.h" +#include "or/hs_ident.h" +#include "or/hs_ntor.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/reasons.h" +#include "or/rendclient.h" +#include "or/router.h" +#include "or/routerset.h" + +#include "or/cpath_build_state_st.h" +#include "or/dir_connection_st.h" +#include "or/entry_connection_st.h" +#include "or/extend_info_st.h" +#include "or/origin_circuit_st.h" /* Return a human-readable string for the client fetch status code. */ static const char * diff --git a/src/or/hs_client.h b/src/or/hs_client.h index 2523568ad1..8083910747 100644 --- a/src/or/hs_client.h +++ b/src/or/hs_client.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,9 +9,9 @@ #ifndef TOR_HS_CLIENT_H #define TOR_HS_CLIENT_H -#include "crypto_ed25519.h" -#include "hs_descriptor.h" -#include "hs_ident.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "or/hs_descriptor.h" +#include "or/hs_ident.h" /* Status code of a descriptor fetch request. */ typedef enum { diff --git a/src/or/hs_common.c b/src/or/hs_common.c index 5354055bb0..e88a04620e 100644 --- a/src/or/hs_common.c +++ b/src/or/hs_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,30 +11,36 @@ #define HS_COMMON_PRIVATE -#include "or.h" - -#include "config.h" -#include "circuitbuild.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "hs_cache.h" -#include "hs_common.h" -#include "hs_client.h" -#include "hs_ident.h" -#include "hs_service.h" -#include "hs_circuitmap.h" -#include "policies.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "routerset.h" -#include "router.h" -#include "shared_random_client.h" -#include "dirauth/shared_random_state.h" +#include "or/or.h" + +#include "or/config.h" +#include "or/circuitbuild.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/hs_cache.h" +#include "or/hs_common.h" +#include "or/hs_client.h" +#include "or/hs_ident.h" +#include "or/hs_service.h" +#include "or/hs_circuitmap.h" +#include "or/policies.h" +#include "or/rendcommon.h" +#include "or/rendservice.h" +#include "or/routerset.h" +#include "or/router.h" +#include "or/shared_random_client.h" +#include "or/dirauth/shared_random_state.h" + +#include "or/edge_connection_st.h" +#include "or/networkstatus_st.h" +#include "or/node_st.h" +#include "or/origin_circuit_st.h" +#include "or/routerstatus_st.h" /* Trunnel */ -#include "ed25519_cert.h" +#include "trunnel/ed25519_cert.h" /* Ed25519 Basepoint value. Taken from section 5 of * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03 */ diff --git a/src/or/hs_common.h b/src/or/hs_common.h index ef7d5dca2b..6d60d7799f 100644 --- a/src/or/hs_common.h +++ b/src/or/hs_common.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,10 +9,10 @@ #ifndef TOR_HS_COMMON_H #define TOR_HS_COMMON_H -#include "or.h" +#include "or/or.h" /* Trunnel */ -#include "ed25519_cert.h" +#include "trunnel/ed25519_cert.h" /* Protocol version 2. Use this instead of hardcoding "2" in the code base, * this adds a clearer semantic to the value when used. */ diff --git a/src/or/hs_config.c b/src/or/hs_config.c index be223503a0..c8ce5b43fa 100644 --- a/src/or/hs_config.c +++ b/src/or/hs_config.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -25,10 +25,10 @@ #define HS_CONFIG_PRIVATE -#include "hs_common.h" -#include "hs_config.h" -#include "hs_service.h" -#include "rendservice.h" +#include "or/hs_common.h" +#include "or/hs_config.h" +#include "or/hs_service.h" +#include "or/rendservice.h" /* Using the given list of services, stage them into our global state. Every * service version are handled. This function can remove entries in the given diff --git a/src/or/hs_config.h b/src/or/hs_config.h index 6cd7aed460..461d58d384 100644 --- a/src/or/hs_config.h +++ b/src/or/hs_config.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,7 +9,7 @@ #ifndef TOR_HS_CONFIG_H #define TOR_HS_CONFIG_H -#include "or.h" +#include "or/or.h" /* Max value for HiddenServiceMaxStreams */ #define HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT 65535 diff --git a/src/or/hs_control.c b/src/or/hs_control.c index 6b9b95c6d8..76c40918bb 100644 --- a/src/or/hs_control.c +++ b/src/or/hs_control.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,14 +6,17 @@ * \brief Contains control port event related code. **/ -#include "or.h" -#include "control.h" -#include "crypto_util.h" -#include "hs_common.h" -#include "hs_control.h" -#include "hs_descriptor.h" -#include "hs_service.h" -#include "nodelist.h" +#include "or/or.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/hs_common.h" +#include "or/hs_control.h" +#include "or/hs_descriptor.h" +#include "or/hs_service.h" +#include "or/nodelist.h" + +#include "or/node_st.h" +#include "or/routerstatus_st.h" /* Send on the control port the "HS_DESC REQUESTED [...]" event. * diff --git a/src/or/hs_control.h b/src/or/hs_control.h index 95c46e655e..040ce4a793 100644 --- a/src/or/hs_control.h +++ b/src/or/hs_control.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,7 +9,7 @@ #ifndef TOR_HS_CONTROL_H #define TOR_HS_CONTROL_H -#include "hs_ident.h" +#include "or/hs_ident.h" /* Event "HS_DESC REQUESTED [...]" */ void hs_control_desc_event_requested(const ed25519_public_key_t *onion_pk, diff --git a/src/or/hs_descriptor.c b/src/or/hs_descriptor.c index 7ffa885ca8..8971ec59f3 100644 --- a/src/or/hs_descriptor.c +++ b/src/or/hs_descriptor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -55,17 +55,19 @@ /* For unit tests.*/ #define HS_DESCRIPTOR_PRIVATE -#include "or.h" -#include "ed25519_cert.h" /* Trunnel interface. */ -#include "hs_descriptor.h" -#include "circuitbuild.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "parsecommon.h" -#include "rendcache.h" -#include "hs_cache.h" -#include "hs_config.h" -#include "torcert.h" /* tor_cert_encode_ed22519() */ +#include "or/or.h" +#include "trunnel/ed25519_cert.h" /* Trunnel interface. */ +#include "or/hs_descriptor.h" +#include "or/circuitbuild.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/parsecommon.h" +#include "or/rendcache.h" +#include "or/hs_cache.h" +#include "or/hs_config.h" +#include "or/torcert.h" /* tor_cert_encode_ed22519() */ + +#include "or/extend_info_st.h" /* Constant string value used for the descriptor format. */ #define str_hs_desc "hs-descriptor" diff --git a/src/or/hs_descriptor.h b/src/or/hs_descriptor.h index 8195c6efbc..d16234969d 100644 --- a/src/or/hs_descriptor.h +++ b/src/or/hs_descriptor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,13 +11,12 @@ #include <stdint.h> -#include "or.h" -#include "address.h" -#include "container.h" -#include "crypto.h" -#include "crypto_ed25519.h" -#include "ed25519_cert.h" /* needed for trunnel */ -#include "torcert.h" +#include "or/or.h" +#include "lib/net/address.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "trunnel/ed25519_cert.h" /* needed for trunnel */ +#include "or/torcert.h" /* Trunnel */ struct link_specifier_t; diff --git a/src/or/hs_ident.c b/src/or/hs_ident.c index 3603e329d4..20539ca878 100644 --- a/src/or/hs_ident.c +++ b/src/or/hs_ident.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,8 +7,8 @@ * subsytem. **/ -#include "crypto_util.h" -#include "hs_ident.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/hs_ident.h" /* Return a newly allocated circuit identifier. The given public key is copied * identity_pk into the identifier. */ diff --git a/src/or/hs_ident.h b/src/or/hs_ident.h index 8f9da30c35..8c53b9dbeb 100644 --- a/src/or/hs_ident.h +++ b/src/or/hs_ident.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,9 +21,9 @@ #ifndef TOR_HS_IDENT_H #define TOR_HS_IDENT_H -#include "crypto_ed25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" -#include "hs_common.h" +#include "or/hs_common.h" /* Length of the rendezvous cookie that is used to connect circuits at the * rendezvous point. */ diff --git a/src/or/hs_intropoint.c b/src/or/hs_intropoint.c index 3274e8e9c0..6c0729b050 100644 --- a/src/or/hs_intropoint.c +++ b/src/or/hs_intropoint.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,24 +8,26 @@ #define HS_INTROPOINT_PRIVATE -#include "or.h" -#include "config.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "relay.h" -#include "rendmid.h" -#include "rephist.h" +#include "or/or.h" +#include "or/config.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/relay.h" +#include "or/rendmid.h" +#include "or/rephist.h" /* Trunnel */ -#include "ed25519_cert.h" -#include "hs/cell_common.h" -#include "hs/cell_establish_intro.h" -#include "hs/cell_introduce1.h" - -#include "hs_circuitmap.h" -#include "hs_descriptor.h" -#include "hs_intropoint.h" -#include "hs_common.h" +#include "trunnel/ed25519_cert.h" +#include "trunnel/hs/cell_common.h" +#include "trunnel/hs/cell_establish_intro.h" +#include "trunnel/hs/cell_introduce1.h" + +#include "or/hs_circuitmap.h" +#include "or/hs_descriptor.h" +#include "or/hs_intropoint.h" +#include "or/hs_common.h" + +#include "or/or_circuit_st.h" /** Extract the authentication key from an ESTABLISH_INTRO or INTRODUCE1 using * the given <b>cell_type</b> from <b>cell</b> and place it in diff --git a/src/or/hs_intropoint.h b/src/or/hs_intropoint.h index 749d1530e1..5f82920991 100644 --- a/src/or/hs_intropoint.h +++ b/src/or/hs_intropoint.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,8 @@ #ifndef TOR_HS_INTRO_H #define TOR_HS_INTRO_H -#include "crypto_curve25519.h" -#include "torcert.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "or/torcert.h" /* Authentication key type in an ESTABLISH_INTRO cell. */ typedef enum { @@ -55,8 +55,8 @@ void hs_intropoint_clear(hs_intropoint_t *ip); #ifdef HS_INTROPOINT_PRIVATE -#include "hs/cell_establish_intro.h" -#include "hs/cell_introduce1.h" +#include "trunnel/hs/cell_establish_intro.h" +#include "trunnel/hs/cell_introduce1.h" STATIC int verify_establish_intro_cell(const trn_cell_establish_intro_t *out, diff --git a/src/or/hs_ntor.c b/src/or/hs_ntor.c index 809fa83bb8..a8a76ed54d 100644 --- a/src/or/hs_ntor.c +++ b/src/or/hs_ntor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** \file hs_ntor.c @@ -24,9 +24,9 @@ * rendezvous key expansion to setup end-to-end rend circuit keys. */ -#include "or.h" -#include "crypto_util.h" -#include "hs_ntor.h" +#include "or/or.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/hs_ntor.h" /* String constants used by the ntor HS protocol */ #define PROTOID "tor-hs-ntor-curve25519-sha3-256-1" diff --git a/src/or/hs_ntor.h b/src/or/hs_ntor.h index 77e544a130..cc4afd536b 100644 --- a/src/or/hs_ntor.h +++ b/src/or/hs_ntor.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_HS_NTOR_H #define TOR_HS_NTOR_H -#include "or.h" +#include "or/or.h" /* Output length of KDF for key expansion */ #define HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN \ diff --git a/src/or/hs_service.c b/src/or/hs_service.c index f1f26954ae..b5649e2636 100644 --- a/src/or/hs_service.c +++ b/src/or/hs_service.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,41 +8,49 @@ #define HS_SERVICE_PRIVATE -#include "or.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "relay.h" -#include "rendservice.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "shared_random_client.h" -#include "statefile.h" - -#include "hs_circuit.h" -#include "hs_common.h" -#include "hs_config.h" -#include "hs_control.h" -#include "hs_descriptor.h" -#include "hs_ident.h" -#include "hs_intropoint.h" -#include "hs_service.h" -#include "hs_stats.h" +#include "or/or.h" +#include "or/circpathbias.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "or/connection.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/directory.h" +#include "or/main.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/relay.h" +#include "or/rendservice.h" +#include "or/router.h" +#include "or/routerkeys.h" +#include "or/routerlist.h" +#include "or/shared_random_client.h" +#include "or/statefile.h" + +#include "or/hs_circuit.h" +#include "or/hs_common.h" +#include "or/hs_config.h" +#include "or/hs_control.h" +#include "or/hs_descriptor.h" +#include "or/hs_ident.h" +#include "or/hs_intropoint.h" +#include "or/hs_service.h" +#include "or/hs_stats.h" + +#include "or/dir_connection_st.h" +#include "or/edge_connection_st.h" +#include "or/extend_info_st.h" +#include "or/networkstatus_st.h" +#include "or/node_st.h" +#include "or/origin_circuit_st.h" +#include "or/routerstatus_st.h" /* Trunnel */ -#include "ed25519_cert.h" -#include "hs/cell_common.h" -#include "hs/cell_establish_intro.h" +#include "trunnel/ed25519_cert.h" +#include "trunnel/hs/cell_common.h" +#include "trunnel/hs/cell_establish_intro.h" /* Helper macro. Iterate over every service in the global map. The var is the * name of the service pointer. */ diff --git a/src/or/hs_service.h b/src/or/hs_service.h index 5494b6f5fa..4676042b54 100644 --- a/src/or/hs_service.h +++ b/src/or/hs_service.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,17 +9,17 @@ #ifndef TOR_HS_SERVICE_H #define TOR_HS_SERVICE_H -#include "crypto_curve25519.h" -#include "crypto_ed25519.h" -#include "replaycache.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "or/replaycache.h" -#include "hs_common.h" -#include "hs_descriptor.h" -#include "hs_ident.h" -#include "hs_intropoint.h" +#include "or/hs_common.h" +#include "or/hs_descriptor.h" +#include "or/hs_ident.h" +#include "or/hs_intropoint.h" /* Trunnel */ -#include "hs/cell_establish_intro.h" +#include "trunnel/hs/cell_establish_intro.h" /* When loading and configuring a service, this is the default version it will * be configured for as it is possible that no HiddenServiceVersion is diff --git a/src/or/hs_stats.c b/src/or/hs_stats.c index 1e2a96945b..c8a99b19d4 100644 --- a/src/or/hs_stats.c +++ b/src/or/hs_stats.c @@ -6,9 +6,9 @@ * \brief Keeps stats about the activity of our onion service(s). **/ -#include "or.h" -#include "hs_stats.h" -#include "hs_service.h" +#include "or/or.h" +#include "or/hs_stats.h" +#include "or/hs_service.h" /** Number of v3 INTRODUCE2 cells received */ static uint32_t n_introduce2_v3 = 0; diff --git a/src/or/hsdir_index_st.h b/src/or/hsdir_index_st.h new file mode 100644 index 0000000000..de5cc9bd16 --- /dev/null +++ b/src/or/hsdir_index_st.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef HSDIR_INDEX_ST_H +#define HSDIR_INDEX_ST_H + +/* Hidden service directory index used in a node_t which is set once we set + * the consensus. */ +struct hsdir_index_t { + /* HSDir index to use when fetching a descriptor. */ + uint8_t fetch[DIGEST256_LEN]; + + /* HSDir index used by services to store their first and second + * descriptor. The first descriptor is chronologically older than the second + * one and uses older TP and SRV values. */ + uint8_t store_first[DIGEST256_LEN]; + uint8_t store_second[DIGEST256_LEN]; +}; + +#endif + diff --git a/src/or/include.am b/src/or/include.am index 59d593a5e9..ed5d0c95c4 100644 --- a/src/or/include.am +++ b/src/or/include.am @@ -1,9 +1,9 @@ bin_PROGRAMS+= src/or/tor noinst_LIBRARIES += \ - src/or/libtor.a + src/or/libtor-app.a if UNITTESTS_ENABLED noinst_LIBRARIES += \ - src/or/libtor-testing.a + src/or/libtor-app-testing.a endif if COVERAGE_ENABLED noinst_PROGRAMS+= src/or/tor-cov @@ -17,7 +17,7 @@ endif EXTRA_DIST+= src/or/ntmain.c src/or/Makefile.nmake -LIBTOR_A_SOURCES = \ +LIBTOR_APP_A_SOURCES = \ src/or/addressmap.c \ src/or/bridges.c \ src/or/channel.c \ @@ -118,7 +118,7 @@ LIBTOR_A_SOURCES = \ # source files of every module to libtor-testing.a so we can build the unit # tests for everything. See the UNITTESTS_ENABLED branch below. # -LIBTOR_TESTING_A_SOURCES = $(LIBTOR_A_SOURCES) +LIBTOR_APP_TESTING_A_SOURCES = $(LIBTOR_APP_A_SOURCES) # The Directory Authority module. MODULE_DIRAUTH_SOURCES = \ @@ -127,32 +127,31 @@ MODULE_DIRAUTH_SOURCES = \ src/or/dirauth/shared_random.c \ src/or/dirauth/shared_random_state.c if BUILD_MODULE_DIRAUTH -LIBTOR_A_SOURCES += $(MODULE_DIRAUTH_SOURCES) +LIBTOR_APP_A_SOURCES += $(MODULE_DIRAUTH_SOURCES) endif -src_or_libtor_a_SOURCES = $(LIBTOR_A_SOURCES) +src_or_libtor_app_a_SOURCES = $(LIBTOR_APP_A_SOURCES) if UNITTESTS_ENABLED # Add the sources of the modules that are needed for tests to work here. -LIBTOR_TESTING_A_SOURCES += $(MODULE_DIRAUTH_SOURCES) +LIBTOR_APP_TESTING_A_SOURCES += $(MODULE_DIRAUTH_SOURCES) -src_or_libtor_testing_a_SOURCES = $(LIBTOR_TESTING_A_SOURCES) +src_or_libtor_app_testing_a_SOURCES = $(LIBTOR_APP_TESTING_A_SOURCES) else -src_or_libtor_testing_a_SOURCES = +src_or_libtor_app_testing_a_SOURCES = endif src_or_tor_SOURCES = src/or/tor_main.c -AM_CPPFLAGS += -I$(srcdir)/src/or -Isrc/or -src/or/tor_main.$(OBJEXT) \ - src/or/src_or_tor_cov-tor_main.$(OBJEXT): micro-revision.i +src/or/git_revision.$(OBJEXT) \ + src/or/src_or_libtor_app_testing_a-git_revision.$(OBJEXT): micro-revision.i AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \ -DLOCALSTATEDIR="\"$(localstatedir)\"" \ -DBINDIR="\"$(bindir)\"" -src_or_libtor_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) -src_or_libtor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +src_or_libtor_app_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_or_libtor_app_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) # -L flags need to go in LDFLAGS. -l flags need to go in LDADD. # This seems to matter nowhere but on windows, but I assure you that it @@ -160,13 +159,10 @@ src_or_libtor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_or_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@ -src_or_tor_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-ctime.a \ - src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \ - src/common/libor-event.a src/trunnel/libor-trunnel.a \ - src/trace/libor-trace.a \ +src_or_tor_LDADD = $(TOR_INTERNAL_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @@ -175,19 +171,20 @@ src_or_tor_cov_SOURCES = src/or/tor_main.c src_or_tor_cov_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_or_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_or_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@ -src_or_tor_cov_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \ - src/common/libor-event-testing.a src/trunnel/libor-trunnel-testing.a \ +src_or_tor_cov_LDADD = $(TOR_INTERNAL_TESTING_LIBS) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ \ + @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ endif ORHEADERS = \ src/or/addressmap.h \ + src/or/authority_cert_st.h \ src/or/auth_dirs.inc \ src/or/bridges.h \ + src/or/cell_st.h \ + src/or/cell_queue_st.h \ src/or/channel.h \ src/or/channelpadding.h \ src/or/channeltls.h \ @@ -198,24 +195,42 @@ ORHEADERS = \ src/or/circuitmux_ewma.h \ src/or/circuitstats.h \ src/or/circuituse.h \ + src/or/circuit_st.h \ + src/or/cached_dir_st.h \ src/or/command.h \ src/or/config.h \ src/or/confparse.h \ src/or/connection.h \ + src/or/connection_st.h \ src/or/connection_edge.h \ src/or/connection_or.h \ src/or/conscache.h \ src/or/consdiff.h \ src/or/consdiffmgr.h \ + src/or/control_connection_st.h \ src/or/control.h \ + src/or/cpath_build_state_st.h \ + src/or/crypt_path_st.h \ + src/or/crypt_path_reference_st.h \ src/or/cpuworker.h \ + src/or/desc_store_st.h \ + src/or/destroy_cell_queue_st.h \ src/or/directory.h \ src/or/dirserv.h \ + src/or/dir_connection_st.h \ + src/or/dir_server_st.h \ + src/or/document_signature_st.h \ + src/or/download_status_st.h \ src/or/dns.h \ src/or/dns_structs.h \ src/or/dnsserv.h \ src/or/dos.h \ + src/or/edge_connection_st.h \ + src/or/entry_connection_st.h \ + src/or/entry_port_cfg_st.h \ src/or/ext_orport.h \ + src/or/extend_info_st.h \ + src/or/extrainfo_st.h \ src/or/fallback_dirs.inc \ src/or/fp_pair.h \ src/or/geoip.h \ @@ -236,20 +251,34 @@ ORHEADERS = \ src/or/hs_ntor.h \ src/or/hs_stats.h \ src/or/hs_service.h \ + src/or/hsdir_index_st.h \ src/or/keypin.h \ + src/or/listener_connection_st.h \ src/or/main.h \ src/or/microdesc.h \ + src/or/microdesc_st.h \ src/or/networkstatus.h \ + src/or/networkstatus_st.h \ + src/or/networkstatus_sr_info_st.h \ + src/or/networkstatus_voter_info_st.h \ src/or/nodelist.h \ + src/or/node_st.h \ + src/or/ns_detached_signatures_st.h \ src/or/ntmain.h \ src/or/onion.h \ src/or/onion_fast.h \ src/or/onion_ntor.h \ src/or/onion_tap.h \ src/or/or.h \ + src/or/or_circuit_st.h \ + src/or/or_connection_st.h \ + src/or/or_handshake_certs_st.h \ + src/or/or_handshake_state_st.h \ + src/or/origin_circuit_st.h \ src/or/transports.h \ - src/or/parsecommon.h \ + src/or/parsecommon.h \ src/or/periodic.h \ + src/or/port_cfg_st.h \ src/or/policies.h \ src/or/protover.h \ src/or/proto_cell.h \ @@ -260,25 +289,41 @@ ORHEADERS = \ src/or/reasons.h \ src/or/relay.h \ src/or/relay_crypto.h \ + src/or/relay_crypto_st.h \ src/or/rendcache.h \ src/or/rendclient.h \ src/or/rendcommon.h \ src/or/rendmid.h \ src/or/rendservice.h \ + src/or/rend_authorized_client_st.h \ + src/or/rend_encoded_v2_service_descriptor_st.h \ + src/or/rend_intro_point_st.h \ + src/or/rend_service_descriptor_st.h \ src/or/rephist.h \ src/or/replaycache.h \ src/or/router.h \ + src/or/routerinfo_st.h \ src/or/routerkeys.h \ src/or/routerlist.h \ + src/or/routerlist_st.h \ src/or/routerkeys.h \ src/or/routerset.h \ src/or/routerparse.h \ + src/or/routerstatus_st.h \ src/or/scheduler.h \ + src/or/server_port_cfg_st.h \ src/or/shared_random_client.h \ + src/or/signed_descriptor_st.h \ + src/or/socks_request_st.h \ src/or/statefile.h \ src/or/status.h \ src/or/torcert.h \ src/or/tor_api_internal.h \ + src/or/tor_version_st.h \ + src/or/var_cell_st.h \ + src/or/vote_microdesc_hash_st.h \ + src/or/vote_routerstatus_st.h \ + src/or/vote_timing_st.h \ src/or/voting_schedule.h # We add the headers of the modules even though they are disabled so we can diff --git a/src/or/keypin.c b/src/or/keypin.c index 97e16c1f78..34cf64f5c4 100644 --- a/src/or/keypin.c +++ b/src/or/keypin.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,17 +11,17 @@ #define KEYPIN_PRIVATE #include "orconfig.h" -#include "compat.h" -#include "crypto_digest.h" -#include "crypto_format.h" -#include "di_ops.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/ctime/di_ops.h" #include "ht.h" -#include "keypin.h" +#include "or/keypin.h" #include "siphash.h" -#include "torint.h" -#include "torlog.h" -#include "util.h" -#include "util_format.h" +#include "lib/cc/torint.h" +#include "lib/log/torlog.h" +#include "lib/fdio/fdio.h" +#include "common/util.h" +#include "lib/encoding/binascii.h" #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -308,7 +308,7 @@ keypin_open_journal(const char *fname) char tbuf[ISO_TIME_LEN+1]; format_iso_time(tbuf, approx_time()); tor_snprintf(buf, sizeof(buf), "@opened-at %s\n", tbuf); - if (write_all(fd, buf, strlen(buf), 0) < 0) + if (write_all_to_fd(fd, buf, strlen(buf)) < 0) goto err; keypin_journal_fd = fd; @@ -347,7 +347,7 @@ keypin_journal_append_entry(const uint8_t *rsa_id_digest, (const char*)ed25519_id_key); line[BASE64_DIGEST_LEN+1+BASE64_DIGEST256_LEN] = '\n'; - if (write_all(keypin_journal_fd, line, JOURNAL_LINE_LEN, 0)<0) { + if (write_all_to_fd(keypin_journal_fd, line, JOURNAL_LINE_LEN)<0) { log_warn(LD_DIRSERV, "Error while adding a line to the key-pinning " "journal: %s", strerror(errno)); keypin_close_journal(); @@ -498,4 +498,3 @@ keypin_clear(void) bad_entries); } } - diff --git a/src/or/keypin.h b/src/or/keypin.h index fbb77e5c35..73a76be563 100644 --- a/src/or/keypin.h +++ b/src/or/keypin.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_KEYPIN_H #define TOR_KEYPIN_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" int keypin_check_and_add(const uint8_t *rsa_id_digest, const uint8_t *ed25519_id_key, diff --git a/src/or/listener_connection_st.h b/src/or/listener_connection_st.h new file mode 100644 index 0000000000..7b5aafcb58 --- /dev/null +++ b/src/or/listener_connection_st.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef LISTENER_CONNECTION_ST_H +#define LISTENER_CONNECTION_ST_H + +#include "or/connection_st.h" + +/** Subtype of connection_t; used for a listener socket. */ +struct listener_connection_t { + connection_t base_; + + /** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points + * to the evdns_server_port it uses to listen to and answer connections. */ + struct evdns_server_port *dns_server_port; + + entry_port_cfg_t entry_cfg; + +}; + +#endif + diff --git a/src/or/main.c b/src/or/main.c index 9dce158b33..81a8cfbee9 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -47,80 +47,89 @@ **/ #define MAIN_PRIVATE -#include "or.h" -#include "addressmap.h" -#include "backtrace.h" -#include "bridges.h" -#include "buffers.h" -#include "buffers_tls.h" -#include "channel.h" -#include "channeltls.h" -#include "channelpadding.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "circuitmux_ewma.h" -#include "command.h" -#include "compress.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "consdiffmgr.h" -#include "control.h" -#include "cpuworker.h" -#include "crypto_s2k.h" -#include "crypto_rand.h" -#include "directory.h" -#include "dirserv.h" -#include "dns.h" -#include "dnsserv.h" -#include "dos.h" -#include "entrynodes.h" -#include "geoip.h" -#include "hibernate.h" -#include "hs_cache.h" -#include "hs_circuitmap.h" -#include "hs_client.h" -#include "keypin.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "ntmain.h" -#include "onion.h" -#include "periodic.h" -#include "policies.h" -#include "protover.h" -#include "transports.h" -#include "relay.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "routerparse.h" -#include "scheduler.h" -#include "statefile.h" -#include "status.h" -#include "tor_api.h" -#include "tor_api_internal.h" -#include "util_process.h" -#include "ext_orport.h" -#ifdef USE_DMALLOC -#include <dmalloc.h> -#endif -#include "memarea.h" -#include "sandbox.h" +#include "or/or.h" +#include "or/addressmap.h" +#include "lib/err/backtrace.h" +#include "or/bridges.h" +#include "lib/container/buffers.h" +#include "lib/tls/buffers_tls.h" +#include "or/channel.h" +#include "or/channeltls.h" +#include "or/channelpadding.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/circuitmux_ewma.h" +#include "or/command.h" +#include "lib/compress/compress.h" +#include "or/config.h" +#include "or/confparse.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/connection_or.h" +#include "or/consdiffmgr.h" +#include "or/control.h" +#include "or/cpuworker.h" +#include "lib/crypt_ops/crypto_s2k.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/directory.h" +#include "or/dirserv.h" +#include "or/dns.h" +#include "or/dnsserv.h" +#include "or/dos.h" +#include "or/entrynodes.h" +#include "or/geoip.h" +#include "or/hibernate.h" +#include "or/hs_cache.h" +#include "or/hs_circuitmap.h" +#include "or/hs_client.h" +#include "or/keypin.h" +#include "or/main.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/ntmain.h" +#include "or/onion.h" +#include "or/periodic.h" +#include "or/policies.h" +#include "or/protover.h" +#include "or/transports.h" +#include "or/relay.h" +#include "or/rendclient.h" +#include "or/rendcommon.h" +#include "or/rendservice.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerkeys.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/scheduler.h" +#include "or/statefile.h" +#include "or/status.h" +#include "or/tor_api.h" +#include "or/tor_api_internal.h" +#include "lib/process/waitpid.h" +#include "or/ext_orport.h" +#include "lib/memarea/memarea.h" +#include "lib/meminfo/meminfo.h" +#include "lib/osinfo/uname.h" +#include "lib/sandbox/sandbox.h" +#include "lib/fs/lockfile.h" +#include "lib/net/buffers_net.h" #include <event2/event.h> -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" -#include "dirauth/shared_random.h" +#include "or/dirauth/dirvote.h" +#include "or/dirauth/mode.h" +#include "or/dirauth/shared_random.h" + +#include "or/cell_st.h" +#include "or/entry_connection_st.h" +#include "or/networkstatus_st.h" +#include "or/or_connection_st.h" +#include "or/port_cfg_st.h" +#include "or/routerinfo_st.h" +#include "or/socks_request_st.h" #ifdef HAVE_SYSTEMD # if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__) @@ -2687,11 +2696,6 @@ do_hup(void) { const or_options_t *options = get_options(); -#ifdef USE_DMALLOC - dmalloc_log_stats(); - dmalloc_log_changed(0, 1, 0, 0); -#endif - log_notice(LD_GENERAL,"Received reload signal (hup). Reloading config and " "resetting internal state."); if (accounting_is_enabled(options)) @@ -3631,7 +3635,7 @@ release_lockfile(void) * only the parts of memory that we won't touch. If !<b>postfork</b>, * Tor is shutting down and we should free everything. * - * Helps us find the real leaks with dmalloc and the like. Also valgrind + * Helps us find the real leaks with sanitizers and the like. Also valgrind * should then report 0 reachable in its leak report (in an ideal world -- * in practice libevent, SSL, libc etc never quite free everything). */ void @@ -3787,18 +3791,11 @@ tor_cleanup(void) timers_shutdown(); -#ifdef USE_DMALLOC - dmalloc_log_stats(); -#endif tor_free_all(0); /* We could move tor_free_all back into the ifdef below later, if it makes shutdown unacceptably slow. But for now, leave it here: it's helped us catch bugs in the past. */ crypto_global_cleanup(); -#ifdef USE_DMALLOC - dmalloc_log_unfreed(); - dmalloc_shutdown(); -#endif } /** Read/create keys as needed, and echo our fingerprint to stdout. */ @@ -4221,7 +4218,13 @@ tor_run_main(const tor_main_configuration_t *tor_cfg) } #endif /* defined(_WIN32) */ - configure_backtrace_handler(get_version()); + { + int bt_err = configure_backtrace_handler(get_version()); + if (bt_err < 0) { + log_warn(LD_BUG, "Unable to install backtrace handler: %s", + strerror(-bt_err)); + } + } init_protocol_warning_severity_level(); update_approx_time(time(NULL)); @@ -4229,14 +4232,6 @@ tor_run_main(const tor_main_configuration_t *tor_cfg) tor_compress_init(); init_logging(0); monotime_init(); -#ifdef USE_DMALLOC - { - /* Instruct OpenSSL to use our internal wrappers for malloc, - realloc and free. */ - int r = crypto_use_tor_alloc_functions(); - tor_assert(r == 0); - } -#endif /* defined(USE_DMALLOC) */ #ifdef NT_SERVICE { int done = 0; @@ -4305,4 +4300,3 @@ tor_run_main(const tor_main_configuration_t *tor_cfg) tor_cleanup(); return result; } - diff --git a/src/or/main.h b/src/or/main.h index 9dbbc6e5ee..214a9b3b0a 100644 --- a/src/or/main.h +++ b/src/or/main.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -112,7 +112,7 @@ STATIC int get_my_roles(const or_options_t *options); extern smartlist_t *connection_array; /* We need the periodic_event_item_t definition. */ -#include "periodic.h" +#include "or/periodic.h" extern periodic_event_item_t periodic_events[]; #endif #endif /* defined(MAIN_PRIVATE) */ diff --git a/src/or/microdesc.c b/src/or/microdesc.c index b4a934e095..838c966a20 100644 --- a/src/or/microdesc.c +++ b/src/or/microdesc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2017, The Tor Project, Inc. */ +/* Copyright (c) 2009-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,19 +8,27 @@ * less-frequently-changing router information. */ -#include "or.h" -#include "circuitbuild.h" -#include "config.h" -#include "directory.h" -#include "dirserv.h" -#include "entrynodes.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" +#include "or/or.h" + +#include "lib/fdio/fdio.h" + +#include "or/circuitbuild.h" +#include "or/config.h" +#include "or/directory.h" +#include "or/dirserv.h" +#include "or/entrynodes.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerparse.h" + +#include "or/microdesc_st.h" +#include "or/networkstatus_st.h" +#include "or/node_st.h" +#include "or/routerstatus_st.h" /** A data structure to hold a bunch of cached microdescriptors. There are * two active files in the cache: a "cache file" that we mmap, and a "journal @@ -189,7 +197,7 @@ dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out) char annotation[ISO_TIME_LEN+32]; format_iso_time(buf, md->last_listed); tor_snprintf(annotation, sizeof(annotation), "@last-listed %s\n", buf); - if (write_all(fd, annotation, strlen(annotation), 0) < 0) { + if (write_all_to_fd(fd, annotation, strlen(annotation)) < 0) { log_warn(LD_DIR, "Couldn't write microdescriptor annotation: %s", strerror(errno)); @@ -202,7 +210,7 @@ dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out) } md->off = tor_fd_getpos(fd); - written = write_all(fd, md->body, md->bodylen, 0); + written = write_all_to_fd(fd, md->body, md->bodylen); if (written != (ssize_t)md->bodylen) { written = written < 0 ? 0 : written; log_warn(LD_DIR, @@ -1042,4 +1050,3 @@ usable_consensus_flavor,(void)) return FLAV_NS; } } - diff --git a/src/or/microdesc.h b/src/or/microdesc.h index 83a90bd8ff..f11b841cf1 100644 --- a/src/or/microdesc.h +++ b/src/or/microdesc.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/microdesc_st.h b/src/or/microdesc_st.h new file mode 100644 index 0000000000..256659e679 --- /dev/null +++ b/src/or/microdesc_st.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef MICRODESC_ST_H +#define MICRODESC_ST_H + +/** A microdescriptor is the smallest amount of information needed to build a + * circuit through a router. They are generated by the directory authorities, + * using information from the uploaded routerinfo documents. They are not + * self-signed, but are rather authenticated by having their hash in a signed + * networkstatus document. */ +struct microdesc_t { + /** Hashtable node, used to look up the microdesc by its digest. */ + HT_ENTRY(microdesc_t) node; + + /* Cache information */ + + /** When was this microdescriptor last listed in a consensus document? + * Once a microdesc has been unlisted long enough, we can drop it. + */ + time_t last_listed; + /** Where is this microdescriptor currently stored? */ + saved_location_bitfield_t saved_location : 3; + /** If true, do not attempt to cache this microdescriptor on disk. */ + unsigned int no_save : 1; + /** If true, this microdesc has an entry in the microdesc_map */ + unsigned int held_in_map : 1; + /** Reference count: how many node_ts have a reference to this microdesc? */ + unsigned int held_by_nodes; + + /** If saved_location == SAVED_IN_CACHE, this field holds the offset of the + * microdescriptor in the cache. */ + off_t off; + + /* The string containing the microdesc. */ + + /** A pointer to the encoded body of the microdescriptor. If the + * saved_location is SAVED_IN_CACHE, then the body is a pointer into an + * mmap'd region. Otherwise, it is a malloc'd string. The string might not + * be NUL-terminated; take the length from <b>bodylen</b>. */ + char *body; + /** The length of the microdescriptor in <b>body</b>. */ + size_t bodylen; + /** A SHA256-digest of the microdescriptor. */ + char digest[DIGEST256_LEN]; + + /* Fields in the microdescriptor. */ + + /** As routerinfo_t.onion_pkey */ + crypto_pk_t *onion_pkey; + /** As routerinfo_t.onion_curve25519_pkey */ + curve25519_public_key_t *onion_curve25519_pkey; + /** Ed25519 identity key, if included. */ + ed25519_public_key_t *ed25519_identity_pkey; + /** As routerinfo_t.ipv6_addr */ + tor_addr_t ipv6_addr; + /** As routerinfo_t.ipv6_orport */ + uint16_t ipv6_orport; + /** As routerinfo_t.family */ + smartlist_t *family; + /** IPv4 exit policy summary */ + short_policy_t *exit_policy; + /** IPv6 exit policy summary */ + short_policy_t *ipv6_exit_policy; +}; + +#endif + diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 998eaf74e6..b12846197c 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -37,42 +37,55 @@ */ #define NETWORKSTATUS_PRIVATE -#include "or.h" -#include "bridges.h" -#include "channel.h" -#include "circuitmux.h" -#include "circuitmux_ewma.h" -#include "circuitstats.h" -#include "config.h" -#include "connection.h" -#include "connection_or.h" -#include "consdiffmgr.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "dirserv.h" -#include "dos.h" -#include "entrynodes.h" -#include "hibernate.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "protover.h" -#include "relay.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "scheduler.h" -#include "transports.h" -#include "torcert.h" -#include "channelpadding.h" -#include "voting_schedule.h" - -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" -#include "dirauth/shared_random.h" +#include "or/or.h" +#include "or/bridges.h" +#include "or/channel.h" +#include "or/circuitmux.h" +#include "or/circuitmux_ewma.h" +#include "or/circuitstats.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_or.h" +#include "or/consdiffmgr.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/directory.h" +#include "or/dirserv.h" +#include "or/dos.h" +#include "or/entrynodes.h" +#include "or/hibernate.h" +#include "or/main.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/protover.h" +#include "or/relay.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/scheduler.h" +#include "or/transports.h" +#include "or/torcert.h" +#include "or/channelpadding.h" +#include "or/voting_schedule.h" + +#include "or/dirauth/dirvote.h" +#include "or/dirauth/mode.h" +#include "or/dirauth/shared_random.h" + +#include "or/authority_cert_st.h" +#include "or/dir_connection_st.h" +#include "or/dir_server_st.h" +#include "or/document_signature_st.h" +#include "or/networkstatus_st.h" +#include "or/networkstatus_voter_info_st.h" +#include "or/ns_detached_signatures_st.h" +#include "or/node_st.h" +#include "or/routerinfo_st.h" +#include "or/routerlist_st.h" +#include "or/vote_microdesc_hash_st.h" +#include "or/vote_routerstatus_st.h" /** Most recently received and validated v3 "ns"-flavored consensus network * status. */ @@ -593,8 +606,11 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus, char *tmp = smartlist_join_strings(list_good, " ", 0, NULL); smartlist_add_asprintf(sl, "A consensus needs %d good signatures from recognized " - "authorities for us to accept it. This one has %d (%s).", - n_required, n_good, tmp); + "authorities for us to accept it. " + "This %s one has %d (%s).", + n_required, + networkstatus_get_flavor_name(consensus->flavor), + n_good, tmp); tor_free(tmp); if (n_no_signature) { tmp = smartlist_join_strings(list_no_signature, " ", 0, NULL); diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h index 94f85c3c29..cc6badf0b2 100644 --- a/src/or/networkstatus.h +++ b/src/or/networkstatus.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #ifndef TOR_NETWORKSTATUS_H #define TOR_NETWORKSTATUS_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" void networkstatus_reset_warnings(void); void networkstatus_reset_download_failures(void); diff --git a/src/or/networkstatus_sr_info_st.h b/src/or/networkstatus_sr_info_st.h new file mode 100644 index 0000000000..6c937a75f5 --- /dev/null +++ b/src/or/networkstatus_sr_info_st.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef NETWORKSTATUS_SR_INFO_ST_H +#define NETWORKSTATUS_SR_INFO_ST_H + +struct networkstatus_sr_info_t { + /* Indicate if the dirauth partitipates in the SR protocol with its vote. + * This is tied to the SR flag in the vote. */ + unsigned int participate:1; + /* Both vote and consensus: Current and previous SRV. If list is empty, + * this means none were found in either the consensus or vote. */ + struct sr_srv_t *previous_srv; + struct sr_srv_t *current_srv; + /* Vote only: List of commitments. */ + smartlist_t *commits; +}; + +#endif + diff --git a/src/or/networkstatus_st.h b/src/or/networkstatus_st.h new file mode 100644 index 0000000000..4fc04a5aa7 --- /dev/null +++ b/src/or/networkstatus_st.h @@ -0,0 +1,95 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef NETWORKSTATUS_ST_H +#define NETWORKSTATUS_ST_H + +#include "or/networkstatus_sr_info_st.h" + +/** A common structure to hold a v3 network status vote, or a v3 network + * status consensus. */ +struct networkstatus_t { + networkstatus_type_t type; /**< Vote, consensus, or opinion? */ + consensus_flavor_t flavor; /**< If a consensus, what kind? */ + unsigned int has_measured_bws : 1;/**< True iff this networkstatus contains + * measured= bandwidth values. */ + + time_t published; /**< Vote only: Time when vote was written. */ + time_t valid_after; /**< Time after which this vote or consensus applies. */ + time_t fresh_until; /**< Time before which this is the most recent vote or + * consensus. */ + time_t valid_until; /**< Time after which this vote or consensus should not + * be used. */ + + /** Consensus only: what method was used to produce this consensus? */ + int consensus_method; + /** Vote only: what methods is this voter willing to use? */ + smartlist_t *supported_methods; + + /** List of 'package' lines describing hashes of downloadable packages */ + smartlist_t *package_lines; + + /** How long does this vote/consensus claim that authorities take to + * distribute their votes to one another? */ + int vote_seconds; + /** How long does this vote/consensus claim that authorities take to + * distribute their consensus signatures to one another? */ + int dist_seconds; + + /** Comma-separated list of recommended client software, or NULL if this + * voter has no opinion. */ + char *client_versions; + char *server_versions; + + /** Lists of subprotocol versions which are _recommended_ for relays and + * clients, or which are _require_ for relays and clients. Tor shouldn't + * make any more network connections if a required protocol is missing. + */ + char *recommended_relay_protocols; + char *recommended_client_protocols; + char *required_relay_protocols; + char *required_client_protocols; + + /** List of flags that this vote/consensus applies to routers. If a flag is + * not listed here, the voter has no opinion on what its value should be. */ + smartlist_t *known_flags; + + /** List of key=value strings for the parameters in this vote or + * consensus, sorted by key. */ + smartlist_t *net_params; + + /** List of key=value strings for the bw weight parameters in the + * consensus. */ + smartlist_t *weight_params; + + /** List of networkstatus_voter_info_t. For a vote, only one element + * is included. For a consensus, one element is included for every voter + * whose vote contributed to the consensus. */ + smartlist_t *voters; + + struct authority_cert_t *cert; /**< Vote only: the voter's certificate. */ + + /** Digests of this document, as signed. */ + common_digests_t digests; + /** A SHA3-256 digest of the document, not including signatures: used for + * consensus diffs */ + uint8_t digest_sha3_as_signed[DIGEST256_LEN]; + + /** List of router statuses, sorted by identity digest. For a vote, + * the elements are vote_routerstatus_t; for a consensus, the elements + * are routerstatus_t. */ + smartlist_t *routerstatus_list; + + /** If present, a map from descriptor digest to elements of + * routerstatus_list. */ + digestmap_t *desc_digest_map; + + /** Contains the shared random protocol data from a vote or consensus. */ + networkstatus_sr_info_t sr_info; +}; + +#endif + diff --git a/src/or/networkstatus_voter_info_st.h b/src/or/networkstatus_voter_info_st.h new file mode 100644 index 0000000000..93ff3cd418 --- /dev/null +++ b/src/or/networkstatus_voter_info_st.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef NETWORKSTATUS_VOTER_INFO_ST_H +#define NETWORKSTATUS_VOTER_INFO_ST_H + +/** Information about a single voter in a vote or a consensus. */ +struct networkstatus_voter_info_t { + /** Declared SHA-1 digest of this voter's identity key */ + char identity_digest[DIGEST_LEN]; + char *nickname; /**< Nickname of this voter */ + /** Digest of this voter's "legacy" identity key, if any. In vote only; for + * consensuses, we treat legacy keys as additional signers. */ + char legacy_id_digest[DIGEST_LEN]; + char *address; /**< Address of this voter, in string format. */ + uint32_t addr; /**< Address of this voter, in IPv4, in host order. */ + uint16_t dir_port; /**< Directory port of this voter */ + uint16_t or_port; /**< OR port of this voter */ + char *contact; /**< Contact information for this voter. */ + char vote_digest[DIGEST_LEN]; /**< Digest of this voter's vote, as signed. */ + + /* Nothing from here on is signed. */ + /** The signature of the document and the signature's status. */ + smartlist_t *sigs; +}; + +#endif diff --git a/src/or/node_st.h b/src/or/node_st.h new file mode 100644 index 0000000000..cc777003d8 --- /dev/null +++ b/src/or/node_st.h @@ -0,0 +1,102 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef NODE_ST_H +#define NODE_ST_H + +#include "or/hsdir_index_st.h" + +/** A node_t represents a Tor router. + * + * Specifically, a node_t is a Tor router as we are using it: a router that + * we are considering for circuits, connections, and so on. A node_t is a + * thin wrapper around the routerstatus, routerinfo, and microdesc for a + * single router, and provides a consistent interface for all of them. + * + * Also, a node_t has mutable state. While a routerinfo, a routerstatus, + * and a microdesc have[*] only the information read from a router + * descriptor, a consensus entry, and a microdescriptor (respectively)... + * a node_t has flags based on *our own current opinion* of the node. + * + * [*] Actually, there is some leftover information in each that is mutable. + * We should try to excise that. + */ +struct node_t { + /* Indexing information */ + + /** Used to look up the node_t by its identity digest. */ + HT_ENTRY(node_t) ht_ent; + /** Used to look up the node_t by its ed25519 identity digest. */ + HT_ENTRY(node_t) ed_ht_ent; + /** Position of the node within the list of nodes */ + int nodelist_idx; + + /** The identity digest of this node_t. No more than one node_t per + * identity may exist at a time. */ + char identity[DIGEST_LEN]; + + /** The ed25519 identity of this node_t. This field is nonzero iff we + * currently have an ed25519 identity for this node in either md or ri, + * _and_ this node has been inserted to the ed25519-to-node map in the + * nodelist. + */ + ed25519_public_key_t ed25519_id; + + microdesc_t *md; + routerinfo_t *ri; + routerstatus_t *rs; + + /* local info: copied from routerstatus, then possibly frobbed based + * on experience. Authorities set this stuff directly. Note that + * these reflect knowledge of the primary (IPv4) OR port only. */ + + unsigned int is_running:1; /**< As far as we know, is this OR currently + * running? */ + unsigned int is_valid:1; /**< Has a trusted dirserver validated this OR? + * (For Authdir: Have we validated this OR?) */ + unsigned int is_fast:1; /** Do we think this is a fast OR? */ + unsigned int is_stable:1; /** Do we think this is a stable OR? */ + unsigned int is_possible_guard:1; /**< Do we think this is an OK guard? */ + unsigned int is_exit:1; /**< Do we think this is an OK exit? */ + unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked, + * or otherwise nasty? */ + unsigned int is_hs_dir:1; /**< True iff this router is a hidden service + * directory according to the authorities. */ + + /* Local info: warning state. */ + + unsigned int name_lookup_warned:1; /**< Have we warned the user for referring + * to this (unnamed) router by nickname? + */ + + /** Local info: we treat this node as if it rejects everything */ + unsigned int rejects_all:1; + + /* Local info: derived. */ + + /** True if the IPv6 OR port is preferred over the IPv4 OR port. + * XX/teor - can this become out of date if the torrc changes? */ + unsigned int ipv6_preferred:1; + + /** According to the geoip db what country is this router in? */ + /* XXXprop186 what is this suppose to mean with multiple OR ports? */ + country_t country; + + /* The below items are used only by authdirservers for + * reachability testing. */ + + /** When was the last time we could reach this OR? */ + time_t last_reachable; /* IPv4. */ + time_t last_reachable6; /* IPv6. */ + + /* Hidden service directory index data. This is used by a service or client + * in order to know what's the hs directory index for this node at the time + * the consensus is set. */ + struct hsdir_index_t hsdir_index; +}; + +#endif + diff --git a/src/or/nodelist.c b/src/or/nodelist.c index ce1830083f..bc04ab9526 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -40,33 +40,41 @@ #define NODELIST_PRIVATE -#include "or.h" -#include "address.h" -#include "address_set.h" -#include "bridges.h" -#include "config.h" -#include "control.h" -#include "dirserv.h" -#include "entrynodes.h" -#include "geoip.h" -#include "hs_common.h" -#include "hs_client.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "protover.h" -#include "rendservice.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "torcert.h" +#include "or/or.h" +#include "lib/net/address.h" +#include "common/address_set.h" +#include "or/bridges.h" +#include "or/config.h" +#include "or/control.h" +#include "or/dirserv.h" +#include "or/entrynodes.h" +#include "or/geoip.h" +#include "or/hs_common.h" +#include "or/hs_client.h" +#include "or/main.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/protover.h" +#include "or/rendservice.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/routerset.h" +#include "or/torcert.h" #include <string.h> -#include "dirauth/mode.h" +#include "or/dirauth/mode.h" + +#include "or/dir_server_st.h" +#include "or/microdesc_st.h" +#include "or/networkstatus_st.h" +#include "or/node_st.h" +#include "or/routerinfo_st.h" +#include "or/routerlist_st.h" +#include "or/routerstatus_st.h" static void nodelist_drop_node(node_t *node, int remove_from_ht); #define node_free(val) \ @@ -643,6 +651,15 @@ nodelist_set_consensus(networkstatus_t *ns) } } +/** Return 1 iff <b>node</b> has Exit flag and no BadExit flag. + * Otherwise, return 0. + */ +int +node_is_good_exit(const node_t *node) +{ + return node->is_exit && ! node->is_bad_exit; +} + /** Helper: return true iff a node has a usable amount of information*/ static inline int node_is_usable(const node_t *node) @@ -2243,9 +2260,14 @@ compute_frac_paths_available(const networkstatus_t *consensus, * browsing (as distinct from hidden service web browsing). */ } - f_guard = frac_nodes_with_descriptors(guards, WEIGHT_FOR_GUARD); - f_mid = frac_nodes_with_descriptors(mid, WEIGHT_FOR_MID); - f_exit = frac_nodes_with_descriptors(exits, WEIGHT_FOR_EXIT); + f_guard = frac_nodes_with_descriptors(guards, WEIGHT_FOR_GUARD, 1); + f_mid = frac_nodes_with_descriptors(mid, WEIGHT_FOR_MID, 0); + f_exit = frac_nodes_with_descriptors(exits, WEIGHT_FOR_EXIT, 0); + + /* If we are using bridges and have at least one bridge with a full + * descriptor, assume f_guard is 1.0. */ + if (options->UseBridges && num_bridges_usable(0) > 0) + f_guard = 1.0; log_debug(LD_NET, "f_guard: %.2f, f_mid: %.2f, f_exit: %.2f", @@ -2299,9 +2321,10 @@ compute_frac_paths_available(const networkstatus_t *consensus, np, nu); - f_myexit= frac_nodes_with_descriptors(myexits,WEIGHT_FOR_EXIT); + f_myexit= frac_nodes_with_descriptors(myexits, WEIGHT_FOR_EXIT, 0); f_myexit_unflagged= - frac_nodes_with_descriptors(myexits_unflagged,WEIGHT_FOR_EXIT); + frac_nodes_with_descriptors(myexits_unflagged, + WEIGHT_FOR_EXIT, 0); log_debug(LD_NET, "f_exit: %.2f, f_myexit: %.2f, f_myexit_unflagged: %.2f", diff --git a/src/or/nodelist.h b/src/or/nodelist.h index dbe9ad18ff..06aec0bad5 100644 --- a/src/or/nodelist.h +++ b/src/or/nodelist.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -47,6 +47,7 @@ void node_get_verbose_nickname(const node_t *node, void node_get_verbose_nickname_by_id(const char *id_digest, char *verbose_name_out); int node_is_dir(const node_t *node); +int node_is_good_exit(const node_t *node); int node_has_any_descriptor(const node_t *node); int node_has_preferred_descriptor(const node_t *node, int for_direct_connect); diff --git a/src/or/ns_detached_signatures_st.h b/src/or/ns_detached_signatures_st.h new file mode 100644 index 0000000000..26ceec84b9 --- /dev/null +++ b/src/or/ns_detached_signatures_st.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef NS_DETACHED_SIGNATURES_ST_H +#define NS_DETACHED_SIGNATURES_ST_H + +/** A set of signatures for a networkstatus consensus. Unless otherwise + * noted, all fields are as for networkstatus_t. */ +struct ns_detached_signatures_t { + time_t valid_after; + time_t fresh_until; + time_t valid_until; + strmap_t *digests; /**< Map from flavor name to digestset_t */ + strmap_t *signatures; /**< Map from flavor name to list of + * document_signature_t */ +}; + +#endif + diff --git a/src/or/ntmain.c b/src/or/ntmain.c index e9a299807a..e23a41fb83 100644 --- a/src/or/ntmain.c +++ b/src/or/ntmain.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,10 +19,12 @@ #ifdef _WIN32 -#include "or.h" -#include "config.h" -#include "main.h" -#include "ntmain.h" +#include "or/or.h" +#include "or/config.h" +#include "or/main.h" +#include "or/ntmain.h" +#include "lib/log/win32err.h" +#include "lib/fs/winlib.h" #include <windows.h> #define GENSRV_SERVICENAME "tor" @@ -778,4 +780,3 @@ nt_service_parse_options(int argc, char **argv, int *should_exit) } #endif /* defined(_WIN32) */ - diff --git a/src/or/ntmain.h b/src/or/ntmain.h index 81b7159855..223d9e318b 100644 --- a/src/or/ntmain.h +++ b/src/or/ntmain.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/onion.c b/src/or/onion.c index 829be12bae..776aacbf78 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -62,23 +62,27 @@ * onion_fast.c for more information. **/ -#include "or.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "config.h" -#include "cpuworker.h" -#include "crypto_util.h" -#include "networkstatus.h" -#include "onion.h" -#include "onion_fast.h" -#include "onion_ntor.h" -#include "onion_tap.h" -#include "relay.h" -#include "rephist.h" -#include "router.h" +#include "or/or.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/config.h" +#include "or/cpuworker.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/networkstatus.h" +#include "or/onion.h" +#include "or/onion_fast.h" +#include "or/onion_ntor.h" +#include "or/onion_tap.h" +#include "or/relay.h" +#include "or/rephist.h" +#include "or/router.h" + +#include "or/cell_st.h" +#include "or/extend_info_st.h" +#include "or/or_circuit_st.h" // trunnel -#include "ed25519_cert.h" +#include "trunnel/ed25519_cert.h" /** Type for a linked list of circuits that are waiting for a free CPU worker * to process a waiting onion handshake. */ diff --git a/src/or/onion.h b/src/or/onion.h index 3b738debeb..57224f629e 100644 --- a/src/or/onion.h +++ b/src/or/onion.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/onion_fast.c b/src/or/onion_fast.c index 9f9b2199d4..7d555c26e7 100644 --- a/src/or/onion_fast.c +++ b/src/or/onion_fast.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,10 +27,10 @@ * many RSA1024 keys. **/ -#include "or.h" -#include "onion_fast.h" -#include "crypto_rand.h" -#include "crypto_util.h" +#include "or/or.h" +#include "or/onion_fast.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" /** Release all state held in <b>victim</b>. */ void diff --git a/src/or/onion_fast.h b/src/or/onion_fast.h index c56712e2c2..a7b6ec53f4 100644 --- a/src/or/onion_fast.h +++ b/src/or/onion_fast.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/onion_ntor.c b/src/or/onion_ntor.c index 02d43cb722..3a60d1b7ec 100644 --- a/src/or/onion_ntor.c +++ b/src/or/onion_ntor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,12 +21,13 @@ #include "orconfig.h" #define ONION_NTOR_PRIVATE -#include "crypto.h" -#include "crypto_digest.h" -#include "crypto_util.h" -#include "onion_ntor.h" -#include "torlog.h" -#include "util.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_hkdf.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/onion_ntor.h" +#include "lib/log/torlog.h" +#include "common/util.h" /** Free storage held in an ntor handshake state. */ void diff --git a/src/or/onion_ntor.h b/src/or/onion_ntor.h index f7c962b7d0..b4da3a8d79 100644 --- a/src/or/onion_ntor.h +++ b/src/or/onion_ntor.h @@ -1,12 +1,12 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_ONION_NTOR_H #define TOR_ONION_NTOR_H -#include "torint.h" -#include "crypto_curve25519.h" -#include "di_ops.h" +#include "lib/cc/torint.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/ctime/di_ops.h" /** State to be maintained by a client between sending an ntor onionskin * and receiving a reply. */ diff --git a/src/or/onion_tap.c b/src/or/onion_tap.c index 44737034f4..cf5963b19e 100644 --- a/src/or/onion_tap.c +++ b/src/or/onion_tap.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,12 +27,12 @@ * invoked from onion.c. **/ -#include "or.h" -#include "config.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "onion_tap.h" -#include "rephist.h" +#include "or/or.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/onion_tap.h" +#include "or/rephist.h" /*----------------------------------------------------------------------*/ diff --git a/src/or/onion_tap.h b/src/or/onion_tap.h index 713c1d7391..fdc2ce9123 100644 --- a/src/or/onion_tap.h +++ b/src/or/onion_tap.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/or.h b/src/or/or.h index e106ec66fa..63349cffbb 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -26,7 +26,7 @@ #ifdef HAVE_SYS_PARAM_H #include <sys/param.h> /* FreeBSD needs this to know what version it is */ #endif -#include "torint.h" +#include "lib/cc/torint.h" #ifdef HAVE_SYS_FCNTL_H #include <sys/fcntl.h> #endif @@ -51,9 +51,6 @@ #ifdef HAVE_ERRNO_H #include <errno.h> #endif -#ifdef HAVE_ASSERT_H -#include <assert.h> -#endif #ifdef HAVE_TIME_H #include <time.h> #endif @@ -66,23 +63,31 @@ #include <windows.h> #endif /* defined(_WIN32) */ -#include "crypto.h" -#include "crypto_format.h" -#include "tortls.h" -#include "torlog.h" -#include "container.h" -#include "compress.h" -#include "address.h" -#include "compat_libevent.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_hkdf.h" +#include "lib/tls/tortls.h" +#include "lib/log/torlog.h" +#include "lib/container/smartlist.h" +#include "lib/container/map.h" +#include "lib/compress/compress.h" +#include "lib/net/address.h" +#include "common/compat_libevent.h" #include "ht.h" -#include "confline.h" -#include "replaycache.h" -#include "crypto_curve25519.h" -#include "crypto_ed25519.h" +#include "lib/encoding/confline.h" +#include "or/replaycache.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" #include "tor_queue.h" -#include "token_bucket.h" -#include "util_format.h" -#include "hs_circuitmap.h" +#include "common/token_bucket.h" +#include "lib/encoding/binascii.h" +#include "or/hs_circuitmap.h" +#include "common/util.h" + +// These, more than other includes, are for keeping the other struct +// definitions working. We should remove them when we minimize our includes. +#include "or/entry_port_cfg_st.h" /* These signals are defined to help handle_control_signal work. */ @@ -895,18 +900,7 @@ struct hs_ident_edge_conn_t; struct hs_ident_dir_conn_t; struct hs_ident_circuit_t; -/* Hidden service directory index used in a node_t which is set once we set - * the consensus. */ -typedef struct hsdir_index_t { - /* HSDir index to use when fetching a descriptor. */ - uint8_t fetch[DIGEST256_LEN]; - - /* HSDir index used by services to store their first and second - * descriptor. The first descriptor is chronologically older than the second - * one and uses older TP and SRV values. */ - uint8_t store_first[DIGEST256_LEN]; - uint8_t store_second[DIGEST256_LEN]; -} hsdir_index_t; +typedef struct hsdir_index_t hsdir_index_t; /** Time interval for tracking replays of DH public keys received in * INTRODUCE2 cells. Used only to avoid launching multiple @@ -929,6 +923,7 @@ typedef enum { /** Initial value on both sides of a stream transmission window when the * stream is initialized. Measured in cells. */ #define STREAMWINDOW_START 500 +#define STREAMWINDOW_START_MAX 500 /** Amount to increment a stream window when we get a stream SENDME. */ #define STREAMWINDOW_INCREMENT 50 @@ -1172,26 +1167,12 @@ typedef struct channel_tls_s channel_tls_t; typedef struct circuitmux_s circuitmux_t; -/** Parsed onion routing cell. All communication between nodes - * is via cells. */ -typedef struct cell_t { - circid_t circ_id; /**< Circuit which received the cell. */ - uint8_t command; /**< Type of the cell: one of CELL_PADDING, CELL_CREATE, - * CELL_DESTROY, etc */ - uint8_t payload[CELL_PAYLOAD_SIZE]; /**< Cell body. */ -} cell_t; - -/** Parsed variable-length onion routing cell. */ -typedef struct var_cell_t { - /** Type of the cell: CELL_VERSIONS, etc. */ - uint8_t command; - /** Circuit thich received the cell */ - circid_t circ_id; - /** Number of bytes actually stored in <b>payload</b> */ - uint16_t payload_len; - /** Payload of this cell */ - uint8_t payload[FLEXIBLE_ARRAY_MEMBER]; -} var_cell_t; +typedef struct cell_t cell_t; +typedef struct var_cell_t var_cell_t; +typedef struct packed_cell_t packed_cell_t; +typedef struct cell_queue_t cell_queue_t; +typedef struct destroy_cell_t destroy_cell_t; +typedef struct destroy_cell_queue_t destroy_cell_queue_t; /** A parsed Extended ORPort message. */ typedef struct ext_or_cmd_t { @@ -1200,39 +1181,6 @@ typedef struct ext_or_cmd_t { char body[FLEXIBLE_ARRAY_MEMBER]; /** Message body */ } ext_or_cmd_t; -/** A cell as packed for writing to the network. */ -typedef struct packed_cell_t { - /** Next cell queued on this circuit. */ - TOR_SIMPLEQ_ENTRY(packed_cell_t) next; - char body[CELL_MAX_NETWORK_SIZE]; /**< Cell as packed for network. */ - uint32_t inserted_timestamp; /**< Time (in timestamp units) when this cell - * was inserted */ -} packed_cell_t; - -/** A queue of cells on a circuit, waiting to be added to the - * or_connection_t's outbuf. */ -typedef struct cell_queue_t { - /** Linked list of packed_cell_t*/ - TOR_SIMPLEQ_HEAD(cell_simpleq, packed_cell_t) head; - int n; /**< The number of cells in the queue. */ -} cell_queue_t; - -/** A single queued destroy cell. */ -typedef struct destroy_cell_t { - TOR_SIMPLEQ_ENTRY(destroy_cell_t) next; - circid_t circid; - uint32_t inserted_timestamp; /**< Time (in timestamp units) when this cell - * was inserted */ - uint8_t reason; -} destroy_cell_t; - -/** A queue of destroy cells on a channel. */ -typedef struct destroy_cell_queue_t { - /** Linked list of packed_cell_t */ - TOR_SIMPLEQ_HEAD(dcell_simpleq, destroy_cell_t) head; - int n; /**< The number of cells in the queue. */ -} destroy_cell_queue_t; - /** Beginning of a RELAY cell payload. */ typedef struct { uint8_t command; /**< The end-to-end relay command. */ @@ -1243,55 +1191,8 @@ typedef struct { } relay_header_t; typedef struct socks_request_t socks_request_t; - -typedef struct entry_port_cfg_t { - /* Client port types (socks, dns, trans, natd) only: */ - uint8_t isolation_flags; /**< Zero or more isolation flags */ - int session_group; /**< A session group, or -1 if this port is not in a - * session group. */ - - /* Socks only: */ - /** When both no-auth and user/pass are advertised by a SOCKS client, select - * no-auth. */ - unsigned int socks_prefer_no_auth : 1; - /** When ISO_SOCKSAUTH is in use, Keep-Alive circuits indefinitely. */ - unsigned int socks_iso_keep_alive : 1; - - /* Client port types only: */ - unsigned int ipv4_traffic : 1; - unsigned int ipv6_traffic : 1; - unsigned int prefer_ipv6 : 1; - unsigned int dns_request : 1; - unsigned int onion_traffic : 1; - - /** For a socks listener: should we cache IPv4/IPv6 DNS information that - * exit nodes tell us? - * - * @{ */ - unsigned int cache_ipv4_answers : 1; - unsigned int cache_ipv6_answers : 1; - /** @} */ - /** For a socks listeners: if we find an answer in our client-side DNS cache, - * should we use it? - * - * @{ */ - unsigned int use_cached_ipv4_answers : 1; - unsigned int use_cached_ipv6_answers : 1; - /** @} */ - /** For socks listeners: When we can automap an address to IPv4 or IPv6, - * do we prefer IPv6? */ - unsigned int prefer_ipv6_virtaddr : 1; - -} entry_port_cfg_t; - -typedef struct server_port_cfg_t { - /* Server port types (or, dir) only: */ - unsigned int no_advertise : 1; - unsigned int no_listen : 1; - unsigned int all_addrs : 1; - unsigned int bind_ipv4_only : 1; - unsigned int bind_ipv6_only : 1; -} server_port_cfg_t; +typedef struct entry_port_cfg_t entry_port_cfg_t; +typedef struct server_port_cfg_t server_port_cfg_t; /* Values for connection_t.magic: used to make sure that downcasts (casts from * connection_t to foo_connection_t) are safe. */ @@ -1303,139 +1204,6 @@ typedef struct server_port_cfg_t { #define CONTROL_CONNECTION_MAGIC 0x8abc765du #define LISTENER_CONNECTION_MAGIC 0x1a1ac741u -struct buf_t; - -/** Description of a connection to another host or process, and associated - * data. - * - * A connection is named based on what it's connected to -- an "OR - * connection" has a Tor node on the other end, an "exit - * connection" has a website or other server on the other end, and an - * "AP connection" has an application proxy (and thus a user) on the - * other end. - * - * Every connection has a type and a state. Connections never change - * their type, but can go through many state changes in their lifetime. - * - * Every connection has two associated input and output buffers. - * Listeners don't use them. For non-listener connections, incoming - * data is appended to conn->inbuf, and outgoing data is taken from - * conn->outbuf. Connections differ primarily in the functions called - * to fill and drain these buffers. - */ -typedef struct connection_t { - uint32_t magic; /**< For memory debugging: must equal one of - * *_CONNECTION_MAGIC. */ - - uint8_t state; /**< Current state of this connection. */ - unsigned int type:5; /**< What kind of connection is this? */ - unsigned int purpose:5; /**< Only used for DIR and EXIT types currently. */ - - /* The next fields are all one-bit booleans. Some are only applicable to - * connection subtypes, but we hold them here anyway, to save space. - */ - unsigned int read_blocked_on_bw:1; /**< Boolean: should we start reading - * again once the bandwidth throttler allows it? */ - unsigned int write_blocked_on_bw:1; /**< Boolean: should we start writing - * again once the bandwidth throttler allows - * writes? */ - unsigned int hold_open_until_flushed:1; /**< Despite this connection's being - * marked for close, do we flush it - * before closing it? */ - unsigned int inbuf_reached_eof:1; /**< Boolean: did read() return 0 on this - * conn? */ - /** Set to 1 when we're inside connection_flushed_some to keep us from - * calling connection_handle_write() recursively. */ - unsigned int in_flushed_some:1; - /** True if connection_handle_write is currently running on this connection. - */ - unsigned int in_connection_handle_write:1; - - /* For linked connections: - */ - unsigned int linked:1; /**< True if there is, or has been, a linked_conn. */ - /** True iff we'd like to be notified about read events from the - * linked conn. */ - unsigned int reading_from_linked_conn:1; - /** True iff we're willing to write to the linked conn. */ - unsigned int writing_to_linked_conn:1; - /** True iff we're currently able to read on the linked conn, and our - * read_event should be made active with libevent. */ - unsigned int active_on_link:1; - /** True iff we've called connection_close_immediate() on this linked - * connection. */ - unsigned int linked_conn_is_closed:1; - - /** CONNECT/SOCKS proxy client handshake state (for outgoing connections). */ - unsigned int proxy_state:4; - - /** Our socket; set to TOR_INVALID_SOCKET if this connection is closed, - * or has no socket. */ - tor_socket_t s; - int conn_array_index; /**< Index into the global connection array. */ - - struct event *read_event; /**< Libevent event structure. */ - struct event *write_event; /**< Libevent event structure. */ - struct buf_t *inbuf; /**< Buffer holding data read over this connection. */ - struct buf_t *outbuf; /**< Buffer holding data to write over this - * connection. */ - size_t outbuf_flushlen; /**< How much data should we try to flush from the - * outbuf? */ - time_t timestamp_last_read_allowed; /**< When was the last time libevent said - * we could read? */ - time_t timestamp_last_write_allowed; /**< When was the last time libevent - * said we could write? */ - - time_t timestamp_created; /**< When was this connection_t created? */ - - int socket_family; /**< Address family of this connection's socket. Usually - * AF_INET, but it can also be AF_UNIX, or AF_INET6 */ - tor_addr_t addr; /**< IP that socket "s" is directly connected to; - * may be the IP address for a proxy or pluggable transport, - * see "address" for the address of the final destination. - */ - uint16_t port; /**< If non-zero, port that socket "s" is directly connected - * to; may be the port for a proxy or pluggable transport, - * see "address" for the port at the final destination. */ - uint16_t marked_for_close; /**< Should we close this conn on the next - * iteration of the main loop? (If true, holds - * the line number where this connection was - * marked.) */ - const char *marked_for_close_file; /**< For debugging: in which file were - * we marked for close? */ - char *address; /**< FQDN (or IP) and port of the final destination for this - * connection; this is always the remote address, it is - * passed to a proxy or pluggable transport if one in use. - * See "addr" and "port" for the address that socket "s" is - * directly connected to. - * strdup into this, because free_connection() frees it. */ - /** Another connection that's connected to this one in lieu of a socket. */ - struct connection_t *linked_conn; - - /** Unique identifier for this connection on this Tor instance. */ - uint64_t global_identifier; - - /** Bytes read since last call to control_event_conn_bandwidth_used(). - * Only used if we're configured to emit CONN_BW events. */ - uint32_t n_read_conn_bw; - - /** Bytes written since last call to control_event_conn_bandwidth_used(). - * Only used if we're configured to emit CONN_BW events. */ - uint32_t n_written_conn_bw; -} connection_t; - -/** Subtype of connection_t; used for a listener socket. */ -typedef struct listener_connection_t { - connection_t base_; - - /** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points - * to the evdns_server_port it uses to listen to and answer connections. */ - struct evdns_server_port *dns_server_port; - - entry_port_cfg_t entry_cfg; - -} listener_connection_t; - /** Minimum length of the random part of an AUTH_CHALLENGE cell. */ #define OR_AUTH_CHALLENGE_LEN 32 @@ -1495,100 +1263,8 @@ typedef struct listener_connection_t { * signs. */ #define V3_AUTH_BODY_LEN (V3_AUTH_FIXED_PART_LEN + 8 + 16) -/** Structure to hold all the certificates we've received on an OR connection - */ -typedef struct or_handshake_certs_t { - /** True iff we originated this connection. */ - int started_here; - /** The cert for the 'auth' RSA key that's supposed to sign the AUTHENTICATE - * cell. Signed with the RSA identity key. */ - tor_x509_cert_t *auth_cert; - /** The cert for the 'link' RSA key that was used to negotiate the TLS - * connection. Signed with the RSA identity key. */ - tor_x509_cert_t *link_cert; - /** A self-signed identity certificate: the RSA identity key signed - * with itself. */ - tor_x509_cert_t *id_cert; - /** The Ed25519 signing key, signed with the Ed25519 identity key. */ - struct tor_cert_st *ed_id_sign; - /** A digest of the X509 link certificate for the TLS connection, signed - * with the Ed25519 siging key. */ - struct tor_cert_st *ed_sign_link; - /** The Ed25519 authentication key (that's supposed to sign an AUTHENTICATE - * cell) , signed with the Ed25519 siging key. */ - struct tor_cert_st *ed_sign_auth; - /** The Ed25519 identity key, crosssigned with the RSA identity key. */ - uint8_t *ed_rsa_crosscert; - /** The length of <b>ed_rsa_crosscert</b> in bytes */ - size_t ed_rsa_crosscert_len; -} or_handshake_certs_t; - -/** Stores flags and information related to the portion of a v2/v3 Tor OR - * connection handshake that happens after the TLS handshake is finished. - */ -typedef struct or_handshake_state_t { - /** When was the VERSIONS cell sent on this connection? Used to get - * an estimate of the skew in the returning NETINFO reply. */ - time_t sent_versions_at; - /** True iff we originated this connection */ - unsigned int started_here : 1; - /** True iff we have received and processed a VERSIONS cell. */ - unsigned int received_versions : 1; - /** True iff we have received and processed an AUTH_CHALLENGE cell */ - unsigned int received_auth_challenge : 1; - /** True iff we have received and processed a CERTS cell. */ - unsigned int received_certs_cell : 1; - /** True iff we have received and processed an AUTHENTICATE cell */ - unsigned int received_authenticate : 1; - - /* True iff we've received valid authentication to some identity. */ - unsigned int authenticated : 1; - unsigned int authenticated_rsa : 1; - unsigned int authenticated_ed25519 : 1; - - /* True iff we have sent a netinfo cell */ - unsigned int sent_netinfo : 1; - - /** The signing->ed25519 link certificate corresponding to the x509 - * certificate we used on the TLS connection (if this is a server-side - * connection). We make a copy of this here to prevent a race condition - * caused by TLS context rotation. */ - struct tor_cert_st *own_link_cert; - - /** True iff we should feed outgoing cells into digest_sent and - * digest_received respectively. - * - * From the server's side of the v3 handshake, we want to capture everything - * from the VERSIONS cell through and including the AUTH_CHALLENGE cell. - * From the client's, we want to capture everything from the VERSIONS cell - * through but *not* including the AUTHENTICATE cell. - * - * @{ */ - unsigned int digest_sent_data : 1; - unsigned int digest_received_data : 1; - /**@}*/ - - /** Identity RSA digest that we have received and authenticated for our peer - * on this connection. */ - uint8_t authenticated_rsa_peer_id[DIGEST_LEN]; - /** Identity Ed25519 public key that we have received and authenticated for - * our peer on this connection. */ - ed25519_public_key_t authenticated_ed25519_peer_id; - - /** Digests of the cells that we have sent or received as part of a V3 - * handshake. Used for making and checking AUTHENTICATE cells. - * - * @{ - */ - crypto_digest_t *digest_sent; - crypto_digest_t *digest_received; - /** @} */ - - /** Certificates that a connection initiator sent us in a CERTS cell; we're - * holding on to them until we get an AUTHENTICATE cell. - */ - or_handshake_certs_t *certs; -} or_handshake_state_t; +typedef struct or_handshake_certs_t or_handshake_certs_t; +typedef struct or_handshake_state_t or_handshake_state_t; /** Length of Extended ORPort connection identifier. */ #define EXT_OR_CONN_ID_LEN DIGEST_LEN /* 20 */ @@ -1605,381 +1281,20 @@ typedef struct or_handshake_state_t { * drops below this size. */ #define OR_CONN_LOWWATER (16*1024) -/** Subtype of connection_t for an "OR connection" -- that is, one that speaks - * cells over TLS. */ -typedef struct or_connection_t { - connection_t base_; - - /** Hash of the public RSA key for the other side's identity key, or zeroes - * if the other side hasn't shown us a valid identity key. */ - char identity_digest[DIGEST_LEN]; - - /** Extended ORPort connection identifier. */ - char *ext_or_conn_id; - /** This is the ClientHash value we expect to receive from the - * client during the Extended ORPort authentication protocol. We - * compute it upon receiving the ClientNoce from the client, and we - * compare it with the acual ClientHash value sent by the - * client. */ - char *ext_or_auth_correct_client_hash; - /** String carrying the name of the pluggable transport - * (e.g. "obfs2") that is obfuscating this connection. If no - * pluggable transports are used, it's NULL. */ - char *ext_or_transport; - - char *nickname; /**< Nickname of OR on other side (if any). */ - - tor_tls_t *tls; /**< TLS connection state. */ - int tls_error; /**< Last tor_tls error code. */ - /** When we last used this conn for any client traffic. If not - * recent, we can rate limit it further. */ - - /* Channel using this connection */ - channel_tls_t *chan; - - tor_addr_t real_addr; /**< The actual address that this connection came from - * or went to. The <b>addr</b> field is prone to - * getting overridden by the address from the router - * descriptor matching <b>identity_digest</b>. */ - - /** Should this connection be used for extending circuits to the server - * matching the <b>identity_digest</b> field? Set to true if we're pretty - * sure we aren't getting MITMed, either because we're connected to an - * address listed in a server descriptor, or because an authenticated - * NETINFO cell listed the address we're connected to as recognized. */ - unsigned int is_canonical:1; - - /** True iff this is an outgoing connection. */ - unsigned int is_outgoing:1; - unsigned int proxy_type:2; /**< One of PROXY_NONE...PROXY_SOCKS5 */ - unsigned int wide_circ_ids:1; - /** True iff this connection has had its bootstrap failure logged with - * control_event_bootstrap_problem. */ - unsigned int have_noted_bootstrap_problem:1; - /** True iff this is a client connection and its address has been put in the - * geoip cache and handled by the DoS mitigation subsystem. We use this to - * insure we have a coherent count of concurrent connection. */ - unsigned int tracked_for_dos_mitigation : 1; - - uint16_t link_proto; /**< What protocol version are we using? 0 for - * "none negotiated yet." */ - uint16_t idle_timeout; /**< How long can this connection sit with no - * circuits on it before we close it? Based on - * IDLE_CIRCUIT_TIMEOUT_{NON,}CANONICAL and - * on is_canonical, randomized. */ - or_handshake_state_t *handshake_state; /**< If we are setting this connection - * up, state information to do so. */ - - time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/ - - token_bucket_rw_t bucket; /**< Used for rate limiting when the connection is - * in state CONN_OPEN. */ - - /* - * Count the number of bytes flushed out on this orconn, and the number of - * bytes TLS actually sent - used for overhead estimation for scheduling. - */ - uint64_t bytes_xmitted, bytes_xmitted_by_tls; -} or_connection_t; - -/** Subtype of connection_t for an "edge connection" -- that is, an entry (ap) - * connection, or an exit. */ -typedef struct edge_connection_t { - connection_t base_; - - struct edge_connection_t *next_stream; /**< Points to the next stream at this - * edge, if any */ - int package_window; /**< How many more relay cells can I send into the - * circuit? */ - int deliver_window; /**< How many more relay cells can end at me? */ - - struct circuit_t *on_circuit; /**< The circuit (if any) that this edge - * connection is using. */ - - /** A pointer to which node in the circ this conn exits at. Set for AP - * connections and for hidden service exit connections. */ - struct crypt_path_t *cpath_layer; - /** What rendezvous service are we querying for (if an AP) or providing (if - * an exit)? */ - rend_data_t *rend_data; - - /* Hidden service connection identifier for edge connections. Used by the HS - * client-side code to identify client SOCKS connections and by the - * service-side code to match HS circuits with their streams. */ - struct hs_ident_edge_conn_t *hs_ident; - - uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit - * connection. Exit connections only. */ - uint32_t begincell_flags; /** Flags sent or received in the BEGIN cell - * for this connection */ - - streamid_t stream_id; /**< The stream ID used for this edge connection on its - * circuit */ - - /** The reason why this connection is closing; passed to the controller. */ - uint16_t end_reason; - - /** Bytes read since last call to control_event_stream_bandwidth_used() */ - uint32_t n_read; - - /** Bytes written since last call to control_event_stream_bandwidth_used() */ - uint32_t n_written; - - /** True iff this connection is for a DNS request only. */ - unsigned int is_dns_request:1; - /** True iff this connection is for a PTR DNS request. (exit only) */ - unsigned int is_reverse_dns_lookup:1; - - unsigned int edge_has_sent_end:1; /**< For debugging; only used on edge - * connections. Set once we've set the stream end, - * and check in connection_about_to_close_connection(). - */ - /** True iff we've blocked reading until the circuit has fewer queued - * cells. */ - unsigned int edge_blocked_on_circ:1; - - /** Unique ID for directory requests; this used to be in connection_t, but - * that's going away and being used on channels instead. We still tag - * edge connections with dirreq_id from circuits, so it's copied here. */ - uint64_t dirreq_id; -} edge_connection_t; - -/** Subtype of edge_connection_t for an "entry connection" -- that is, a SOCKS - * connection, a DNS request, a TransPort connection or a NATD connection */ -typedef struct entry_connection_t { - edge_connection_t edge_; - - /** Nickname of planned exit node -- used with .exit support. */ - /* XXX prop220: we need to make chosen_exit_name able to encode Ed IDs too. - * That's logically part of the UI parts for prop220 though. */ - char *chosen_exit_name; - - socks_request_t *socks_request; /**< SOCKS structure describing request (AP - * only.) */ - - /* === Isolation related, AP only. === */ - entry_port_cfg_t entry_cfg; - /** AP only: The newnym epoch in which we created this connection. */ - unsigned nym_epoch; - - /** AP only: The original requested address before we rewrote it. */ - char *original_dest_address; - /* Other fields to isolate on already exist. The ClientAddr is addr. The - ClientProtocol is a combination of type and socks_request-> - socks_version. SocksAuth is socks_request->username/password. - DestAddr is in socks_request->address. */ - - /** Number of times we've reassigned this application connection to - * a new circuit. We keep track because the timeout is longer if we've - * already retried several times. */ - uint8_t num_socks_retries; - - /** For AP connections only: buffer for data that we have sent - * optimistically, which we might need to re-send if we have to - * retry this connection. */ - struct buf_t *pending_optimistic_data; - /* For AP connections only: buffer for data that we previously sent - * optimistically which we are currently re-sending as we retry this - * connection. */ - struct buf_t *sending_optimistic_data; - - /** If this is a DNSPort connection, this field holds the pending DNS - * request that we're going to try to answer. */ - struct evdns_server_request *dns_server_request; - -#define DEBUGGING_17659 - -#ifdef DEBUGGING_17659 - uint16_t marked_pending_circ_line; - const char *marked_pending_circ_file; -#endif - -#define NUM_CIRCUITS_LAUNCHED_THRESHOLD 10 - /** Number of times we've launched a circuit to handle this stream. If - * it gets too high, that could indicate an inconsistency between our - * "launch a circuit to handle this stream" logic and our "attach our - * stream to one of the available circuits" logic. */ - unsigned int num_circuits_launched:4; - - /** True iff this stream must attach to a one-hop circuit (e.g. for - * begin_dir). */ - unsigned int want_onehop:1; - /** True iff this stream should use a BEGIN_DIR relay command to establish - * itself rather than BEGIN (either via onehop or via a whole circuit). */ - unsigned int use_begindir:1; - - /** For AP connections only. If 1, and we fail to reach the chosen exit, - * stop requiring it. */ - unsigned int chosen_exit_optional:1; - /** For AP connections only. If non-zero, this exit node was picked as - * a result of the TrackHostExit, and the value decrements every time - * we fail to complete a circuit to our chosen exit -- if it reaches - * zero, abandon the associated mapaddress. */ - unsigned int chosen_exit_retries:3; - - /** True iff this is an AP connection that came from a transparent or - * NATd connection */ - unsigned int is_transparent_ap:1; - - /** For AP connections only: Set if this connection's target exit node - * allows optimistic data (that is, data sent on this stream before - * the exit has sent a CONNECTED cell) and we have chosen to use it. - */ - unsigned int may_use_optimistic_data : 1; -} entry_connection_t; - -/** Subtype of connection_t for an "directory connection" -- that is, an HTTP - * connection to retrieve or serve directory material. */ -typedef struct dir_connection_t { - connection_t base_; - - /** Which 'resource' did we ask the directory for? This is typically the part - * of the URL string that defines, relative to the directory conn purpose, - * what thing we want. For example, in router descriptor downloads by - * descriptor digest, it contains "d/", then one or more +-separated - * fingerprints. - **/ - char *requested_resource; - unsigned int dirconn_direct:1; /**< Is this dirconn direct, or via Tor? */ - - /** If we're fetching descriptors, what router purpose shall we assign - * to them? */ - uint8_t router_purpose; - - /** List of spooled_resource_t for objects that we're spooling. We use - * it from back to front. */ - smartlist_t *spool; - /** The compression object doing on-the-fly compression for spooled data. */ - tor_compress_state_t *compress_state; - - /** What rendezvous service are we querying for? */ - rend_data_t *rend_data; - - /* Hidden service connection identifier for dir connections: Used by HS - client-side code to fetch HS descriptors, and by the service-side code to - upload descriptors. */ - struct hs_ident_dir_conn_t *hs_ident; - - /** If this is a one-hop connection, tracks the state of the directory guard - * for this connection (if any). */ - struct circuit_guard_state_t *guard_state; - - char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for - * the directory server's signing key. */ - - /** Unique ID for directory requests; this used to be in connection_t, but - * that's going away and being used on channels instead. The dirserver still - * needs this for the incoming side, so it's moved here. */ - uint64_t dirreq_id; - -#ifdef MEASUREMENTS_21206 - /** Number of RELAY_DATA cells received. */ - uint32_t data_cells_received; - - /** Number of RELAY_DATA cells sent. */ - uint32_t data_cells_sent; -#endif /* defined(MEASUREMENTS_21206) */ -} dir_connection_t; - -/** Subtype of connection_t for an connection to a controller. */ -typedef struct control_connection_t { - connection_t base_; - - uint64_t event_mask; /**< Bitfield: which events does this controller - * care about? - * EVENT_MAX_ is >31, so we need a 64 bit mask */ - - /** True if we have sent a protocolinfo reply on this connection. */ - unsigned int have_sent_protocolinfo:1; - /** True if we have received a takeownership command on this - * connection. */ - unsigned int is_owning_control_connection:1; - - /** List of ephemeral onion services belonging to this connection. */ - smartlist_t *ephemeral_onion_services; - - /** If we have sent an AUTHCHALLENGE reply on this connection and - * have not received a successful AUTHENTICATE command, points to - * the value which the client must send to authenticate itself; - * otherwise, NULL. */ - char *safecookie_client_hash; - - /** Amount of space allocated in incoming_cmd. */ - uint32_t incoming_cmd_len; - /** Number of bytes currently stored in incoming_cmd. */ - uint32_t incoming_cmd_cur_len; - /** A control command that we're reading from the inbuf, but which has not - * yet arrived completely. */ - char *incoming_cmd; -} control_connection_t; +typedef struct connection_t connection_t; +typedef struct control_connection_t control_connection_t; +typedef struct dir_connection_t dir_connection_t; +typedef struct edge_connection_t edge_connection_t; +typedef struct entry_connection_t entry_connection_t; +typedef struct listener_connection_t listener_connection_t; +typedef struct or_connection_t or_connection_t; /** Cast a connection_t subtype pointer to a connection_t **/ #define TO_CONN(c) (&(((c)->base_))) -/** Cast a entry_connection_t subtype pointer to a edge_connection_t **/ -#define ENTRY_TO_EDGE_CONN(c) (&(((c))->edge_)) /** Cast a entry_connection_t subtype pointer to a connection_t **/ #define ENTRY_TO_CONN(c) (TO_CONN(ENTRY_TO_EDGE_CONN(c))) -/** Convert a connection_t* to an or_connection_t*; assert if the cast is - * invalid. */ -static or_connection_t *TO_OR_CONN(connection_t *); -/** Convert a connection_t* to a dir_connection_t*; assert if the cast is - * invalid. */ -static dir_connection_t *TO_DIR_CONN(connection_t *); -/** Convert a connection_t* to an edge_connection_t*; assert if the cast is - * invalid. */ -static edge_connection_t *TO_EDGE_CONN(connection_t *); -/** Convert a connection_t* to an entry_connection_t*; assert if the cast is - * invalid. */ -static entry_connection_t *TO_ENTRY_CONN(connection_t *); -/** Convert a edge_connection_t* to an entry_connection_t*; assert if the cast - * is invalid. */ -static entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *); -/** Convert a connection_t* to an control_connection_t*; assert if the cast is - * invalid. */ -static control_connection_t *TO_CONTROL_CONN(connection_t *); -/** Convert a connection_t* to an listener_connection_t*; assert if the cast is - * invalid. */ -static listener_connection_t *TO_LISTENER_CONN(connection_t *); - -static inline or_connection_t *TO_OR_CONN(connection_t *c) -{ - tor_assert(c->magic == OR_CONNECTION_MAGIC); - return DOWNCAST(or_connection_t, c); -} -static inline dir_connection_t *TO_DIR_CONN(connection_t *c) -{ - tor_assert(c->magic == DIR_CONNECTION_MAGIC); - return DOWNCAST(dir_connection_t, c); -} -static inline edge_connection_t *TO_EDGE_CONN(connection_t *c) -{ - tor_assert(c->magic == EDGE_CONNECTION_MAGIC || - c->magic == ENTRY_CONNECTION_MAGIC); - return DOWNCAST(edge_connection_t, c); -} -static inline entry_connection_t *TO_ENTRY_CONN(connection_t *c) -{ - tor_assert(c->magic == ENTRY_CONNECTION_MAGIC); - return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_.base_); -} -static inline entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *c) -{ - tor_assert(c->base_.magic == ENTRY_CONNECTION_MAGIC); - return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_); -} -static inline control_connection_t *TO_CONTROL_CONN(connection_t *c) -{ - tor_assert(c->magic == CONTROL_CONNECTION_MAGIC); - return DOWNCAST(control_connection_t, c); -} -static inline listener_connection_t *TO_LISTENER_CONN(connection_t *c) -{ - tor_assert(c->magic == LISTENER_CONNECTION_MAGIC); - return DOWNCAST(listener_connection_t, c); -} - /** What action type does an address policy indicate: accept or reject? */ typedef enum { ADDR_POLICY_ACCEPT=1, @@ -2013,19 +1328,7 @@ typedef struct addr_policy_t { uint16_t prt_max; /**< Highest port number to accept/reject. */ } addr_policy_t; -/** A cached_dir_t represents a cacheable directory object, along with its - * compressed form. */ -typedef struct cached_dir_t { - char *dir; /**< Contents of this object, NUL-terminated. */ - char *dir_compressed; /**< Compressed contents of this object. */ - size_t dir_len; /**< Length of <b>dir</b> (not counting its NUL). */ - size_t dir_compressed_len; /**< Length of <b>dir_compressed</b>. */ - time_t published; /**< When was this object published. */ - common_digests_t digests; /**< Digests of this object (networkstatus only) */ - /** Sha3 digest (also ns only) */ - uint8_t digest_sha3_as_signed[DIGEST256_LEN]; - int refcnt; /**< Reference count for this cached_dir_t. */ -} cached_dir_t; +typedef struct cached_dir_t cached_dir_t; /** Enum used to remember where a signed_descriptor_t is stored and how to * manage the memory for signed_descriptor_body. */ @@ -2078,59 +1381,7 @@ typedef enum { #define download_schedule_increment_bitfield_t \ ENUM_BF(download_schedule_increment_t) -/** Information about our plans for retrying downloads for a downloadable - * directory object. - * Each type of downloadable directory object has a corresponding retry - * <b>schedule</b>, which can be different depending on whether the object is - * being downloaded from an authority or a mirror (<b>want_authority</b>). - * <b>next_attempt_at</b> contains the next time we will attempt to download - * the object. - * For schedules that <b>increment_on</b> failure, <b>n_download_failures</b> - * is used to determine the position in the schedule. (Each schedule is a - * smartlist of integer delays, parsed from a CSV option.) Every time a - * connection attempt fails, <b>n_download_failures</b> is incremented, - * the new delay value is looked up from the schedule, and - * <b>next_attempt_at</b> is set delay seconds from the time the previous - * connection failed. Therefore, at most one failure-based connection can be - * in progress for each download_status_t. - * For schedules that <b>increment_on</b> attempt, <b>n_download_attempts</b> - * is used to determine the position in the schedule. Every time a - * connection attempt is made, <b>n_download_attempts</b> is incremented, - * the new delay value is looked up from the schedule, and - * <b>next_attempt_at</b> is set delay seconds from the time the previous - * connection was attempted. Therefore, multiple concurrent attempted-based - * connections can be in progress for each download_status_t. - * After an object is successfully downloaded, any other concurrent connections - * are terminated. A new schedule which starts at position 0 is used for - * subsequent downloads of the same object. - */ -typedef struct download_status_t { - time_t next_attempt_at; /**< When should we try downloading this object - * again? */ - uint8_t n_download_failures; /**< Number of failed downloads of the most - * recent object, since the last success. */ - uint8_t n_download_attempts; /**< Number of (potentially concurrent) attempts - * to download the most recent object, since - * the last success. */ - download_schedule_bitfield_t schedule : 8; /**< What kind of object is being - * downloaded? This determines the - * schedule used for the download. - */ - download_want_authority_bitfield_t want_authority : 1; /**< Is the download - * happening from an authority - * or a mirror? This determines - * the schedule used for the - * download. */ - download_schedule_increment_bitfield_t increment_on : 1; /**< does this - * schedule increment on each attempt, - * or after each failure? */ - uint8_t last_backoff_position; /**< number of attempts/failures, depending - * on increment_on, when we last recalculated - * the delay. Only updated if backoff - * == 1. */ - int last_delay_used; /**< last delay used for random exponential backoff; - * only updated if backoff == 1 */ -} download_status_t; +typedef struct download_status_t download_status_t; /** If n_download_failures is this high, the download can never happen. */ #define IMPOSSIBLE_TO_DOWNLOAD 255 @@ -2140,53 +1391,7 @@ typedef struct download_status_t { * create any that are larger than this. */ #define ROUTER_ANNOTATION_BUF_LEN 256 -/** Information need to cache an onion router's descriptor. */ -typedef struct signed_descriptor_t { - /** Pointer to the raw server descriptor, preceded by annotations. Not - * necessarily NUL-terminated. If saved_location is SAVED_IN_CACHE, this - * pointer is null. */ - char *signed_descriptor_body; - /** Length of the annotations preceding the server descriptor. */ - size_t annotations_len; - /** Length of the server descriptor. */ - size_t signed_descriptor_len; - /** Digest of the server descriptor, computed as specified in - * dir-spec.txt. */ - char signed_descriptor_digest[DIGEST_LEN]; - /** Identity digest of the router. */ - char identity_digest[DIGEST_LEN]; - /** Declared publication time of the descriptor. */ - time_t published_on; - /** For routerdescs only: digest of the corresponding extrainfo. */ - char extra_info_digest[DIGEST_LEN]; - /** For routerdescs only: A SHA256-digest of the extrainfo (if any) */ - char extra_info_digest256[DIGEST256_LEN]; - /** Certificate for ed25519 signing key. */ - struct tor_cert_st *signing_key_cert; - /** For routerdescs only: Status of downloading the corresponding - * extrainfo. */ - download_status_t ei_dl_status; - /** Where is the descriptor saved? */ - saved_location_t saved_location; - /** If saved_location is SAVED_IN_CACHE or SAVED_IN_JOURNAL, the offset of - * this descriptor in the corresponding file. */ - off_t saved_offset; - /** What position is this descriptor within routerlist->routers or - * routerlist->old_routers? -1 for none. */ - int routerlist_index; - /** The valid-until time of the most recent consensus that listed this - * descriptor. 0 for "never listed in a consensus, so far as we know." */ - time_t last_listed_as_valid_until; - /* If true, we do not ever try to save this object in the cache. */ - unsigned int do_not_cache : 1; - /* If true, this item is meant to represent an extrainfo. */ - unsigned int is_extrainfo : 1; - /* If true, we got an extrainfo for this item, and the digest was right, - * but it was incompatible. */ - unsigned int extrainfo_is_bogus : 1; - /* If true, we are willing to transmit this item unencrypted. */ - unsigned int send_unencrypted : 1; -} signed_descriptor_t; +typedef struct signed_descriptor_t signed_descriptor_t; /** A signed integer representing a country code. */ typedef int16_t country_t; @@ -2228,183 +1433,9 @@ typedef struct protover_summary_flags_t { unsigned int supports_v3_rendezvous_point: 1; } protover_summary_flags_t; -/** Information about another onion router in the network. */ -typedef struct { - signed_descriptor_t cache_info; - char *nickname; /**< Human-readable OR name. */ - - uint32_t addr; /**< IPv4 address of OR, in host order. */ - uint16_t or_port; /**< Port for TLS connections. */ - uint16_t dir_port; /**< Port for HTTP directory connections. */ - - /** A router's IPv6 address, if it has one. */ - /* XXXXX187 Actually these should probably be part of a list of addresses, - * not just a special case. Use abstractions to access these; don't do it - * directly. */ - tor_addr_t ipv6_addr; - uint16_t ipv6_orport; - - crypto_pk_t *onion_pkey; /**< Public RSA key for onions. */ - crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */ - /** Public curve25519 key for onions */ - curve25519_public_key_t *onion_curve25519_pkey; - /** What's the earliest expiration time on all the certs in this - * routerinfo? */ - time_t cert_expiration_time; - - char *platform; /**< What software/operating system is this OR using? */ - - char *protocol_list; /**< Encoded list of subprotocol versions supported - * by this OR */ - - /* link info */ - uint32_t bandwidthrate; /**< How many bytes does this OR add to its token - * bucket per second? */ - uint32_t bandwidthburst; /**< How large is this OR's token bucket? */ - /** How many bytes/s is this router known to handle? */ - uint32_t bandwidthcapacity; - smartlist_t *exit_policy; /**< What streams will this OR permit - * to exit on IPv4? NULL for 'reject *:*'. */ - /** What streams will this OR permit to exit on IPv6? - * NULL for 'reject *:*' */ - struct short_policy_t *ipv6_exit_policy; - long uptime; /**< How many seconds the router claims to have been up */ - smartlist_t *declared_family; /**< Nicknames of router which this router - * claims are its family. */ - char *contact_info; /**< Declared contact info for this router. */ - unsigned int is_hibernating:1; /**< Whether the router claims to be - * hibernating */ - unsigned int caches_extra_info:1; /**< Whether the router says it caches and - * serves extrainfo documents. */ - unsigned int allow_single_hop_exits:1; /**< Whether the router says - * it allows single hop exits. */ - - unsigned int wants_to_be_hs_dir:1; /**< True iff this router claims to be - * a hidden service directory. */ - unsigned int policy_is_reject_star:1; /**< True iff the exit policy for this - * router rejects everything. */ - /** True if, after we have added this router, we should re-launch - * tests for it. */ - unsigned int needs_retest_if_added:1; - - /** True iff this router included "tunnelled-dir-server" in its descriptor, - * implying it accepts tunnelled directory requests, or it advertised - * dir_port > 0. */ - unsigned int supports_tunnelled_dir_requests:1; - - /** Used during voting to indicate that we should not include an entry for - * this routerinfo. Used only during voting. */ - unsigned int omit_from_vote:1; - - /** Flags to summarize the protocol versions for this routerinfo_t. */ - protover_summary_flags_t pv; - -/** Tor can use this router for general positions in circuits; we got it - * from a directory server as usual, or we're an authority and a server - * uploaded it. */ -#define ROUTER_PURPOSE_GENERAL 0 -/** Tor should avoid using this router for circuit-building: we got it - * from a controller. If the controller wants to use it, it'll have to - * ask for it by identity. */ -#define ROUTER_PURPOSE_CONTROLLER 1 -/** Tor should use this router only for bridge positions in circuits: we got - * it via a directory request from the bridge itself, or a bridge - * authority. */ -#define ROUTER_PURPOSE_BRIDGE 2 -/** Tor should not use this router; it was marked in cached-descriptors with - * a purpose we didn't recognize. */ -#define ROUTER_PURPOSE_UNKNOWN 255 - - /** In what way did we find out about this router? One of ROUTER_PURPOSE_*. - * Routers of different purposes are kept segregated and used for different - * things; see notes on ROUTER_PURPOSE_* macros above. - */ - uint8_t purpose; -} routerinfo_t; - -/** Information needed to keep and cache a signed extra-info document. */ -typedef struct extrainfo_t { - signed_descriptor_t cache_info; - /** SHA256 digest of this document */ - uint8_t digest256[DIGEST256_LEN]; - /** The router's nickname. */ - char nickname[MAX_NICKNAME_LEN+1]; - /** True iff we found the right key for this extra-info, verified the - * signature, and found it to be bad. */ - unsigned int bad_sig : 1; - /** If present, we didn't have the right key to verify this extra-info, - * so this is a copy of the signature in the document. */ - char *pending_sig; - /** Length of pending_sig. */ - size_t pending_sig_len; -} extrainfo_t; - -/** Contents of a single router entry in a network status object. - */ -typedef struct routerstatus_t { - time_t published_on; /**< When was this router published? */ - char nickname[MAX_NICKNAME_LEN+1]; /**< The nickname this router says it - * has. */ - char identity_digest[DIGEST_LEN]; /**< Digest of the router's identity - * key. */ - /** Digest of the router's most recent descriptor or microdescriptor. - * If it's a descriptor, we only use the first DIGEST_LEN bytes. */ - char descriptor_digest[DIGEST256_LEN]; - uint32_t addr; /**< IPv4 address for this router, in host order. */ - uint16_t or_port; /**< IPv4 OR port for this router. */ - uint16_t dir_port; /**< Directory port for this router. */ - tor_addr_t ipv6_addr; /**< IPv6 address for this router. */ - uint16_t ipv6_orport; /**< IPv6 OR port for this router. */ - unsigned int is_authority:1; /**< True iff this router is an authority. */ - unsigned int is_exit:1; /**< True iff this router is a good exit. */ - unsigned int is_stable:1; /**< True iff this router stays up a long time. */ - unsigned int is_fast:1; /**< True iff this router has good bandwidth. */ - /** True iff this router is called 'running' in the consensus. We give it - * this funny name so that we don't accidentally use this bit as a view of - * whether we think the router is *currently* running. If that's what you - * want to know, look at is_running in node_t. */ - unsigned int is_flagged_running:1; - unsigned int is_named:1; /**< True iff "nickname" belongs to this router. */ - unsigned int is_unnamed:1; /**< True iff "nickname" belongs to another - * router. */ - unsigned int is_valid:1; /**< True iff this router isn't invalid. */ - unsigned int is_possible_guard:1; /**< True iff this router would be a good - * choice as an entry guard. */ - unsigned int is_bad_exit:1; /**< True iff this node is a bad choice for - * an exit node. */ - unsigned int is_hs_dir:1; /**< True iff this router is a v2-or-later hidden - * service directory. */ - unsigned int is_v2_dir:1; /** True iff this router publishes an open DirPort - * or it claims to accept tunnelled dir requests. - */ - - unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */ - unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */ - unsigned int bw_is_unmeasured:1; /**< This is a consensus entry, with - * the Unmeasured flag set. */ - - /** Flags to summarize the protocol versions for this routerstatus_t. */ - protover_summary_flags_t pv; - - uint32_t bandwidth_kb; /**< Bandwidth (capacity) of the router as reported in - * the vote/consensus, in kilobytes/sec. */ - - /** The consensus has guardfraction information for this router. */ - unsigned int has_guardfraction:1; - /** The guardfraction value of this router. */ - uint32_t guardfraction_percentage; - - char *exitsummary; /**< exit policy summary - - * XXX weasel: this probably should not stay a string. */ - - /* ---- The fields below aren't derived from the networkstatus; they - * hold local information only. */ - - time_t last_dir_503_at; /**< When did this router last tell us that it - * was too busy to serve directory info? */ - download_status_t dl_status; - -} routerstatus_t; +typedef struct routerinfo_t routerinfo_t; +typedef struct extrainfo_t extrainfo_t; +typedef struct routerstatus_t routerstatus_t; /** A single entry in a parsed policy summary, describing a range of ports. */ typedef struct short_policy_entry_t { @@ -2425,244 +1456,13 @@ typedef struct short_policy_t { short_policy_entry_t entries[FLEXIBLE_ARRAY_MEMBER]; } short_policy_t; -/** A microdescriptor is the smallest amount of information needed to build a - * circuit through a router. They are generated by the directory authorities, - * using information from the uploaded routerinfo documents. They are not - * self-signed, but are rather authenticated by having their hash in a signed - * networkstatus document. */ -typedef struct microdesc_t { - /** Hashtable node, used to look up the microdesc by its digest. */ - HT_ENTRY(microdesc_t) node; - - /* Cache information */ - - /** When was this microdescriptor last listed in a consensus document? - * Once a microdesc has been unlisted long enough, we can drop it. - */ - time_t last_listed; - /** Where is this microdescriptor currently stored? */ - saved_location_bitfield_t saved_location : 3; - /** If true, do not attempt to cache this microdescriptor on disk. */ - unsigned int no_save : 1; - /** If true, this microdesc has an entry in the microdesc_map */ - unsigned int held_in_map : 1; - /** Reference count: how many node_ts have a reference to this microdesc? */ - unsigned int held_by_nodes; - - /** If saved_location == SAVED_IN_CACHE, this field holds the offset of the - * microdescriptor in the cache. */ - off_t off; - - /* The string containing the microdesc. */ - - /** A pointer to the encoded body of the microdescriptor. If the - * saved_location is SAVED_IN_CACHE, then the body is a pointer into an - * mmap'd region. Otherwise, it is a malloc'd string. The string might not - * be NUL-terminated; take the length from <b>bodylen</b>. */ - char *body; - /** The length of the microdescriptor in <b>body</b>. */ - size_t bodylen; - /** A SHA256-digest of the microdescriptor. */ - char digest[DIGEST256_LEN]; - - /* Fields in the microdescriptor. */ - - /** As routerinfo_t.onion_pkey */ - crypto_pk_t *onion_pkey; - /** As routerinfo_t.onion_curve25519_pkey */ - curve25519_public_key_t *onion_curve25519_pkey; - /** Ed25519 identity key, if included. */ - ed25519_public_key_t *ed25519_identity_pkey; - /** As routerinfo_t.ipv6_addr */ - tor_addr_t ipv6_addr; - /** As routerinfo_t.ipv6_orport */ - uint16_t ipv6_orport; - /** As routerinfo_t.family */ - smartlist_t *family; - /** IPv4 exit policy summary */ - short_policy_t *exit_policy; - /** IPv6 exit policy summary */ - short_policy_t *ipv6_exit_policy; - -} microdesc_t; - -/** A node_t represents a Tor router. - * - * Specifically, a node_t is a Tor router as we are using it: a router that - * we are considering for circuits, connections, and so on. A node_t is a - * thin wrapper around the routerstatus, routerinfo, and microdesc for a - * single router, and provides a consistent interface for all of them. - * - * Also, a node_t has mutable state. While a routerinfo, a routerstatus, - * and a microdesc have[*] only the information read from a router - * descriptor, a consensus entry, and a microdescriptor (respectively)... - * a node_t has flags based on *our own current opinion* of the node. - * - * [*] Actually, there is some leftover information in each that is mutable. - * We should try to excise that. - */ -typedef struct node_t { - /* Indexing information */ - - /** Used to look up the node_t by its identity digest. */ - HT_ENTRY(node_t) ht_ent; - /** Used to look up the node_t by its ed25519 identity digest. */ - HT_ENTRY(node_t) ed_ht_ent; - /** Position of the node within the list of nodes */ - int nodelist_idx; - - /** The identity digest of this node_t. No more than one node_t per - * identity may exist at a time. */ - char identity[DIGEST_LEN]; - - /** The ed25519 identity of this node_t. This field is nonzero iff we - * currently have an ed25519 identity for this node in either md or ri, - * _and_ this node has been inserted to the ed25519-to-node map in the - * nodelist. - */ - ed25519_public_key_t ed25519_id; - - microdesc_t *md; - routerinfo_t *ri; - routerstatus_t *rs; - - /* local info: copied from routerstatus, then possibly frobbed based - * on experience. Authorities set this stuff directly. Note that - * these reflect knowledge of the primary (IPv4) OR port only. */ - - unsigned int is_running:1; /**< As far as we know, is this OR currently - * running? */ - unsigned int is_valid:1; /**< Has a trusted dirserver validated this OR? - * (For Authdir: Have we validated this OR?) */ - unsigned int is_fast:1; /** Do we think this is a fast OR? */ - unsigned int is_stable:1; /** Do we think this is a stable OR? */ - unsigned int is_possible_guard:1; /**< Do we think this is an OK guard? */ - unsigned int is_exit:1; /**< Do we think this is an OK exit? */ - unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked, - * or otherwise nasty? */ - unsigned int is_hs_dir:1; /**< True iff this router is a hidden service - * directory according to the authorities. */ - - /* Local info: warning state. */ - - unsigned int name_lookup_warned:1; /**< Have we warned the user for referring - * to this (unnamed) router by nickname? - */ - - /** Local info: we treat this node as if it rejects everything */ - unsigned int rejects_all:1; - - /* Local info: derived. */ - - /** True if the IPv6 OR port is preferred over the IPv4 OR port. - * XX/teor - can this become out of date if the torrc changes? */ - unsigned int ipv6_preferred:1; - - /** According to the geoip db what country is this router in? */ - /* XXXprop186 what is this suppose to mean with multiple OR ports? */ - country_t country; - - /* The below items are used only by authdirservers for - * reachability testing. */ - - /** When was the last time we could reach this OR? */ - time_t last_reachable; /* IPv4. */ - time_t last_reachable6; /* IPv6. */ - - /* Hidden service directory index data. This is used by a service or client - * in order to know what's the hs directory index for this node at the time - * the consensus is set. */ - struct hsdir_index_t hsdir_index; -} node_t; - -/** Linked list of microdesc hash lines for a single router in a directory - * vote. - */ -typedef struct vote_microdesc_hash_t { - /** Next element in the list, or NULL. */ - struct vote_microdesc_hash_t *next; - /** The raw contents of the microdesc hash line, from the "m" through the - * newline. */ - char *microdesc_hash_line; -} vote_microdesc_hash_t; - -/** The claim about a single router, made in a vote. */ -typedef struct vote_routerstatus_t { - routerstatus_t status; /**< Underlying 'status' object for this router. - * Flags are redundant. */ - /** How many known-flags are allowed in a vote? This is the width of - * the flags field of vote_routerstatus_t */ -#define MAX_KNOWN_FLAGS_IN_VOTE 64 - uint64_t flags; /**< Bit-field for all recognized flags; index into - * networkstatus_t.known_flags. */ - char *version; /**< The version that the authority says this router is - * running. */ - char *protocols; /**< The protocols that this authority says this router - * provides. */ - unsigned int has_measured_bw:1; /**< The vote had a measured bw */ - /** True iff the vote included an entry for ed25519 ID, or included - * "id ed25519 none" to indicate that there was no ed25519 ID. */ - unsigned int has_ed25519_listing:1; - /** True if the Ed25519 listing here is the consensus-opinion for the - * Ed25519 listing; false if there was no consensus on Ed25519 key status, - * or if this VRS doesn't reflect it. */ - unsigned int ed25519_reflects_consensus:1; - uint32_t measured_bw_kb; /**< Measured bandwidth (capacity) of the router */ - /** The hash or hashes that the authority claims this microdesc has. */ - vote_microdesc_hash_t *microdesc; - /** Ed25519 identity for this router, or zero if it has none. */ - uint8_t ed25519_id[ED25519_PUBKEY_LEN]; -} vote_routerstatus_t; - -/** A signature of some document by an authority. */ -typedef struct document_signature_t { - /** Declared SHA-1 digest of this voter's identity key */ - char identity_digest[DIGEST_LEN]; - /** Declared SHA-1 digest of signing key used by this voter. */ - char signing_key_digest[DIGEST_LEN]; - /** Algorithm used to compute the digest of the document. */ - digest_algorithm_t alg; - /** Signature of the signed thing. */ - char *signature; - /** Length of <b>signature</b> */ - int signature_len; - unsigned int bad_signature : 1; /**< Set to true if we've tried to verify - * the sig, and we know it's bad. */ - unsigned int good_signature : 1; /**< Set to true if we've verified the sig - * as good. */ -} document_signature_t; - -/** Information about a single voter in a vote or a consensus. */ -typedef struct networkstatus_voter_info_t { - /** Declared SHA-1 digest of this voter's identity key */ - char identity_digest[DIGEST_LEN]; - char *nickname; /**< Nickname of this voter */ - /** Digest of this voter's "legacy" identity key, if any. In vote only; for - * consensuses, we treat legacy keys as additional signers. */ - char legacy_id_digest[DIGEST_LEN]; - char *address; /**< Address of this voter, in string format. */ - uint32_t addr; /**< Address of this voter, in IPv4, in host order. */ - uint16_t dir_port; /**< Directory port of this voter */ - uint16_t or_port; /**< OR port of this voter */ - char *contact; /**< Contact information for this voter. */ - char vote_digest[DIGEST_LEN]; /**< Digest of this voter's vote, as signed. */ - - /* Nothing from here on is signed. */ - /** The signature of the document and the signature's status. */ - smartlist_t *sigs; -} networkstatus_voter_info_t; - -typedef struct networkstatus_sr_info_t { - /* Indicate if the dirauth partitipates in the SR protocol with its vote. - * This is tied to the SR flag in the vote. */ - unsigned int participate:1; - /* Both vote and consensus: Current and previous SRV. If list is empty, - * this means none were found in either the consensus or vote. */ - struct sr_srv_t *previous_srv; - struct sr_srv_t *current_srv; - /* Vote only: List of commitments. */ - smartlist_t *commits; -} networkstatus_sr_info_t; +typedef struct microdesc_t microdesc_t; +typedef struct node_t node_t; +typedef struct vote_microdesc_hash_t vote_microdesc_hash_t; +typedef struct vote_routerstatus_t vote_routerstatus_t; +typedef struct document_signature_t document_signature_t; +typedef struct networkstatus_voter_info_t networkstatus_voter_info_t; +typedef struct networkstatus_sr_info_t networkstatus_sr_info_t; /** Enumerates the possible seriousness values of a networkstatus document. */ typedef enum { @@ -2682,98 +1482,8 @@ typedef enum { /** How many different consensus flavors are there? */ #define N_CONSENSUS_FLAVORS ((int)(FLAV_MICRODESC)+1) -/** A common structure to hold a v3 network status vote, or a v3 network - * status consensus. */ -typedef struct networkstatus_t { - networkstatus_type_t type; /**< Vote, consensus, or opinion? */ - consensus_flavor_t flavor; /**< If a consensus, what kind? */ - unsigned int has_measured_bws : 1;/**< True iff this networkstatus contains - * measured= bandwidth values. */ - - time_t published; /**< Vote only: Time when vote was written. */ - time_t valid_after; /**< Time after which this vote or consensus applies. */ - time_t fresh_until; /**< Time before which this is the most recent vote or - * consensus. */ - time_t valid_until; /**< Time after which this vote or consensus should not - * be used. */ - - /** Consensus only: what method was used to produce this consensus? */ - int consensus_method; - /** Vote only: what methods is this voter willing to use? */ - smartlist_t *supported_methods; - - /** List of 'package' lines describing hashes of downloadable packages */ - smartlist_t *package_lines; - - /** How long does this vote/consensus claim that authorities take to - * distribute their votes to one another? */ - int vote_seconds; - /** How long does this vote/consensus claim that authorities take to - * distribute their consensus signatures to one another? */ - int dist_seconds; - - /** Comma-separated list of recommended client software, or NULL if this - * voter has no opinion. */ - char *client_versions; - char *server_versions; - - /** Lists of subprotocol versions which are _recommended_ for relays and - * clients, or which are _require_ for relays and clients. Tor shouldn't - * make any more network connections if a required protocol is missing. - */ - char *recommended_relay_protocols; - char *recommended_client_protocols; - char *required_relay_protocols; - char *required_client_protocols; - - /** List of flags that this vote/consensus applies to routers. If a flag is - * not listed here, the voter has no opinion on what its value should be. */ - smartlist_t *known_flags; - - /** List of key=value strings for the parameters in this vote or - * consensus, sorted by key. */ - smartlist_t *net_params; - - /** List of key=value strings for the bw weight parameters in the - * consensus. */ - smartlist_t *weight_params; - - /** List of networkstatus_voter_info_t. For a vote, only one element - * is included. For a consensus, one element is included for every voter - * whose vote contributed to the consensus. */ - smartlist_t *voters; - - struct authority_cert_t *cert; /**< Vote only: the voter's certificate. */ - - /** Digests of this document, as signed. */ - common_digests_t digests; - /** A SHA3-256 digest of the document, not including signatures: used for - * consensus diffs */ - uint8_t digest_sha3_as_signed[DIGEST256_LEN]; - - /** List of router statuses, sorted by identity digest. For a vote, - * the elements are vote_routerstatus_t; for a consensus, the elements - * are routerstatus_t. */ - smartlist_t *routerstatus_list; - - /** If present, a map from descriptor digest to elements of - * routerstatus_list. */ - digestmap_t *desc_digest_map; - - /** Contains the shared random protocol data from a vote or consensus. */ - networkstatus_sr_info_t sr_info; -} networkstatus_t; - -/** A set of signatures for a networkstatus consensus. Unless otherwise - * noted, all fields are as for networkstatus_t. */ -typedef struct ns_detached_signatures_t { - time_t valid_after; - time_t fresh_until; - time_t valid_until; - strmap_t *digests; /**< Map from flavor name to digestset_t */ - strmap_t *signatures; /**< Map from flavor name to list of - * document_signature_t */ -} ns_detached_signatures_t; +typedef struct networkstatus_t networkstatus_t; +typedef struct ns_detached_signatures_t ns_detached_signatures_t; /** Allowable types of desc_store_t. */ typedef enum store_type_t { @@ -2781,91 +1491,10 @@ typedef enum store_type_t { EXTRAINFO_STORE = 1 } store_type_t; -/** A 'store' is a set of descriptors saved on disk, with accompanying - * journal, mmaped as needed, rebuilt as needed. */ -typedef struct desc_store_t { - /** Filename (within DataDir) for the store. We append .tmp to this - * filename for a temporary file when rebuilding the store, and .new to this - * filename for the journal. */ - const char *fname_base; - /** Human-readable description of what this store contains. */ - const char *description; - - tor_mmap_t *mmap; /**< A mmap for the main file in the store. */ - - store_type_t type; /**< What's stored in this store? */ - - /** The size of the router log, in bytes. */ - size_t journal_len; - /** The size of the router store, in bytes. */ - size_t store_len; - /** Total bytes dropped since last rebuild: this is space currently - * used in the cache and the journal that could be freed by a rebuild. */ - size_t bytes_dropped; -} desc_store_t; - -/** Contents of a directory of onion routers. */ -typedef struct { - /** Map from server identity digest to a member of routers. */ - struct digest_ri_map_t *identity_map; - /** Map from server descriptor digest to a signed_descriptor_t from - * routers or old_routers. */ - struct digest_sd_map_t *desc_digest_map; - /** Map from extra-info digest to an extrainfo_t. Only exists for - * routers in routers or old_routers. */ - struct digest_ei_map_t *extra_info_map; - /** Map from extra-info digests to a signed_descriptor_t for a router - * descriptor having that extra-info digest. Only exists for - * routers in routers or old_routers. */ - struct digest_sd_map_t *desc_by_eid_map; - /** List of routerinfo_t for all currently live routers we know. */ - smartlist_t *routers; - /** List of signed_descriptor_t for older router descriptors we're - * caching. */ - smartlist_t *old_routers; - /** Store holding server descriptors. If present, any router whose - * cache_info.saved_location == SAVED_IN_CACHE is stored in this file - * starting at cache_info.saved_offset */ - desc_store_t desc_store; - /** Store holding extra-info documents. */ - desc_store_t extrainfo_store; -} routerlist_t; - -/** Information on router used when extending a circuit. We don't need a - * full routerinfo_t to extend: we only need addr:port:keyid to build an OR - * connection, and onion_key to create the onionskin. Note that for onehop - * general-purpose tunnels, the onion_key is NULL. */ -typedef struct extend_info_t { - char nickname[MAX_HEX_NICKNAME_LEN+1]; /**< This router's nickname for - * display. */ - /** Hash of this router's RSA identity key. */ - char identity_digest[DIGEST_LEN]; - /** Ed25519 identity for this router, if any. */ - ed25519_public_key_t ed_identity; - uint16_t port; /**< OR port. */ - tor_addr_t addr; /**< IP address. */ - crypto_pk_t *onion_key; /**< Current onionskin key. */ - curve25519_public_key_t curve25519_onion_key; -} extend_info_t; - -/** Certificate for v3 directory protocol: binds long-term authority identity - * keys to medium-term authority signing keys. */ -typedef struct authority_cert_t { - /** Information relating to caching this cert on disk and looking it up. */ - signed_descriptor_t cache_info; - /** This authority's long-term authority identity key. */ - crypto_pk_t *identity_key; - /** This authority's medium-term signing key. */ - crypto_pk_t *signing_key; - /** The digest of <b>signing_key</b> */ - char signing_key_digest[DIGEST_LEN]; - /** The listed expiration time of this certificate. */ - time_t expires; - /** This authority's IPv4 address, in host order. */ - uint32_t addr; - /** This authority's directory port. */ - uint16_t dir_port; -} authority_cert_t; +typedef struct desc_store_t desc_store_t; +typedef struct routerlist_t routerlist_t; +typedef struct extend_info_t extend_info_t; +typedef struct authority_cert_t authority_cert_t; /** Bitfield enum type listing types of information that directory authorities * can be authoritative about, and that directory caches may or may not cache. @@ -2907,107 +1536,15 @@ typedef struct { } u; } onion_handshake_state_t; -typedef struct relay_crypto_t { - /* crypto environments */ - /** Encryption key and counter for cells heading towards the OR at this - * step. */ - crypto_cipher_t *f_crypto; - /** Encryption key and counter for cells heading back from the OR at this - * step. */ - crypto_cipher_t *b_crypto; - - /** Digest state for cells heading towards the OR at this step. */ - crypto_digest_t *f_digest; /* for integrity checking */ - /** Digest state for cells heading away from the OR at this step. */ - crypto_digest_t *b_digest; - -} relay_crypto_t; - -/** Holds accounting information for a single step in the layered encryption - * performed by a circuit. Used only at the client edge of a circuit. */ -typedef struct crypt_path_t { - uint32_t magic; - - /** Cryptographic state used for encrypting and authenticating relay - * cells to and from this hop. */ - relay_crypto_t crypto; - - /** Current state of the handshake as performed with the OR at this - * step. */ - onion_handshake_state_t handshake_state; - /** Diffie-hellman handshake state for performing an introduction - * operations */ - crypto_dh_t *rend_dh_handshake_state; - - /** Negotiated key material shared with the OR at this step. */ - char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */ - - /** Information to extend to the OR at this step. */ - extend_info_t *extend_info; - - /** Is the circuit built to this step? Must be one of: - * - CPATH_STATE_CLOSED (The circuit has not been extended to this step) - * - CPATH_STATE_AWAITING_KEYS (We have sent an EXTEND/CREATE to this step - * and not received an EXTENDED/CREATED) - * - CPATH_STATE_OPEN (The circuit has been extended to this step) */ - uint8_t state; -#define CPATH_STATE_CLOSED 0 -#define CPATH_STATE_AWAITING_KEYS 1 -#define CPATH_STATE_OPEN 2 - struct crypt_path_t *next; /**< Link to next crypt_path_t in the circuit. - * (The list is circular, so the last node - * links to the first.) */ - struct crypt_path_t *prev; /**< Link to previous crypt_path_t in the - * circuit. */ - - int package_window; /**< How many cells are we allowed to originate ending - * at this step? */ - int deliver_window; /**< How many cells are we willing to deliver originating - * at this step? */ -} crypt_path_t; - -/** A reference-counted pointer to a crypt_path_t, used only to share - * the final rendezvous cpath to be used on a service-side rendezvous - * circuit among multiple circuits built in parallel to the same - * destination rendezvous point. */ -typedef struct { - /** The reference count. */ - unsigned int refcount; - /** The pointer. Set to NULL when the crypt_path_t is put into use - * on an opened rendezvous circuit. */ - crypt_path_t *cpath; -} crypt_path_reference_t; +typedef struct relay_crypto_t relay_crypto_t; +typedef struct crypt_path_t crypt_path_t; +typedef struct crypt_path_reference_t crypt_path_reference_t; #define CPATH_KEY_MATERIAL_LEN (20*2+16*2) #define DH_KEY_LEN DH_BYTES -/** Information used to build a circuit. */ -typedef struct { - /** Intended length of the final circuit. */ - int desired_path_len; - /** How to extend to the planned exit node. */ - extend_info_t *chosen_exit; - /** Whether every node in the circ must have adequate uptime. */ - unsigned int need_uptime : 1; - /** Whether every node in the circ must have adequate capacity. */ - unsigned int need_capacity : 1; - /** Whether the last hop was picked with exiting in mind. */ - unsigned int is_internal : 1; - /** Did we pick this as a one-hop tunnel (not safe for other streams)? - * These are for encrypted dir conns that exit to this router, not - * for arbitrary exits from the circuit. */ - unsigned int onehop_tunnel : 1; - /** The crypt_path_t to append after rendezvous: used for rendezvous. */ - crypt_path_t *pending_final_cpath; - /** A ref-counted reference to the crypt_path_t to append after - * rendezvous; used on the service side. */ - crypt_path_reference_t *service_pending_final_cpath_ref; - /** How many times has building a circuit for this task failed? */ - int failure_count; - /** At what time should we give up on this task? */ - time_t expiry_time; -} cpath_build_state_t; +typedef struct cpath_build_state_t cpath_build_state_t; /** "magic" value for an origin_circuit_t */ #define ORIGIN_CIRCUIT_MAGIC 0x35315243u @@ -3033,162 +1570,9 @@ typedef struct testing_cell_stats_entry_t { unsigned int exitward:1; /**< 0 for app-ward, 1 for exit-ward. */ } testing_cell_stats_entry_t; -/** - * A circuit is a path over the onion routing - * network. Applications can connect to one end of the circuit, and can - * create exit connections at the other end of the circuit. AP and exit - * connections have only one circuit associated with them (and thus these - * connection types are closed when the circuit is closed), whereas - * OR connections multiplex many circuits at once, and stay standing even - * when there are no circuits running over them. - * - * A circuit_t structure can fill one of two roles. First, a or_circuit_t - * links two connections together: either an edge connection and an OR - * connection, or two OR connections. (When joined to an OR connection, a - * circuit_t affects only cells sent to a particular circID on that - * connection. When joined to an edge connection, a circuit_t affects all - * data.) - - * Second, an origin_circuit_t holds the cipher keys and state for sending data - * along a given circuit. At the OP, it has a sequence of ciphers, each - * of which is shared with a single OR along the circuit. Separate - * ciphers are used for data going "forward" (away from the OP) and - * "backward" (towards the OP). At the OR, a circuit has only two stream - * ciphers: one for data going forward, and one for data going backward. - */ -typedef struct circuit_t { - uint32_t magic; /**< For memory and type debugging: must equal - * ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */ - - /** The channel that is next in this circuit. */ - channel_t *n_chan; - - /** - * The circuit_id used in the next (forward) hop of this circuit; - * this is unique to n_chan, but this ordered pair is globally - * unique: - * - * (n_chan->global_identifier, n_circ_id) - */ - circid_t n_circ_id; - - /** - * Circuit mux associated with n_chan to which this circuit is attached; - * NULL if we have no n_chan. - */ - circuitmux_t *n_mux; - - /** Queue of cells waiting to be transmitted on n_chan */ - cell_queue_t n_chan_cells; - - /** - * The hop to which we want to extend this circuit. Should be NULL if - * the circuit has attached to a channel. - */ - extend_info_t *n_hop; - - /** True iff we are waiting for n_chan_cells to become less full before - * allowing p_streams to add any more cells. (Origin circuit only.) */ - unsigned int streams_blocked_on_n_chan : 1; - /** True iff we are waiting for p_chan_cells to become less full before - * allowing n_streams to add any more cells. (OR circuit only.) */ - unsigned int streams_blocked_on_p_chan : 1; - - /** True iff we have queued a delete backwards on this circuit, but not put - * it on the output buffer. */ - unsigned int p_delete_pending : 1; - /** True iff we have queued a delete forwards on this circuit, but not put - * it on the output buffer. */ - unsigned int n_delete_pending : 1; - - /** True iff this circuit has received a DESTROY cell in either direction */ - unsigned int received_destroy : 1; - - uint8_t state; /**< Current status of this circuit. */ - uint8_t purpose; /**< Why are we creating this circuit? */ - - /** How many relay data cells can we package (read from edge streams) - * on this circuit before we receive a circuit-level sendme cell asking - * for more? */ - int package_window; - /** How many relay data cells will we deliver (write to edge streams) - * on this circuit? When deliver_window gets low, we send some - * circuit-level sendme cells to indicate that we're willing to accept - * more. */ - int deliver_window; - - /** Temporary field used during circuits_handle_oom. */ - uint32_t age_tmp; - - /** For storage while n_chan is pending (state CIRCUIT_STATE_CHAN_WAIT). */ - struct create_cell_t *n_chan_create_cell; - - /** When did circuit construction actually begin (ie send the - * CREATE cell or begin cannibalization). - * - * Note: This timer will get reset if we decide to cannibalize - * a circuit. It may also get reset during certain phases of hidden - * service circuit use. - * - * We keep this timestamp with a higher resolution than most so that the - * circuit-build-time tracking code can get millisecond resolution. - */ - struct timeval timestamp_began; - - /** This timestamp marks when the init_circuit_base constructor ran. */ - struct timeval timestamp_created; - - /** When the circuit was first used, or 0 if the circuit is clean. - * - * XXXX Note that some code will artificially adjust this value backward - * in time in order to indicate that a circuit shouldn't be used for new - * streams, but that it can stay alive as long as it has streams on it. - * That's a kludge we should fix. - * - * XXX The CBT code uses this field to record when HS-related - * circuits entered certain states. This usage probably won't - * interfere with this field's primary purpose, but we should - * document it more thoroughly to make sure of that. - * - * XXX The SocksPort option KeepaliveIsolateSOCKSAuth will artificially - * adjust this value forward each time a suitable stream is attached to an - * already constructed circuit, potentially keeping the circuit alive - * indefinitely. - */ - time_t timestamp_dirty; - - uint16_t marked_for_close; /**< Should we close this circuit at the end of - * the main loop? (If true, holds the line number - * where this circuit was marked.) */ - const char *marked_for_close_file; /**< For debugging: in which file was this - * circuit marked for close? */ - /** For what reason (See END_CIRC_REASON...) is this circuit being closed? - * This field is set in circuit_mark_for_close and used later in - * circuit_about_to_free. */ - int marked_for_close_reason; - /** As marked_for_close_reason, but reflects the underlying reason for - * closing this circuit. - */ - int marked_for_close_orig_reason; - - /** Unique ID for measuring tunneled network status requests. */ - uint64_t dirreq_id; - - /** Index in smartlist of all circuits (global_circuitlist). */ - int global_circuitlist_idx; - - /** Various statistics about cells being added to or removed from this - * circuit's queues; used only if CELL_STATS events are enabled and - * cleared after being sent to control port. */ - smartlist_t *testing_cell_stats; - - /** If set, points to an HS token that this circuit might be carrying. - * Used by the HS circuitmap. */ - hs_token_t *hs_token; - /** Hashtable node: used to look up the circuit by its HS token using the HS - circuitmap. */ - HT_ENTRY(circuit_t) hs_circuitmap_node; -} circuit_t; +typedef struct circuit_t circuit_t; +typedef struct origin_circuit_t origin_circuit_t; +typedef struct or_circuit_t or_circuit_t; /** Largest number of relay_early cells that we can send on a given * circuit. */ @@ -3251,288 +1635,6 @@ typedef enum { } path_state_t; #define path_state_bitfield_t ENUM_BF(path_state_t) -/** An origin_circuit_t holds data necessary to build and use a circuit. - */ -typedef struct origin_circuit_t { - circuit_t base_; - - /** Linked list of AP streams (or EXIT streams if hidden service) - * associated with this circuit. */ - edge_connection_t *p_streams; - - /** Bytes read on this circuit since last call to - * control_event_circ_bandwidth_used(). Only used if we're configured - * to emit CIRC_BW events. */ - uint32_t n_read_circ_bw; - - /** Bytes written to on this circuit since last call to - * control_event_circ_bandwidth_used(). Only used if we're configured - * to emit CIRC_BW events. */ - uint32_t n_written_circ_bw; - - /** Total known-valid relay cell bytes since last call to - * control_event_circ_bandwidth_used(). Only used if we're configured - * to emit CIRC_BW events. */ - uint32_t n_delivered_read_circ_bw; - - /** Total written relay cell bytes since last call to - * control_event_circ_bandwidth_used(). Only used if we're configured - * to emit CIRC_BW events. */ - uint32_t n_delivered_written_circ_bw; - - /** Total overhead data in all known-valid relay data cells since last - * call to control_event_circ_bandwidth_used(). Only used if we're - * configured to emit CIRC_BW events. */ - uint32_t n_overhead_read_circ_bw; - - /** Total written overhead data in all relay data cells since last call to - * control_event_circ_bandwidth_used(). Only used if we're configured - * to emit CIRC_BW events. */ - uint32_t n_overhead_written_circ_bw; - - /** Build state for this circuit. It includes the intended path - * length, the chosen exit router, rendezvous information, etc. - */ - cpath_build_state_t *build_state; - /** The doubly-linked list of crypt_path_t entries, one per hop, - * for this circuit. This includes ciphers for each hop, - * integrity-checking digests for each hop, and package/delivery - * windows for each hop. - */ - crypt_path_t *cpath; - - /** Holds all rendezvous data on either client or service side. */ - rend_data_t *rend_data; - - /** Holds hidden service identifier on either client or service side. This - * is for both introduction and rendezvous circuit. */ - struct hs_ident_circuit_t *hs_ident; - - /** Holds the data that the entry guard system uses to track the - * status of the guard this circuit is using, and thereby to determine - * whether this circuit can be used. */ - struct circuit_guard_state_t *guard_state; - - /** Index into global_origin_circuit_list for this circuit. -1 if not - * present. */ - int global_origin_circuit_list_idx; - - /** How many more relay_early cells can we send on this circuit, according - * to the specification? */ - unsigned int remaining_relay_early_cells : 4; - - /** Set if this circuit is insanely old and we already informed the user */ - unsigned int is_ancient : 1; - - /** Set if this circuit has already been opened. Used to detect - * cannibalized circuits. */ - unsigned int has_opened : 1; - - /** - * Path bias state machine. Used to ensure integrity of our - * circuit building and usage accounting. See path_state_t - * for more details. - */ - path_state_bitfield_t path_state : 3; - - /* If this flag is set, we should not consider attaching any more - * connections to this circuit. */ - unsigned int unusable_for_new_conns : 1; - - /** - * Tristate variable to guard against pathbias miscounting - * due to circuit purpose transitions changing the decision - * of pathbias_should_count(). This variable is informational - * only. The current results of pathbias_should_count() are - * the official decision for pathbias accounting. - */ - uint8_t pathbias_shouldcount; -#define PATHBIAS_SHOULDCOUNT_UNDECIDED 0 -#define PATHBIAS_SHOULDCOUNT_IGNORED 1 -#define PATHBIAS_SHOULDCOUNT_COUNTED 2 - - /** For path probing. Store the temporary probe stream ID - * for response comparison */ - streamid_t pathbias_probe_id; - - /** For path probing. Store the temporary probe address nonce - * (in host byte order) for response comparison. */ - uint32_t pathbias_probe_nonce; - - /** Set iff this is a hidden-service circuit which has timed out - * according to our current circuit-build timeout, but which has - * been kept around because it might still succeed in connecting to - * its destination, and which is not a fully-connected rendezvous - * circuit. - * - * (We clear this flag for client-side rendezvous circuits when they - * are 'joined' to the other side's rendezvous circuit, so that - * connection_ap_handshake_attach_circuit can put client streams on - * the circuit. We also clear this flag for service-side rendezvous - * circuits when they are 'joined' to a client's rend circ, but only - * for symmetry with the client case. Client-side introduction - * circuits are closed when we get a joined rend circ, and - * service-side introduction circuits never have this flag set.) */ - unsigned int hs_circ_has_timed_out : 1; - - /** Set iff this circuit has been given a relaxed timeout because - * no circuits have opened. Used to prevent spamming logs. */ - unsigned int relaxed_timeout : 1; - - /** Set iff this is a service-side rendezvous circuit for which a - * new connection attempt has been launched. We consider launching - * a new service-side rend circ to a client when the previous one - * fails; now that we don't necessarily close a service-side rend - * circ when we launch a new one to the same client, this flag keeps - * us from launching two retries for the same failed rend circ. */ - unsigned int hs_service_side_rend_circ_has_been_relaunched : 1; - - /** What commands were sent over this circuit that decremented the - * RELAY_EARLY counter? This is for debugging task 878. */ - uint8_t relay_early_commands[MAX_RELAY_EARLY_CELLS_PER_CIRCUIT]; - - /** How many RELAY_EARLY cells have been sent over this circuit? This is - * for debugging task 878, too. */ - int relay_early_cells_sent; - - /** The next stream_id that will be tried when we're attempting to - * construct a new AP stream originating at this circuit. */ - streamid_t next_stream_id; - - /* The intro key replaces the hidden service's public key if purpose is - * S_ESTABLISH_INTRO or S_INTRO, provided that no unversioned rendezvous - * descriptor is used. */ - crypto_pk_t *intro_key; - - /** Quasi-global identifier for this circuit; used for control.c */ - /* XXXX NM This can get re-used after 2**32 circuits. */ - uint32_t global_identifier; - - /** True if we have associated one stream to this circuit, thereby setting - * the isolation parameters for this circuit. Note that this doesn't - * necessarily mean that we've <em>attached</em> any streams to the circuit: - * we may only have marked up this circuit during the launch process. - */ - unsigned int isolation_values_set : 1; - /** True iff any stream has <em>ever</em> been attached to this circuit. - * - * In a better world we could use timestamp_dirty for this, but - * timestamp_dirty is far too overloaded at the moment. - */ - unsigned int isolation_any_streams_attached : 1; - - /** A bitfield of ISO_* flags for every isolation field such that this - * circuit has had streams with more than one value for that field - * attached to it. */ - uint8_t isolation_flags_mixed; - - /** @name Isolation parameters - * - * If any streams have been associated with this circ (isolation_values_set - * == 1), and all streams associated with the circuit have had the same - * value for some field ((isolation_flags_mixed & ISO_FOO) == 0), then these - * elements hold the value for that field. - * - * Note again that "associated" is not the same as "attached": we - * preliminarily associate streams with a circuit while the circuit is being - * launched, so that we can tell whether we need to launch more circuits. - * - * @{ - */ - uint8_t client_proto_type; - uint8_t client_proto_socksver; - uint16_t dest_port; - tor_addr_t client_addr; - char *dest_address; - int session_group; - unsigned nym_epoch; - size_t socks_username_len; - uint8_t socks_password_len; - /* Note that the next two values are NOT NUL-terminated; see - socks_username_len and socks_password_len for their lengths. */ - char *socks_username; - char *socks_password; - /** Global identifier for the first stream attached here; used by - * ISO_STREAM. */ - uint64_t associated_isolated_stream_global_id; - /**@}*/ - /** A list of addr_policy_t for this circuit in particular. Used by - * adjust_exit_policy_from_exitpolicy_failure. - */ - smartlist_t *prepend_policy; - - /** How long do we wait before closing this circuit if it remains - * completely idle after it was built, in seconds? This value - * is randomized on a per-circuit basis from CircuitsAvailableTimoeut - * to 2*CircuitsAvailableTimoeut. */ - int circuit_idle_timeout; - -} origin_circuit_t; - -struct onion_queue_t; - -/** An or_circuit_t holds information needed to implement a circuit at an - * OR. */ -typedef struct or_circuit_t { - circuit_t base_; - - /** Pointer to an entry on the onion queue, if this circuit is waiting for a - * chance to give an onionskin to a cpuworker. Used only in onion.c */ - struct onion_queue_t *onionqueue_entry; - /** Pointer to a workqueue entry, if this circuit has given an onionskin to - * a cpuworker and is waiting for a response. Used to decide whether it is - * safe to free a circuit or if it is still in use by a cpuworker. */ - struct workqueue_entry_s *workqueue_entry; - - /** The circuit_id used in the previous (backward) hop of this circuit. */ - circid_t p_circ_id; - /** Queue of cells waiting to be transmitted on p_conn. */ - cell_queue_t p_chan_cells; - /** The channel that is previous in this circuit. */ - channel_t *p_chan; - /** - * Circuit mux associated with p_chan to which this circuit is attached; - * NULL if we have no p_chan. - */ - circuitmux_t *p_mux; - /** Linked list of Exit streams associated with this circuit. */ - edge_connection_t *n_streams; - /** Linked list of Exit streams associated with this circuit that are - * still being resolved. */ - edge_connection_t *resolving_streams; - - /** Cryptographic state used for encrypting and authenticating relay - * cells to and from this hop. */ - relay_crypto_t crypto; - - /** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit - * is not marked for close. */ - struct or_circuit_t *rend_splice; - - /** Stores KH for the handshake. */ - char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */ - - /** How many more relay_early cells can we send on this circuit, according - * to the specification? */ - unsigned int remaining_relay_early_cells : 4; - - /* We have already received an INTRODUCE1 cell on this circuit. */ - unsigned int already_received_introduce1 : 1; - - /** If set, this circuit carries HS traffic. Consider it in any HS - * statistics. */ - unsigned int circuit_carries_hs_traffic_stats : 1; - - /** Number of cells that were removed from circuit queue; reset every - * time when writing buffer stats to disk. */ - uint32_t processed_cells; - - /** Total time in milliseconds that cells spent in both app-ward and - * exit-ward queues of this circuit; reset every time when writing - * buffer stats to disk. */ - uint64_t total_cell_waiting_time; -} or_circuit_t; - #if REND_COOKIE_LEN != DIGEST_LEN #error "The REND_TOKEN_LEN macro assumes REND_COOKIE_LEN == DIGEST_LEN" #endif @@ -3541,45 +1643,6 @@ typedef struct or_circuit_t { /** Convert a circuit subtype to a circuit_t. */ #define TO_CIRCUIT(x) (&((x)->base_)) -/** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Assert - * if the cast is impossible. */ -static or_circuit_t *TO_OR_CIRCUIT(circuit_t *); -static const or_circuit_t *CONST_TO_OR_CIRCUIT(const circuit_t *); -/** Convert a circuit_t* to a pointer to the enclosing origin_circuit_t. - * Assert if the cast is impossible. */ -static origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *); -static const origin_circuit_t *CONST_TO_ORIGIN_CIRCUIT(const circuit_t *); - -/** Return 1 iff <b>node</b> has Exit flag and no BadExit flag. - * Otherwise, return 0. - */ -static inline int node_is_good_exit(const node_t *node) -{ - return node->is_exit && ! node->is_bad_exit; -} - -static inline or_circuit_t *TO_OR_CIRCUIT(circuit_t *x) -{ - tor_assert(x->magic == OR_CIRCUIT_MAGIC); - return DOWNCAST(or_circuit_t, x); -} -static inline const or_circuit_t *CONST_TO_OR_CIRCUIT(const circuit_t *x) -{ - tor_assert(x->magic == OR_CIRCUIT_MAGIC); - return DOWNCAST(or_circuit_t, x); -} -static inline origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *x) -{ - tor_assert(x->magic == ORIGIN_CIRCUIT_MAGIC); - return DOWNCAST(origin_circuit_t, x); -} -static inline const origin_circuit_t *CONST_TO_ORIGIN_CIRCUIT( - const circuit_t *x) -{ - tor_assert(x->magic == ORIGIN_CIRCUIT_MAGIC); - return DOWNCAST(origin_circuit_t, x); -} - /* limits for TCP send and recv buffer size used for constrained sockets */ #define MIN_CONSTRAINED_TCP_BUFFER 2048 #define MAX_CONSTRAINED_TCP_BUFFER 262144 /* 256k */ @@ -3620,27 +1683,7 @@ static inline const origin_circuit_t *CONST_TO_ORIGIN_CIRCUIT( /** First automatically allocated session group number */ #define SESSION_GROUP_FIRST_AUTO -4 -/** Configuration for a single port that we're listening on. */ -typedef struct port_cfg_t { - tor_addr_t addr; /**< The actual IP to listen on, if !is_unix_addr. */ - int port; /**< The configured port, or CFG_AUTO_PORT to tell Tor to pick its - * own port. */ - uint8_t type; /**< One of CONN_TYPE_*_LISTENER */ - unsigned is_unix_addr : 1; /**< True iff this is an AF_UNIX address. */ - - unsigned is_group_writable : 1; - unsigned is_world_writable : 1; - unsigned relax_dirmode_check : 1; - - entry_port_cfg_t entry_cfg; - - server_port_cfg_t server_cfg; - - /* Unix sockets only: */ - /** Path for an AF_UNIX address */ - char unix_addr[FLEXIBLE_ARRAY_MEMBER]; -} port_cfg_t; - +typedef struct port_cfg_t port_cfg_t; typedef struct routerset_t routerset_t; /** A magic value for the (Socks|OR|...)Port options below, telling Tor @@ -4794,54 +2837,6 @@ typedef struct { #define SOCKS_COMMAND_IS_RESOLVE(c) ((c)==SOCKS_COMMAND_RESOLVE || \ (c)==SOCKS_COMMAND_RESOLVE_PTR) -/** State of a SOCKS request from a user to an OP. Also used to encode other - * information for non-socks user request (such as those on TransPort and - * DNSPort) */ -struct socks_request_t { - /** Which version of SOCKS did the client use? One of "0, 4, 5" -- where - * 0 means that no socks handshake ever took place, and this is just a - * stub connection (e.g. see connection_ap_make_link()). */ - uint8_t socks_version; - /** If using socks5 authentication, which authentication type did we - * negotiate? currently we support 0 (no authentication) and 2 - * (username/password). */ - uint8_t auth_type; - /** What is this stream's goal? One of the SOCKS_COMMAND_* values */ - uint8_t command; - /** Which kind of listener created this stream? */ - uint8_t listener_type; - size_t replylen; /**< Length of <b>reply</b>. */ - uint8_t reply[MAX_SOCKS_REPLY_LEN]; /**< Write an entry into this string if - * we want to specify our own socks reply, - * rather than using the default socks4 or - * socks5 socks reply. We use this for the - * two-stage socks5 handshake. - */ - char address[MAX_SOCKS_ADDR_LEN]; /**< What address did the client ask to - connect to/resolve? */ - uint16_t port; /**< What port did the client ask to connect to? */ - unsigned int has_finished : 1; /**< Has the SOCKS handshake finished? Used to - * make sure we send back a socks reply for - * every connection. */ - unsigned int got_auth : 1; /**< Have we received any authentication data? */ - /** If this is set, we will choose "no authentication" instead of - * "username/password" authentication if both are offered. Used as input to - * parse_socks. */ - unsigned int socks_prefer_no_auth : 1; - - /** Number of bytes in username; 0 if username is NULL */ - size_t usernamelen; - /** Number of bytes in password; 0 if password is NULL */ - uint8_t passwordlen; - /** The negotiated username value if any (for socks5), or the entire - * authentication string (for socks4). This value is NOT nul-terminated; - * see usernamelen for its length. */ - char *username; - /** The negotiated password value if any (for socks5). This value is NOT - * nul-terminated; see passwordlen for its length. */ - char *password; -}; - /********************************* circuitbuild.c **********************/ /** How many hops does a general-purpose circuit have by default? */ @@ -4940,21 +2935,6 @@ int32_t circuit_build_times_initial_timeout(void); #error "RECENT_CIRCUITS is set too low." #endif -/** Information about the state of our local network connection */ -typedef struct { - /** The timestamp we last completed a TLS handshake or received a cell */ - time_t network_last_live; - /** If the network is not live, how many timeouts has this caused? */ - int nonlive_timeouts; - /** Circular array of circuits that have made it to the first hop. Slot is - * 1 if circuit timed out, 0 if circuit succeeded */ - int8_t *timeouts_after_firsthop; - /** Number of elements allocated for the above array */ - int num_recent_circs; - /** Index into circular array. */ - int after_firsthop_idx; -} network_liveness_t; - typedef struct circuit_build_times_s circuit_build_times_t; /********************************* config.c ***************************/ @@ -5084,14 +3064,6 @@ typedef enum { BOOTSTRAP_STATUS_DONE=100 } bootstrap_status_t; -/********************************* directory.c ***************************/ - -/** A pair of digests created by dir_split_resource_info_fingerprint_pairs() */ -typedef struct { - char first[DIGEST_LEN]; - char second[DIGEST_LEN]; -} fp_pair_t; - /********************************* dirserv.c ***************************/ /** An enum to describe what format we're generating a routerstatus line in. @@ -5109,29 +3081,9 @@ typedef enum { NS_V3_CONSENSUS_MICRODESC } routerstatus_format_type_t; -#ifdef DIRSERV_PRIVATE -typedef struct measured_bw_line_t { - char node_id[DIGEST_LEN]; - char node_hex[MAX_HEX_NICKNAME_LEN+1]; - long int bw_kb; -} measured_bw_line_t; - -#endif /* defined(DIRSERV_PRIVATE) */ - /********************************* dirvote.c ************************/ -/** Describes the schedule by which votes should be generated. */ -typedef struct vote_timing_t { - /** Length in seconds between one consensus becoming valid and the next - * becoming valid. */ - int vote_interval; - /** For how many intervals is a consensus valid? */ - int n_intervals_valid; - /** Time in seconds allowed to propagate votes */ - int vote_delay; - /** Time in seconds allowed to propagate signatures */ - int dist_delay; -} vote_timing_t; +typedef struct vote_timing_t vote_timing_t; /********************************* geoip.c **************************/ @@ -5245,18 +3197,9 @@ typedef enum { /********************************* rendcommon.c ***************************/ -/** Hidden-service side configuration of client authorization. */ -typedef struct rend_authorized_client_t { - char *client_name; - uint8_t descriptor_cookie[REND_DESC_COOKIE_LEN]; - crypto_pk_t *client_key; -} rend_authorized_client_t; - -/** ASCII-encoded v2 hidden service descriptor. */ -typedef struct rend_encoded_v2_service_descriptor_t { - char desc_id[DIGEST_LEN]; /**< Descriptor ID. */ - char *desc_str; /**< Descriptor string. */ -} rend_encoded_v2_service_descriptor_t; +typedef struct rend_authorized_client_t rend_authorized_client_t; +typedef struct rend_encoded_v2_service_descriptor_t + rend_encoded_v2_service_descriptor_t; /** The maximum number of non-circuit-build-timeout failures a hidden * service client will tolerate while trying to build a circuit to an @@ -5289,133 +3232,12 @@ typedef struct rend_encoded_v2_service_descriptor_t { * lifetime so this is a hard limit on the amount of time we do that. */ #define MAX_INTRO_POINT_CIRCUIT_RETRIES 3 -/** Introduction point information. Used both in rend_service_t (on - * the service side) and in rend_service_descriptor_t (on both the - * client and service side). */ -typedef struct rend_intro_point_t { - extend_info_t *extend_info; /**< Extend info for connecting to this - * introduction point via a multi-hop path. */ - crypto_pk_t *intro_key; /**< Introduction key that replaces the service - * key, if this descriptor is V2. */ - - /** (Client side only) Flag indicating that a timeout has occurred - * after sending an INTRODUCE cell to this intro point. After a - * timeout, an intro point should not be tried again during the same - * hidden service connection attempt, but it may be tried again - * during a future connection attempt. */ - unsigned int timed_out : 1; - - /** (Client side only) The number of times we have failed to build a - * circuit to this intro point for some reason other than our - * circuit-build timeout. See also MAX_INTRO_POINT_REACHABILITY_FAILURES. */ - unsigned int unreachable_count : 3; - - /** (Service side only) Flag indicating that this intro point was - * included in the last HS descriptor we generated. */ - unsigned int listed_in_last_desc : 1; - - /** (Service side only) A replay cache recording the RSA-encrypted parts - * of INTRODUCE2 cells this intro point's circuit has received. This is - * used to prevent replay attacks. */ - replaycache_t *accepted_intro_rsa_parts; - - /** (Service side only) Count of INTRODUCE2 cells accepted from this - * intro point. - */ - int accepted_introduce2_count; - - /** (Service side only) Maximum number of INTRODUCE2 cells that this IP - * will accept. This is a random value between - * INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS and - * INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS. */ - int max_introductions; - - /** (Service side only) The time at which this intro point was first - * published, or -1 if this intro point has not yet been - * published. */ - time_t time_published; - - /** (Service side only) The time at which this intro point should - * (start to) expire, or -1 if we haven't decided when this intro - * point should expire. */ - time_t time_to_expire; - - /** (Service side only) The amount of circuit creation we've made to this - * intro point. This is incremented every time we do a circuit relaunch on - * this object which is triggered when the circuit dies but the node is - * still in the consensus. After MAX_INTRO_POINT_CIRCUIT_RETRIES, we give - * up on it. */ - unsigned int circuit_retries; - - /** (Service side only) Set if this intro point has an established circuit - * and unset if it doesn't. */ - unsigned int circuit_established:1; -} rend_intro_point_t; - -#define REND_PROTOCOL_VERSION_BITMASK_WIDTH 16 - -/** Information used to connect to a hidden service. Used on both the - * service side and the client side. */ -typedef struct rend_service_descriptor_t { - crypto_pk_t *pk; /**< This service's public key. */ - int version; /**< Version of the descriptor format: 0 or 2. */ - time_t timestamp; /**< Time when the descriptor was generated. */ - /** Bitmask: which introduce/rendezvous protocols are supported? - * (We allow bits '0', '1', '2' and '3' to be set.) */ - unsigned protocols : REND_PROTOCOL_VERSION_BITMASK_WIDTH; - /** List of the service's introduction points. Elements are removed if - * introduction attempts fail. */ - smartlist_t *intro_nodes; - /** Has descriptor been uploaded to all hidden service directories? */ - int all_uploads_performed; - /** List of hidden service directories to which an upload request for - * this descriptor could be sent. Smartlist exists only when at least one - * of the previous upload requests failed (otherwise it's not important - * to know which uploads succeeded and which not). */ - smartlist_t *successful_uploads; -} rend_service_descriptor_t; +typedef struct rend_intro_point_t rend_intro_point_t; +typedef struct rend_service_descriptor_t rend_service_descriptor_t; /********************************* routerlist.c ***************************/ -/** Represents information about a single trusted or fallback directory - * server. */ -typedef struct dir_server_t { - char *description; - char *nickname; - char *address; /**< Hostname. */ - /* XX/teor - why do we duplicate the address and port fields here and in - * fake_status? Surely we could just use fake_status (#17867). */ - tor_addr_t ipv6_addr; /**< IPv6 address if present; AF_UNSPEC if not */ - uint32_t addr; /**< IPv4 address. */ - uint16_t dir_port; /**< Directory port. */ - uint16_t or_port; /**< OR port: Used for tunneling connections. */ - uint16_t ipv6_orport; /**< OR port corresponding to ipv6_addr. */ - double weight; /** Weight used when selecting this node at random */ - char digest[DIGEST_LEN]; /**< Digest of identity key. */ - char v3_identity_digest[DIGEST_LEN]; /**< Digest of v3 (authority only, - * high-security) identity key. */ - - unsigned int is_running:1; /**< True iff we think this server is running. */ - unsigned int is_authority:1; /**< True iff this is a directory authority - * of some kind. */ - - /** True iff this server has accepted the most recent server descriptor - * we tried to upload to it. */ - unsigned int has_accepted_serverdesc:1; - - /** What kind of authority is this? (Bitfield.) */ - dirinfo_type_t type; - - time_t addr_current_at; /**< When was the document that we derived the - * address information from published? */ - - routerstatus_t fake_status; /**< Used when we need to pass this trusted - * dir_server_t to - * directory_request_set_routerstatus. - * as a routerstatus_t. Not updated by the - * router-status management code! - **/ -} dir_server_t; +typedef struct dir_server_t dir_server_t; #define RELAY_REQUIRED_MIN_BANDWIDTH (75*1024) #define BRIDGE_REQUIRED_MIN_BANDWIDTH (50*1024) @@ -5506,28 +3328,6 @@ typedef enum was_router_added_t { ROUTER_CERTS_EXPIRED = -8 } was_router_added_t; -/********************************* routerparse.c ************************/ - -#define MAX_STATUS_TAG_LEN 32 -/** Structure to hold parsed Tor versions. This is a little messier - * than we would like it to be, because we changed version schemes with 0.1.0. - * - * See version-spec.txt for the whole business. - */ -typedef struct tor_version_t { - int major; - int minor; - int micro; - /** Release status. For version in the post-0.1 format, this is always - * VER_RELEASE. */ - enum { VER_PRE=0, VER_RC=1, VER_RELEASE=2, } status; - int patchlevel; - char status_tag[MAX_STATUS_TAG_LEN]; - int svn_revision; - - int git_tag_len; - char git_tag[DIGEST_LEN]; -} tor_version_t; +typedef struct tor_version_t tor_version_t; #endif /* !defined(TOR_OR_H) */ - diff --git a/src/or/or_circuit_st.h b/src/or/or_circuit_st.h new file mode 100644 index 0000000000..158a5314ef --- /dev/null +++ b/src/or/or_circuit_st.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef OR_CIRCUIT_ST_H +#define OR_CIRCUIT_ST_H + +#include "or/or.h" + +#include "or/circuit_st.h" +#include "or/crypt_path_st.h" + +struct onion_queue_t; + +/** An or_circuit_t holds information needed to implement a circuit at an + * OR. */ +struct or_circuit_t { + circuit_t base_; + + /** Pointer to an entry on the onion queue, if this circuit is waiting for a + * chance to give an onionskin to a cpuworker. Used only in onion.c */ + struct onion_queue_t *onionqueue_entry; + /** Pointer to a workqueue entry, if this circuit has given an onionskin to + * a cpuworker and is waiting for a response. Used to decide whether it is + * safe to free a circuit or if it is still in use by a cpuworker. */ + struct workqueue_entry_s *workqueue_entry; + + /** The circuit_id used in the previous (backward) hop of this circuit. */ + circid_t p_circ_id; + /** Queue of cells waiting to be transmitted on p_conn. */ + cell_queue_t p_chan_cells; + /** The channel that is previous in this circuit. */ + channel_t *p_chan; + /** + * Circuit mux associated with p_chan to which this circuit is attached; + * NULL if we have no p_chan. + */ + circuitmux_t *p_mux; + /** Linked list of Exit streams associated with this circuit. */ + edge_connection_t *n_streams; + /** Linked list of Exit streams associated with this circuit that are + * still being resolved. */ + edge_connection_t *resolving_streams; + + /** Cryptographic state used for encrypting and authenticating relay + * cells to and from this hop. */ + relay_crypto_t crypto; + + /** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit + * is not marked for close. */ + struct or_circuit_t *rend_splice; + + /** Stores KH for the handshake. */ + char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */ + + /** How many more relay_early cells can we send on this circuit, according + * to the specification? */ + unsigned int remaining_relay_early_cells : 4; + + /* We have already received an INTRODUCE1 cell on this circuit. */ + unsigned int already_received_introduce1 : 1; + + /** If set, this circuit carries HS traffic. Consider it in any HS + * statistics. */ + unsigned int circuit_carries_hs_traffic_stats : 1; + + /** Number of cells that were removed from circuit queue; reset every + * time when writing buffer stats to disk. */ + uint32_t processed_cells; + + /** Total time in milliseconds that cells spent in both app-ward and + * exit-ward queues of this circuit; reset every time when writing + * buffer stats to disk. */ + uint64_t total_cell_waiting_time; +}; + +#endif + diff --git a/src/or/or_connection_st.h b/src/or/or_connection_st.h new file mode 100644 index 0000000000..eba2721c37 --- /dev/null +++ b/src/or/or_connection_st.h @@ -0,0 +1,90 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef OR_CONNECTION_ST_H +#define OR_CONNECTION_ST_H + +#include "or/connection_st.h" + +/** Subtype of connection_t for an "OR connection" -- that is, one that speaks + * cells over TLS. */ +struct or_connection_t { + connection_t base_; + + /** Hash of the public RSA key for the other side's identity key, or zeroes + * if the other side hasn't shown us a valid identity key. */ + char identity_digest[DIGEST_LEN]; + + /** Extended ORPort connection identifier. */ + char *ext_or_conn_id; + /** This is the ClientHash value we expect to receive from the + * client during the Extended ORPort authentication protocol. We + * compute it upon receiving the ClientNoce from the client, and we + * compare it with the acual ClientHash value sent by the + * client. */ + char *ext_or_auth_correct_client_hash; + /** String carrying the name of the pluggable transport + * (e.g. "obfs2") that is obfuscating this connection. If no + * pluggable transports are used, it's NULL. */ + char *ext_or_transport; + + char *nickname; /**< Nickname of OR on other side (if any). */ + + tor_tls_t *tls; /**< TLS connection state. */ + int tls_error; /**< Last tor_tls error code. */ + /** When we last used this conn for any client traffic. If not + * recent, we can rate limit it further. */ + + /* Channel using this connection */ + channel_tls_t *chan; + + tor_addr_t real_addr; /**< The actual address that this connection came from + * or went to. The <b>addr</b> field is prone to + * getting overridden by the address from the router + * descriptor matching <b>identity_digest</b>. */ + + /** Should this connection be used for extending circuits to the server + * matching the <b>identity_digest</b> field? Set to true if we're pretty + * sure we aren't getting MITMed, either because we're connected to an + * address listed in a server descriptor, or because an authenticated + * NETINFO cell listed the address we're connected to as recognized. */ + unsigned int is_canonical:1; + + /** True iff this is an outgoing connection. */ + unsigned int is_outgoing:1; + unsigned int proxy_type:2; /**< One of PROXY_NONE...PROXY_SOCKS5 */ + unsigned int wide_circ_ids:1; + /** True iff this connection has had its bootstrap failure logged with + * control_event_bootstrap_problem. */ + unsigned int have_noted_bootstrap_problem:1; + /** True iff this is a client connection and its address has been put in the + * geoip cache and handled by the DoS mitigation subsystem. We use this to + * insure we have a coherent count of concurrent connection. */ + unsigned int tracked_for_dos_mitigation : 1; + + uint16_t link_proto; /**< What protocol version are we using? 0 for + * "none negotiated yet." */ + uint16_t idle_timeout; /**< How long can this connection sit with no + * circuits on it before we close it? Based on + * IDLE_CIRCUIT_TIMEOUT_{NON,}CANONICAL and + * on is_canonical, randomized. */ + or_handshake_state_t *handshake_state; /**< If we are setting this connection + * up, state information to do so. */ + + time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/ + + token_bucket_rw_t bucket; /**< Used for rate limiting when the connection is + * in state CONN_OPEN. */ + + /* + * Count the number of bytes flushed out on this orconn, and the number of + * bytes TLS actually sent - used for overhead estimation for scheduling. + */ + uint64_t bytes_xmitted, bytes_xmitted_by_tls; +}; + +#endif + diff --git a/src/or/or_handshake_certs_st.h b/src/or/or_handshake_certs_st.h new file mode 100644 index 0000000000..f05dd92617 --- /dev/null +++ b/src/or/or_handshake_certs_st.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef OR_HANDSHAKE_CERTS_ST +#define OR_HANDSHAKE_CERTS_ST + +/** Structure to hold all the certificates we've received on an OR connection + */ +struct or_handshake_certs_t { + /** True iff we originated this connection. */ + int started_here; + /** The cert for the 'auth' RSA key that's supposed to sign the AUTHENTICATE + * cell. Signed with the RSA identity key. */ + tor_x509_cert_t *auth_cert; + /** The cert for the 'link' RSA key that was used to negotiate the TLS + * connection. Signed with the RSA identity key. */ + tor_x509_cert_t *link_cert; + /** A self-signed identity certificate: the RSA identity key signed + * with itself. */ + tor_x509_cert_t *id_cert; + /** The Ed25519 signing key, signed with the Ed25519 identity key. */ + struct tor_cert_st *ed_id_sign; + /** A digest of the X509 link certificate for the TLS connection, signed + * with the Ed25519 siging key. */ + struct tor_cert_st *ed_sign_link; + /** The Ed25519 authentication key (that's supposed to sign an AUTHENTICATE + * cell) , signed with the Ed25519 siging key. */ + struct tor_cert_st *ed_sign_auth; + /** The Ed25519 identity key, crosssigned with the RSA identity key. */ + uint8_t *ed_rsa_crosscert; + /** The length of <b>ed_rsa_crosscert</b> in bytes */ + size_t ed_rsa_crosscert_len; +}; + +#endif + diff --git a/src/or/or_handshake_state_st.h b/src/or/or_handshake_state_st.h new file mode 100644 index 0000000000..4ee095d9af --- /dev/null +++ b/src/or/or_handshake_state_st.h @@ -0,0 +1,78 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef OR_HANDSHAKE_STATE_ST +#define OR_HANDSHAKE_STATE_ST + +/** Stores flags and information related to the portion of a v2/v3 Tor OR + * connection handshake that happens after the TLS handshake is finished. + */ +struct or_handshake_state_t { + /** When was the VERSIONS cell sent on this connection? Used to get + * an estimate of the skew in the returning NETINFO reply. */ + time_t sent_versions_at; + /** True iff we originated this connection */ + unsigned int started_here : 1; + /** True iff we have received and processed a VERSIONS cell. */ + unsigned int received_versions : 1; + /** True iff we have received and processed an AUTH_CHALLENGE cell */ + unsigned int received_auth_challenge : 1; + /** True iff we have received and processed a CERTS cell. */ + unsigned int received_certs_cell : 1; + /** True iff we have received and processed an AUTHENTICATE cell */ + unsigned int received_authenticate : 1; + + /* True iff we've received valid authentication to some identity. */ + unsigned int authenticated : 1; + unsigned int authenticated_rsa : 1; + unsigned int authenticated_ed25519 : 1; + + /* True iff we have sent a netinfo cell */ + unsigned int sent_netinfo : 1; + + /** The signing->ed25519 link certificate corresponding to the x509 + * certificate we used on the TLS connection (if this is a server-side + * connection). We make a copy of this here to prevent a race condition + * caused by TLS context rotation. */ + struct tor_cert_st *own_link_cert; + + /** True iff we should feed outgoing cells into digest_sent and + * digest_received respectively. + * + * From the server's side of the v3 handshake, we want to capture everything + * from the VERSIONS cell through and including the AUTH_CHALLENGE cell. + * From the client's, we want to capture everything from the VERSIONS cell + * through but *not* including the AUTHENTICATE cell. + * + * @{ */ + unsigned int digest_sent_data : 1; + unsigned int digest_received_data : 1; + /**@}*/ + + /** Identity RSA digest that we have received and authenticated for our peer + * on this connection. */ + uint8_t authenticated_rsa_peer_id[DIGEST_LEN]; + /** Identity Ed25519 public key that we have received and authenticated for + * our peer on this connection. */ + ed25519_public_key_t authenticated_ed25519_peer_id; + + /** Digests of the cells that we have sent or received as part of a V3 + * handshake. Used for making and checking AUTHENTICATE cells. + * + * @{ + */ + crypto_digest_t *digest_sent; + crypto_digest_t *digest_received; + /** @} */ + + /** Certificates that a connection initiator sent us in a CERTS cell; we're + * holding on to them until we get an AUTHENTICATE cell. + */ + or_handshake_certs_t *certs; +}; + +#endif + diff --git a/src/or/origin_circuit_st.h b/src/or/origin_circuit_st.h new file mode 100644 index 0000000000..fa41214d41 --- /dev/null +++ b/src/or/origin_circuit_st.h @@ -0,0 +1,235 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef ORIGIN_CIRCUIT_ST_H +#define ORIGIN_CIRCUIT_ST_H + +#include "or/or.h" + +#include "or/circuit_st.h" + +struct onion_queue_t; + +/** An origin_circuit_t holds data necessary to build and use a circuit. + */ +struct origin_circuit_t { + circuit_t base_; + + /** Linked list of AP streams (or EXIT streams if hidden service) + * associated with this circuit. */ + edge_connection_t *p_streams; + + /** Bytes read on this circuit since last call to + * control_event_circ_bandwidth_used(). Only used if we're configured + * to emit CIRC_BW events. */ + uint32_t n_read_circ_bw; + + /** Bytes written to on this circuit since last call to + * control_event_circ_bandwidth_used(). Only used if we're configured + * to emit CIRC_BW events. */ + uint32_t n_written_circ_bw; + + /** Total known-valid relay cell bytes since last call to + * control_event_circ_bandwidth_used(). Only used if we're configured + * to emit CIRC_BW events. */ + uint32_t n_delivered_read_circ_bw; + + /** Total written relay cell bytes since last call to + * control_event_circ_bandwidth_used(). Only used if we're configured + * to emit CIRC_BW events. */ + uint32_t n_delivered_written_circ_bw; + + /** Total overhead data in all known-valid relay data cells since last + * call to control_event_circ_bandwidth_used(). Only used if we're + * configured to emit CIRC_BW events. */ + uint32_t n_overhead_read_circ_bw; + + /** Total written overhead data in all relay data cells since last call to + * control_event_circ_bandwidth_used(). Only used if we're configured + * to emit CIRC_BW events. */ + uint32_t n_overhead_written_circ_bw; + + /** Build state for this circuit. It includes the intended path + * length, the chosen exit router, rendezvous information, etc. + */ + cpath_build_state_t *build_state; + /** The doubly-linked list of crypt_path_t entries, one per hop, + * for this circuit. This includes ciphers for each hop, + * integrity-checking digests for each hop, and package/delivery + * windows for each hop. + */ + crypt_path_t *cpath; + + /** Holds all rendezvous data on either client or service side. */ + rend_data_t *rend_data; + + /** Holds hidden service identifier on either client or service side. This + * is for both introduction and rendezvous circuit. */ + struct hs_ident_circuit_t *hs_ident; + + /** Holds the data that the entry guard system uses to track the + * status of the guard this circuit is using, and thereby to determine + * whether this circuit can be used. */ + struct circuit_guard_state_t *guard_state; + + /** Index into global_origin_circuit_list for this circuit. -1 if not + * present. */ + int global_origin_circuit_list_idx; + + /** How many more relay_early cells can we send on this circuit, according + * to the specification? */ + unsigned int remaining_relay_early_cells : 4; + + /** Set if this circuit is insanely old and we already informed the user */ + unsigned int is_ancient : 1; + + /** Set if this circuit has already been opened. Used to detect + * cannibalized circuits. */ + unsigned int has_opened : 1; + + /** + * Path bias state machine. Used to ensure integrity of our + * circuit building and usage accounting. See path_state_t + * for more details. + */ + path_state_bitfield_t path_state : 3; + + /* If this flag is set, we should not consider attaching any more + * connections to this circuit. */ + unsigned int unusable_for_new_conns : 1; + + /** + * Tristate variable to guard against pathbias miscounting + * due to circuit purpose transitions changing the decision + * of pathbias_should_count(). This variable is informational + * only. The current results of pathbias_should_count() are + * the official decision for pathbias accounting. + */ + uint8_t pathbias_shouldcount; +#define PATHBIAS_SHOULDCOUNT_UNDECIDED 0 +#define PATHBIAS_SHOULDCOUNT_IGNORED 1 +#define PATHBIAS_SHOULDCOUNT_COUNTED 2 + + /** For path probing. Store the temporary probe stream ID + * for response comparison */ + streamid_t pathbias_probe_id; + + /** For path probing. Store the temporary probe address nonce + * (in host byte order) for response comparison. */ + uint32_t pathbias_probe_nonce; + + /** Set iff this is a hidden-service circuit which has timed out + * according to our current circuit-build timeout, but which has + * been kept around because it might still succeed in connecting to + * its destination, and which is not a fully-connected rendezvous + * circuit. + * + * (We clear this flag for client-side rendezvous circuits when they + * are 'joined' to the other side's rendezvous circuit, so that + * connection_ap_handshake_attach_circuit can put client streams on + * the circuit. We also clear this flag for service-side rendezvous + * circuits when they are 'joined' to a client's rend circ, but only + * for symmetry with the client case. Client-side introduction + * circuits are closed when we get a joined rend circ, and + * service-side introduction circuits never have this flag set.) */ + unsigned int hs_circ_has_timed_out : 1; + + /** Set iff this circuit has been given a relaxed timeout because + * no circuits have opened. Used to prevent spamming logs. */ + unsigned int relaxed_timeout : 1; + + /** Set iff this is a service-side rendezvous circuit for which a + * new connection attempt has been launched. We consider launching + * a new service-side rend circ to a client when the previous one + * fails; now that we don't necessarily close a service-side rend + * circ when we launch a new one to the same client, this flag keeps + * us from launching two retries for the same failed rend circ. */ + unsigned int hs_service_side_rend_circ_has_been_relaunched : 1; + + /** What commands were sent over this circuit that decremented the + * RELAY_EARLY counter? This is for debugging task 878. */ + uint8_t relay_early_commands[MAX_RELAY_EARLY_CELLS_PER_CIRCUIT]; + + /** How many RELAY_EARLY cells have been sent over this circuit? This is + * for debugging task 878, too. */ + int relay_early_cells_sent; + + /** The next stream_id that will be tried when we're attempting to + * construct a new AP stream originating at this circuit. */ + streamid_t next_stream_id; + + /* The intro key replaces the hidden service's public key if purpose is + * S_ESTABLISH_INTRO or S_INTRO, provided that no unversioned rendezvous + * descriptor is used. */ + crypto_pk_t *intro_key; + + /** Quasi-global identifier for this circuit; used for control.c */ + /* XXXX NM This can get re-used after 2**32 circuits. */ + uint32_t global_identifier; + + /** True if we have associated one stream to this circuit, thereby setting + * the isolation parameters for this circuit. Note that this doesn't + * necessarily mean that we've <em>attached</em> any streams to the circuit: + * we may only have marked up this circuit during the launch process. + */ + unsigned int isolation_values_set : 1; + /** True iff any stream has <em>ever</em> been attached to this circuit. + * + * In a better world we could use timestamp_dirty for this, but + * timestamp_dirty is far too overloaded at the moment. + */ + unsigned int isolation_any_streams_attached : 1; + + /** A bitfield of ISO_* flags for every isolation field such that this + * circuit has had streams with more than one value for that field + * attached to it. */ + uint8_t isolation_flags_mixed; + + /** @name Isolation parameters + * + * If any streams have been associated with this circ (isolation_values_set + * == 1), and all streams associated with the circuit have had the same + * value for some field ((isolation_flags_mixed & ISO_FOO) == 0), then these + * elements hold the value for that field. + * + * Note again that "associated" is not the same as "attached": we + * preliminarily associate streams with a circuit while the circuit is being + * launched, so that we can tell whether we need to launch more circuits. + * + * @{ + */ + uint8_t client_proto_type; + uint8_t client_proto_socksver; + uint16_t dest_port; + tor_addr_t client_addr; + char *dest_address; + int session_group; + unsigned nym_epoch; + size_t socks_username_len; + uint8_t socks_password_len; + /* Note that the next two values are NOT NUL-terminated; see + socks_username_len and socks_password_len for their lengths. */ + char *socks_username; + char *socks_password; + /** Global identifier for the first stream attached here; used by + * ISO_STREAM. */ + uint64_t associated_isolated_stream_global_id; + /**@}*/ + /** A list of addr_policy_t for this circuit in particular. Used by + * adjust_exit_policy_from_exitpolicy_failure. + */ + smartlist_t *prepend_policy; + + /** How long do we wait before closing this circuit if it remains + * completely idle after it was built, in seconds? This value + * is randomized on a per-circuit basis from CircuitsAvailableTimoeut + * to 2*CircuitsAvailableTimoeut. */ + int circuit_idle_timeout; + +}; + +#endif + diff --git a/src/or/parsecommon.c b/src/or/parsecommon.c index 9bd00e17ce..7c9cf88f95 100644 --- a/src/or/parsecommon.c +++ b/src/or/parsecommon.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,9 +6,15 @@ * \brief Common code to parse and validate various type of descriptors. **/ -#include "parsecommon.h" -#include "torlog.h" -#include "util_format.h" +#include "or/parsecommon.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/encoding/binascii.h" +#include "lib/container/smartlist.h" +#include "lib/string/util_string.h" +#include "lib/string/printf.h" + +#include <string.h> #define MIN_ANNOTATION A_PURPOSE #define MAX_ANNOTATION A_UNKNOWN_ @@ -448,4 +454,3 @@ find_all_by_keyword(const smartlist_t *s, directory_keyword k) }); return out; } - diff --git a/src/or/parsecommon.h b/src/or/parsecommon.h index d33faf8ec7..7fe192c2a5 100644 --- a/src/or/parsecommon.h +++ b/src/or/parsecommon.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,9 +9,10 @@ #ifndef TOR_PARSECOMMON_H #define TOR_PARSECOMMON_H -#include "container.h" -#include "crypto.h" -#include "memarea.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/memarea/memarea.h" + +struct smartlist_t; /** Enumeration of possible token types. The ones starting with K_ correspond * to directory 'keywords'. A_ is for an annotation, R or C is related to @@ -299,7 +300,7 @@ void token_clear(directory_token_t *tok); int tokenize_string(memarea_t *area, const char *start, const char *end, - smartlist_t *out, + struct smartlist_t *out, token_rule_t *table, int flags); directory_token_t *get_next_token(memarea_t *area, @@ -307,16 +308,16 @@ directory_token_t *get_next_token(memarea_t *area, const char *eos, token_rule_t *table); -directory_token_t *find_by_keyword_(smartlist_t *s, +directory_token_t *find_by_keyword_(struct smartlist_t *s, directory_keyword keyword, const char *keyword_str); #define find_by_keyword(s, keyword) \ find_by_keyword_((s), (keyword), #keyword) -directory_token_t *find_opt_by_keyword(const smartlist_t *s, +directory_token_t *find_opt_by_keyword(const struct smartlist_t *s, directory_keyword keyword); -smartlist_t * find_all_by_keyword(const smartlist_t *s, directory_keyword k); +struct smartlist_t * find_all_by_keyword(const struct smartlist_t *s, + directory_keyword k); #endif /* !defined(TOR_PARSECOMMON_H) */ - diff --git a/src/or/periodic.c b/src/or/periodic.c index 92fa677f8f..d379325f50 100644 --- a/src/or/periodic.c +++ b/src/or/periodic.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,11 +11,11 @@ * that they fire. See periodic_events[] in main.c for examples. */ -#include "or.h" -#include "compat_libevent.h" -#include "config.h" -#include "main.h" -#include "periodic.h" +#include "or/or.h" +#include "common/compat_libevent.h" +#include "or/config.h" +#include "or/main.h" +#include "or/periodic.h" /** We disable any interval greater than this number of seconds, on the * grounds that it is probably an absolute time mistakenly passed in as a diff --git a/src/or/periodic.h b/src/or/periodic.h index e8208b2475..4c8c3c96cc 100644 --- a/src/or/periodic.h +++ b/src/or/periodic.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PERIODIC_H diff --git a/src/or/policies.c b/src/or/policies.c index 1210ca687d..0f52d6bf15 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,19 +17,26 @@ #define POLICIES_PRIVATE -#include "or.h" -#include "bridges.h" -#include "config.h" -#include "dirserv.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "router.h" -#include "routerparse.h" -#include "geoip.h" +#include "or/or.h" +#include "or/bridges.h" +#include "or/config.h" +#include "or/dirserv.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/router.h" +#include "or/routerparse.h" +#include "or/geoip.h" #include "ht.h" +#include "or/dir_server_st.h" +#include "or/microdesc_st.h" +#include "or/node_st.h" +#include "or/port_cfg_st.h" +#include "or/routerinfo_st.h" +#include "or/routerstatus_st.h" + /** Policy that addresses for incoming SOCKS connections must match. */ static smartlist_t *socks_policy = NULL; /** Policy that addresses for incoming directory connections must match. */ diff --git a/src/or/policies.h b/src/or/policies.h index 4879acdd8d..d4379c0e7a 100644 --- a/src/or/policies.h +++ b/src/or/policies.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/port_cfg_st.h b/src/or/port_cfg_st.h new file mode 100644 index 0000000000..86a3b963bc --- /dev/null +++ b/src/or/port_cfg_st.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef PORT_CFG_ST_H +#define PORT_CFG_ST_H + +#include "or/entry_port_cfg_st.h" +#include "or/server_port_cfg_st.h" + +/** Configuration for a single port that we're listening on. */ +struct port_cfg_t { + tor_addr_t addr; /**< The actual IP to listen on, if !is_unix_addr. */ + int port; /**< The configured port, or CFG_AUTO_PORT to tell Tor to pick its + * own port. */ + uint8_t type; /**< One of CONN_TYPE_*_LISTENER */ + unsigned is_unix_addr : 1; /**< True iff this is an AF_UNIX address. */ + + unsigned is_group_writable : 1; + unsigned is_world_writable : 1; + unsigned relax_dirmode_check : 1; + + entry_port_cfg_t entry_cfg; + + server_port_cfg_t server_cfg; + + /* Unix sockets only: */ + /** Path for an AF_UNIX address */ + char unix_addr[FLEXIBLE_ARRAY_MEMBER]; +}; + +#endif + diff --git a/src/or/proto_cell.c b/src/or/proto_cell.c index 75eb2a7e7f..41554bd1b0 100644 --- a/src/or/proto_cell.c +++ b/src/or/proto_cell.c @@ -1,14 +1,16 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "buffers.h" -#include "proto_cell.h" +#include "or/or.h" +#include "lib/container/buffers.h" +#include "or/proto_cell.h" -#include "connection_or.h" +#include "or/connection_or.h" + +#include "or/var_cell_st.h" /** True iff the cell command <b>command</b> is one that implies a * variable-length cell in Tor link protocol <b>linkproto</b>. */ diff --git a/src/or/proto_cell.h b/src/or/proto_cell.h index bbc14b9a02..b29645e41d 100644 --- a/src/or/proto_cell.h +++ b/src/or/proto_cell.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PROTO_CELL_H diff --git a/src/or/proto_control0.c b/src/or/proto_control0.c index c17ba34948..34e7ddb8d9 100644 --- a/src/or/proto_control0.c +++ b/src/or/proto_control0.c @@ -1,12 +1,12 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "buffers.h" -#include "proto_control0.h" +#include "or/or.h" +#include "lib/container/buffers.h" +#include "or/proto_control0.h" /** Return 1 iff buf looks more like it has an (obsolete) v0 controller * command on it than any valid v1 controller command. */ diff --git a/src/or/proto_control0.h b/src/or/proto_control0.h index 0cc8eacad0..b80dc6c8f8 100644 --- a/src/or/proto_control0.h +++ b/src/or/proto_control0.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PROTO_CONTROL0_H diff --git a/src/or/proto_ext_or.c b/src/or/proto_ext_or.c index 057cf109ec..f30d876231 100644 --- a/src/or/proto_ext_or.c +++ b/src/or/proto_ext_or.c @@ -1,13 +1,13 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "buffers.h" -#include "ext_orport.h" -#include "proto_ext_or.h" +#include "or/or.h" +#include "lib/container/buffers.h" +#include "or/ext_orport.h" +#include "or/proto_ext_or.h" /** The size of the header of an Extended ORPort message: 2 bytes for * COMMAND, 2 bytes for BODYLEN */ diff --git a/src/or/proto_ext_or.h b/src/or/proto_ext_or.h index cc504d18e3..5366ec4471 100644 --- a/src/or/proto_ext_or.h +++ b/src/or/proto_ext_or.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PROTO_EXT_OR_H diff --git a/src/or/proto_http.c b/src/or/proto_http.c index 3762429e1e..ecc669e3a4 100644 --- a/src/or/proto_http.c +++ b/src/or/proto_http.c @@ -1,13 +1,13 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define PROTO_HTTP_PRIVATE -#include "or.h" -#include "buffers.h" -#include "proto_http.h" +#include "or/or.h" +#include "lib/container/buffers.h" +#include "or/proto_http.h" /** Return true if <b>cmd</b> looks like a HTTP (proxy) request. */ int diff --git a/src/or/proto_http.h b/src/or/proto_http.h index 805686070f..587e435ede 100644 --- a/src/or/proto_http.h +++ b/src/or/proto_http.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PROTO_HTTP_H diff --git a/src/or/proto_socks.c b/src/or/proto_socks.c index 57a7d1cd64..94603c2609 100644 --- a/src/or/proto_socks.c +++ b/src/or/proto_socks.c @@ -1,18 +1,20 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "addressmap.h" -#include "buffers.h" -#include "control.h" -#include "config.h" -#include "crypto_util.h" -#include "ext_orport.h" -#include "proto_socks.h" -#include "reasons.h" +#include "or/or.h" +#include "or/addressmap.h" +#include "lib/container/buffers.h" +#include "or/control.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/ext_orport.h" +#include "or/proto_socks.h" +#include "or/reasons.h" + +#include "or/socks_request_st.h" static void socks_request_set_socks5_error(socks_request_t *req, socks5_reply_status_t reason); diff --git a/src/or/proto_socks.h b/src/or/proto_socks.h index 02e0aca7e9..1624d7b060 100644 --- a/src/or/proto_socks.h +++ b/src/or/proto_socks.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PROTO_SOCKS_H diff --git a/src/or/protover.c b/src/or/protover.c index 0e8902196d..f63c134565 100644 --- a/src/or/protover.c +++ b/src/or/protover.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -23,9 +23,9 @@ #define PROTOVER_PRIVATE -#include "or.h" -#include "protover.h" -#include "routerparse.h" +#include "or/or.h" +#include "or/protover.h" +#include "or/routerparse.h" #ifndef HAVE_RUST diff --git a/src/or/protover.h b/src/or/protover.h index c46a13de66..7319d2f8c4 100644 --- a/src/or/protover.h +++ b/src/or/protover.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,7 +9,10 @@ #ifndef TOR_PROTOVER_H #define TOR_PROTOVER_H -#include "container.h" +#include <stdbool.h> +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" +struct smartlist_t; /** The first version of Tor that included "proto" entries in its * descriptors. Authorities should use this to decide whether to @@ -47,7 +50,7 @@ int protover_all_supported(const char *s, char **missing); int protover_is_supported_here(protocol_type_t pr, uint32_t ver); const char *protover_get_supported_protocols(void); -char *protover_compute_vote(const smartlist_t *list_of_proto_strings, +char *protover_compute_vote(const struct smartlist_t *list_of_proto_strings, int threshold); const char *protover_compute_for_old_tor(const char *version); int protocol_list_supports_protocol(const char *list, protocol_type_t tp, @@ -75,12 +78,12 @@ typedef struct proto_entry_t { */ char *name; /** Smartlist of proto_range_t */ - smartlist_t *ranges; + struct smartlist_t *ranges; } proto_entry_t; #if !defined(HAVE_RUST) && defined(TOR_UNIT_TESTS) -STATIC smartlist_t *parse_protocol_list(const char *s); -STATIC char *encode_protocol_list(const smartlist_t *sl); +STATIC struct smartlist_t *parse_protocol_list(const char *s); +STATIC char *encode_protocol_list(const struct smartlist_t *sl); STATIC const char *protocol_type_to_str(protocol_type_t pr); STATIC int str_to_protocol_type(const char *s, protocol_type_t *pr_out); STATIC void proto_entry_free_(proto_entry_t *entry); @@ -92,4 +95,3 @@ STATIC void proto_entry_free_(proto_entry_t *entry); #endif /* defined(PROTOVER_PRIVATE) */ #endif /* !defined(TOR_PROTOVER_H) */ - diff --git a/src/or/protover_rust.c b/src/or/protover_rust.c index 99304f8b51..bd2f88b98e 100644 --- a/src/or/protover_rust.c +++ b/src/or/protover_rust.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* @@ -7,8 +7,8 @@ * and safe translation/handling between the Rust/C boundary. */ -#include "or.h" -#include "protover.h" +#include "or/or.h" +#include "or/protover.h" #ifdef HAVE_RUST diff --git a/src/or/reasons.c b/src/or/reasons.c index ce1259b8f3..b9b7a7db8b 100644 --- a/src/or/reasons.c +++ b/src/or/reasons.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,9 +14,9 @@ * to another. **/ -#include "or.h" -#include "config.h" -#include "reasons.h" +#include "or/or.h" +#include "or/config.h" +#include "or/reasons.h" /***************************** Edge (stream) reasons **********************/ diff --git a/src/or/reasons.h b/src/or/reasons.h index 3d6ba8fc83..8f4d7c6bcc 100644 --- a/src/or/reasons.h +++ b/src/or/reasons.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,6 +12,8 @@ #ifndef TOR_REASONS_H #define TOR_REASONS_H +#include "common/socks5_status.h" + const char *stream_end_reason_to_control_string(int reason); const char *stream_end_reason_to_string(int reason); socks5_reply_status_t stream_end_reason_to_socks5_response(int reason); @@ -29,4 +31,3 @@ const char *bandwidth_weight_rule_to_string(enum bandwidth_weight_rule_t rule); const char *end_reason_to_http_connect_response_line(int endreason); #endif /* !defined(TOR_REASONS_H) */ - diff --git a/src/or/relay.c b/src/or/relay.c index 50f59d6b99..e8e1762b40 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -46,40 +46,55 @@ **/ #define RELAY_PRIVATE -#include "or.h" -#include "addressmap.h" -#include "backtrace.h" -#include "buffers.h" -#include "channel.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "compress.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "geoip.h" -#include "hs_cache.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "onion.h" -#include "policies.h" -#include "reasons.h" -#include "relay.h" -#include "relay_crypto.h" -#include "rendcache.h" -#include "rendcommon.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "scheduler.h" -#include "rephist.h" +#include "or/or.h" +#include "or/addressmap.h" +#include "lib/err/backtrace.h" +#include "lib/container/buffers.h" +#include "or/channel.h" +#include "or/circpathbias.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "lib/compress/compress.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/connection_or.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/directory.h" +#include "or/geoip.h" +#include "or/hs_cache.h" +#include "or/main.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/onion.h" +#include "or/policies.h" +#include "or/reasons.h" +#include "or/relay.h" +#include "or/relay_crypto.h" +#include "or/rendcache.h" +#include "or/rendcommon.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/scheduler.h" +#include "or/rephist.h" + +#include "or/cell_st.h" +#include "or/cell_queue_st.h" +#include "or/cpath_build_state_st.h" +#include "or/dir_connection_st.h" +#include "or/destroy_cell_queue_st.h" +#include "or/entry_connection_st.h" +#include "or/extend_info_st.h" +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" +#include "or/routerinfo_st.h" +#include "or/socks_request_st.h" + +#include "lib/intmath/weakrng.h" static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction, @@ -1752,8 +1767,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, circuit_resume_edge_reading(circ, layer_hint); /* We count circuit-level sendme's as valid delivered data because - * they are rate limited. Note that we cannot count stream - * sendme's because the other end could send as many as they like. + * they are rate limited. */ if (CIRCUIT_IS_ORIGIN(circ)) { circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), @@ -1783,6 +1797,27 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, rh.stream_id); return 0; } + + /* Don't allow the other endpoint to request more than our maximum + * (i.e. initial) stream SENDME window worth of data. Well-behaved + * stock clients will not request more than this max (as per the check + * in the while loop of connection_edge_consider_sending_sendme()). + */ + if (conn->package_window + STREAMWINDOW_INCREMENT > + STREAMWINDOW_START_MAX) { + static struct ratelim_t stream_warn_ratelim = RATELIM_INIT(600); + log_fn_ratelim(&stream_warn_ratelim, LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Unexpected stream sendme cell. Closing circ (window %d).", + conn->package_window); + return -END_CIRC_REASON_TORPROTOCOL; + } + + /* At this point, the stream sendme is valid */ + if (CIRCUIT_IS_ORIGIN(circ)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), + rh.length); + } + conn->package_window += STREAMWINDOW_INCREMENT; log_debug(domain,"stream-level sendme, packagewindow now %d.", conn->package_window); @@ -3051,4 +3086,3 @@ circuit_queue_streams_are_blocked(circuit_t *circ) return circ->streams_blocked_on_p_chan; } } - diff --git a/src/or/relay.h b/src/or/relay.h index ce0969b46c..db7f17b96c 100644 --- a/src/or/relay.h +++ b/src/or/relay.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/relay_crypto.c b/src/or/relay_crypto.c index 530c8e5828..6682cd86f4 100644 --- a/src/or/relay_crypto.c +++ b/src/or/relay_crypto.c @@ -4,12 +4,17 @@ * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "config.h" -#include "crypto_util.h" -#include "hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN -#include "relay.h" -#include "relay_crypto.h" +#include "or/or.h" +#include "or/circuitlist.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN +#include "or/relay.h" +#include "or/relay_crypto.h" + +#include "or/cell_st.h" +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" /** Update digest from the payload of cell. Assign integrity part to * cell. diff --git a/src/or/relay_crypto.h b/src/or/relay_crypto.h index 66ae02cee9..67da93344f 100644 --- a/src/or/relay_crypto.h +++ b/src/or/relay_crypto.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/relay_crypto_st.h b/src/or/relay_crypto_st.h new file mode 100644 index 0000000000..4e23f4e404 --- /dev/null +++ b/src/or/relay_crypto_st.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef RELAY_CRYPTO_ST_H +#define RELAY_CRYPTO_ST_H + +struct relay_crypto_t { + /* crypto environments */ + /** Encryption key and counter for cells heading towards the OR at this + * step. */ + crypto_cipher_t *f_crypto; + /** Encryption key and counter for cells heading back from the OR at this + * step. */ + crypto_cipher_t *b_crypto; + + /** Digest state for cells heading towards the OR at this step. */ + crypto_digest_t *f_digest; /* for integrity checking */ + /** Digest state for cells heading away from the OR at this step. */ + crypto_digest_t *b_digest; + +}; + +#endif + diff --git a/src/or/rend_authorized_client_st.h b/src/or/rend_authorized_client_st.h new file mode 100644 index 0000000000..7ccf9771e1 --- /dev/null +++ b/src/or/rend_authorized_client_st.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef REND_AUTHORIZED_CLIENT_ST_H +#define REND_AUTHORIZED_CLIENT_ST_H + +/** Hidden-service side configuration of client authorization. */ +struct rend_authorized_client_t { + char *client_name; + uint8_t descriptor_cookie[REND_DESC_COOKIE_LEN]; + crypto_pk_t *client_key; +}; + +#endif + diff --git a/src/or/rend_encoded_v2_service_descriptor_st.h b/src/or/rend_encoded_v2_service_descriptor_st.h new file mode 100644 index 0000000000..0555ef6728 --- /dev/null +++ b/src/or/rend_encoded_v2_service_descriptor_st.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H +#define REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H + +/** ASCII-encoded v2 hidden service descriptor. */ +struct rend_encoded_v2_service_descriptor_t { + char desc_id[DIGEST_LEN]; /**< Descriptor ID. */ + char *desc_str; /**< Descriptor string. */ +}; + +#endif + diff --git a/src/or/rend_intro_point_st.h b/src/or/rend_intro_point_st.h new file mode 100644 index 0000000000..f707c7aaaf --- /dev/null +++ b/src/or/rend_intro_point_st.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef REND_INTRO_POINT_ST_H +#define REND_INTRO_POINT_ST_H + +/** Introduction point information. Used both in rend_service_t (on + * the service side) and in rend_service_descriptor_t (on both the + * client and service side). */ +struct rend_intro_point_t { + extend_info_t *extend_info; /**< Extend info for connecting to this + * introduction point via a multi-hop path. */ + crypto_pk_t *intro_key; /**< Introduction key that replaces the service + * key, if this descriptor is V2. */ + + /** (Client side only) Flag indicating that a timeout has occurred + * after sending an INTRODUCE cell to this intro point. After a + * timeout, an intro point should not be tried again during the same + * hidden service connection attempt, but it may be tried again + * during a future connection attempt. */ + unsigned int timed_out : 1; + + /** (Client side only) The number of times we have failed to build a + * circuit to this intro point for some reason other than our + * circuit-build timeout. See also MAX_INTRO_POINT_REACHABILITY_FAILURES. */ + unsigned int unreachable_count : 3; + + /** (Service side only) Flag indicating that this intro point was + * included in the last HS descriptor we generated. */ + unsigned int listed_in_last_desc : 1; + + /** (Service side only) A replay cache recording the RSA-encrypted parts + * of INTRODUCE2 cells this intro point's circuit has received. This is + * used to prevent replay attacks. */ + replaycache_t *accepted_intro_rsa_parts; + + /** (Service side only) Count of INTRODUCE2 cells accepted from this + * intro point. + */ + int accepted_introduce2_count; + + /** (Service side only) Maximum number of INTRODUCE2 cells that this IP + * will accept. This is a random value between + * INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS and + * INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS. */ + int max_introductions; + + /** (Service side only) The time at which this intro point was first + * published, or -1 if this intro point has not yet been + * published. */ + time_t time_published; + + /** (Service side only) The time at which this intro point should + * (start to) expire, or -1 if we haven't decided when this intro + * point should expire. */ + time_t time_to_expire; + + /** (Service side only) The amount of circuit creation we've made to this + * intro point. This is incremented every time we do a circuit relaunch on + * this object which is triggered when the circuit dies but the node is + * still in the consensus. After MAX_INTRO_POINT_CIRCUIT_RETRIES, we give + * up on it. */ + unsigned int circuit_retries; + + /** (Service side only) Set if this intro point has an established circuit + * and unset if it doesn't. */ + unsigned int circuit_established:1; +}; + +#endif + diff --git a/src/or/rend_service_descriptor_st.h b/src/or/rend_service_descriptor_st.h new file mode 100644 index 0000000000..8ea8a62305 --- /dev/null +++ b/src/or/rend_service_descriptor_st.h @@ -0,0 +1,34 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef REND_SERVICE_DESCRIPTOR_ST_H +#define REND_SERVICE_DESCRIPTOR_ST_H + +#define REND_PROTOCOL_VERSION_BITMASK_WIDTH 16 + +/** Information used to connect to a hidden service. Used on both the + * service side and the client side. */ +struct rend_service_descriptor_t { + crypto_pk_t *pk; /**< This service's public key. */ + int version; /**< Version of the descriptor format: 0 or 2. */ + time_t timestamp; /**< Time when the descriptor was generated. */ + /** Bitmask: which introduce/rendezvous protocols are supported? + * (We allow bits '0', '1', '2' and '3' to be set.) */ + unsigned protocols : REND_PROTOCOL_VERSION_BITMASK_WIDTH; + /** List of the service's introduction points. Elements are removed if + * introduction attempts fail. */ + smartlist_t *intro_nodes; + /** Has descriptor been uploaded to all hidden service directories? */ + int all_uploads_performed; + /** List of hidden service directories to which an upload request for + * this descriptor could be sent. Smartlist exists only when at least one + * of the previous upload requests failed (otherwise it's not important + * to know which uploads succeeded and which not). */ + smartlist_t *successful_uploads; +}; + +#endif + diff --git a/src/or/rendcache.c b/src/or/rendcache.c index d27e1c293f..c18920154e 100644 --- a/src/or/rendcache.c +++ b/src/or/rendcache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,13 +7,17 @@ **/ #define RENDCACHE_PRIVATE -#include "rendcache.h" +#include "or/rendcache.h" -#include "config.h" -#include "rephist.h" -#include "routerlist.h" -#include "routerparse.h" -#include "rendcommon.h" +#include "or/config.h" +#include "or/rephist.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/rendcommon.h" + +#include "or/extend_info_st.h" +#include "or/rend_intro_point_st.h" +#include "or/rend_service_descriptor_st.h" /** Map from service id (as generated by rend_get_service_id) to * rend_cache_entry_t. */ @@ -908,9 +912,7 @@ rend_cache_store_v2_desc_as_client(const char *desc, if (n_intro_points <= 0) { log_warn(LD_REND, "Failed to parse introduction points. Either the " "service has published a corrupt descriptor or you have " - "provided invalid authorization data, or (maybe!) the " - "server is deliberately serving broken data in an attempt " - "to crash you with bug 21018."); + "provided invalid authorization data."); goto err; } else if (n_intro_points > MAX_INTRO_POINTS) { log_warn(LD_REND, "Found too many introduction points on a hidden " diff --git a/src/or/rendcache.h b/src/or/rendcache.h index 8b6fd5b671..bb075409ec 100644 --- a/src/or/rendcache.h +++ b/src/or/rendcache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,8 @@ #ifndef TOR_RENDCACHE_H #define TOR_RENDCACHE_H -#include "or.h" -#include "rendcommon.h" +#include "or/or.h" +#include "or/rendcommon.h" /** How old do we let hidden service descriptors get before discarding * them as too old? */ diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 7ef12a4faf..1da695706c 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,31 +7,41 @@ * \brief Client code to access location-hidden services. **/ -#include "or.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "hs_circuit.h" -#include "hs_client.h" -#include "hs_common.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "relay.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerset.h" +#include "or/or.h" +#include "or/circpathbias.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/directory.h" +#include "or/hs_circuit.h" +#include "or/hs_client.h" +#include "or/hs_common.h" +#include "or/main.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/relay.h" +#include "or/rendclient.h" +#include "or/rendcommon.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerset.h" + +#include "or/cpath_build_state_st.h" +#include "or/crypt_path_st.h" +#include "or/dir_connection_st.h" +#include "or/entry_connection_st.h" +#include "or/extend_info_st.h" +#include "or/origin_circuit_st.h" +#include "or/rend_intro_point_st.h" +#include "or/rend_service_descriptor_st.h" +#include "or/routerstatus_st.h" static extend_info_t *rend_client_get_random_intro_impl( const rend_cache_entry_t *rend_query, diff --git a/src/or/rendclient.h b/src/or/rendclient.h index e8495ce09c..77395d6cb8 100644 --- a/src/or/rendclient.h +++ b/src/or/rendclient.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #ifndef TOR_RENDCLIENT_H #define TOR_RENDCLIENT_H -#include "rendcache.h" +#include "or/rendcache.h" void rend_client_purge_state(void); diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index f3fa2f64d1..1eadbd602c 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,25 +10,36 @@ #define RENDCOMMON_PRIVATE -#include "or.h" -#include "circuitbuild.h" -#include "circuituse.h" -#include "config.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "hs_client.h" -#include "hs_common.h" -#include "hs_intropoint.h" -#include "networkstatus.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendmid.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" +#include "or/or.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/hs_client.h" +#include "or/hs_common.h" +#include "or/hs_intropoint.h" +#include "or/networkstatus.h" +#include "or/rendclient.h" +#include "or/rendcommon.h" +#include "or/rendmid.h" +#include "or/rendservice.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerparse.h" + +#include "or/cpath_build_state_st.h" +#include "or/crypt_path_st.h" +#include "or/extend_info_st.h" +#include "or/networkstatus_st.h" +#include "or/origin_circuit_st.h" +#include "or/rend_encoded_v2_service_descriptor_st.h" +#include "or/rend_intro_point_st.h" +#include "or/rend_service_descriptor_st.h" +#include "or/routerstatus_st.h" /** Return 0 if one and two are the same service ids, else -1 or 1 */ int diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h index 1ed0f62609..4ea35f88c2 100644 --- a/src/or/rendcommon.h +++ b/src/or/rendcommon.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/rendmid.c b/src/or/rendmid.c index c4a34ca62c..56b65079ab 100644 --- a/src/or/rendmid.c +++ b/src/or/rendmid.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,18 +7,20 @@ * \brief Implement introductions points and rendezvous points. **/ -#include "or.h" -#include "channel.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "crypto.h" -#include "dos.h" -#include "relay.h" -#include "rendmid.h" -#include "rephist.h" -#include "hs_circuitmap.h" -#include "hs_intropoint.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto.h" +#include "or/dos.h" +#include "or/relay.h" +#include "or/rendmid.h" +#include "or/rephist.h" +#include "or/hs_circuitmap.h" +#include "or/hs_intropoint.h" + +#include "or/or_circuit_st.h" /** Respond to an ESTABLISH_INTRO cell by checking the signed data and * setting the circuit's purpose and service pk digest. diff --git a/src/or/rendmid.h b/src/or/rendmid.h index 6cc1fc8d95..907a0c6a73 100644 --- a/src/or/rendmid.h +++ b/src/or/rendmid.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 92c323b10d..b2023c72cb 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,32 +9,45 @@ #define RENDSERVICE_PRIVATE -#include "or.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "hs_common.h" -#include "hs_config.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "router.h" -#include "relay.h" -#include "rephist.h" -#include "replaycache.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" +#include "or/or.h" +#include "or/circpathbias.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/directory.h" +#include "or/hs_common.h" +#include "or/hs_config.h" +#include "or/main.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/rendclient.h" +#include "or/rendcommon.h" +#include "or/rendservice.h" +#include "or/router.h" +#include "or/relay.h" +#include "or/rephist.h" +#include "or/replaycache.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/routerset.h" + +#include "or/cpath_build_state_st.h" +#include "or/crypt_path_st.h" +#include "or/crypt_path_reference_st.h" +#include "or/edge_connection_st.h" +#include "or/extend_info_st.h" +#include "or/networkstatus_st.h" +#include "or/origin_circuit_st.h" +#include "or/rend_authorized_client_st.h" +#include "or/rend_encoded_v2_service_descriptor_st.h" +#include "or/rend_intro_point_st.h" +#include "or/rend_service_descriptor_st.h" +#include "or/routerstatus_st.h" struct rend_service_t; static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro, diff --git a/src/or/rendservice.h b/src/or/rendservice.h index cc872ab575..b2644d8b40 100644 --- a/src/or/rendservice.h +++ b/src/or/rendservice.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,8 @@ #ifndef TOR_RENDSERVICE_H #define TOR_RENDSERVICE_H -#include "or.h" -#include "hs_service.h" +#include "or/or.h" +#include "or/hs_service.h" typedef struct rend_intro_cell_s rend_intro_cell_t; diff --git a/src/or/rephist.c b/src/or/rephist.c index c7117bad63..907b01d68e 100644 --- a/src/or/rephist.c +++ b/src/or/rephist.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -74,20 +74,28 @@ * (The "rephist" name originally stood for "reputation and history". ) **/ -#include "or.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "crypto_rand.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" +#include "or/or.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerlist.h" #include "ht.h" -#include "channelpadding.h" -#include "connection_or.h" -#include "statefile.h" +#include "or/channelpadding.h" +#include "or/connection_or.h" +#include "or/statefile.h" + +#include "or/networkstatus_st.h" +#include "or/or_circuit_st.h" + +#include "lib/container/bloomfilt.h" +#include "lib/container/order.h" +#include "lib/math/fp.h" +#include "lib/math/laplace.h" static void bw_arrays_init(void); static void predicted_ports_alloc(void); @@ -3205,4 +3213,3 @@ rep_hist_free_all(void) tor_assert_nonfatal(rephist_total_alloc == 0); tor_assert_nonfatal_once(rephist_total_num == 0); } - diff --git a/src/or/rephist.h b/src/or/rephist.h index 5072721592..06a5e48211 100644 --- a/src/or/rephist.h +++ b/src/or/rephist.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/replaycache.c b/src/or/replaycache.c index a9a6709937..b5cc6a2823 100644 --- a/src/or/replaycache.c +++ b/src/or/replaycache.c @@ -1,4 +1,4 @@ - /* Copyright (c) 2012-2017, The Tor Project, Inc. */ + /* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,8 +21,8 @@ #define REPLAYCACHE_PRIVATE -#include "or.h" -#include "replaycache.h" +#include "or/or.h" +#include "or/replaycache.h" /** Free the replaycache r and all of its entries. */ diff --git a/src/or/replaycache.h b/src/or/replaycache.h index 81a8d907fd..d8a9929120 100644 --- a/src/or/replaycache.h +++ b/src/or/replaycache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/router.c b/src/or/router.c index 3879863e82..c7fed1f021 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1,43 +1,56 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTER_PRIVATE -#include "or.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "crypto_curve25519.h" -#include "directory.h" -#include "dirserv.h" -#include "dns.h" -#include "geoip.h" -#include "hibernate.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "protover.h" -#include "relay.h" -#include "rephist.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "routerparse.h" -#include "statefile.h" -#include "torcert.h" -#include "transports.h" -#include "routerset.h" - -#include "dirauth/mode.h" +#include "or/or.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "or/directory.h" +#include "or/dirserv.h" +#include "or/dns.h" +#include "or/geoip.h" +#include "or/hibernate.h" +#include "or/main.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/protover.h" +#include "or/relay.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerkeys.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/statefile.h" +#include "or/torcert.h" +#include "or/transports.h" +#include "or/routerset.h" + +#include "or/dirauth/mode.h" + +#include "or/authority_cert_st.h" +#include "or/crypt_path_st.h" +#include "or/dir_connection_st.h" +#include "or/dir_server_st.h" +#include "or/extend_info_st.h" +#include "or/extrainfo_st.h" +#include "or/node_st.h" +#include "or/origin_circuit_st.h" +#include "or/port_cfg_st.h" +#include "or/routerinfo_st.h" + +#include "lib/osinfo/uname.h" /** * \file router.c @@ -3813,4 +3826,3 @@ router_get_all_orports(const routerinfo_t *ri) fake_node.ri = (routerinfo_t *)ri; return node_get_all_orports(&fake_node); } - diff --git a/src/or/router.h b/src/or/router.h index 752f2f2dbe..54f61c45a6 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #ifndef TOR_ROUTER_H #define TOR_ROUTER_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" #define TOR_ROUTERINFO_ERROR_NO_EXT_ADDR (-1) #define TOR_ROUTERINFO_ERROR_CANNOT_PARSE (-2) diff --git a/src/or/routerinfo_st.h b/src/or/routerinfo_st.h new file mode 100644 index 0000000000..feb3b41fc6 --- /dev/null +++ b/src/or/routerinfo_st.h @@ -0,0 +1,107 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef ROUTERINFO_ST_H +#define ROUTERINFO_ST_H + +#include "or/signed_descriptor_st.h" + +/** Information about another onion router in the network. */ +struct routerinfo_t { + signed_descriptor_t cache_info; + char *nickname; /**< Human-readable OR name. */ + + uint32_t addr; /**< IPv4 address of OR, in host order. */ + uint16_t or_port; /**< Port for TLS connections. */ + uint16_t dir_port; /**< Port for HTTP directory connections. */ + + /** A router's IPv6 address, if it has one. */ + /* XXXXX187 Actually these should probably be part of a list of addresses, + * not just a special case. Use abstractions to access these; don't do it + * directly. */ + tor_addr_t ipv6_addr; + uint16_t ipv6_orport; + + crypto_pk_t *onion_pkey; /**< Public RSA key for onions. */ + crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */ + /** Public curve25519 key for onions */ + curve25519_public_key_t *onion_curve25519_pkey; + /** What's the earliest expiration time on all the certs in this + * routerinfo? */ + time_t cert_expiration_time; + + char *platform; /**< What software/operating system is this OR using? */ + + char *protocol_list; /**< Encoded list of subprotocol versions supported + * by this OR */ + + /* link info */ + uint32_t bandwidthrate; /**< How many bytes does this OR add to its token + * bucket per second? */ + uint32_t bandwidthburst; /**< How large is this OR's token bucket? */ + /** How many bytes/s is this router known to handle? */ + uint32_t bandwidthcapacity; + smartlist_t *exit_policy; /**< What streams will this OR permit + * to exit on IPv4? NULL for 'reject *:*'. */ + /** What streams will this OR permit to exit on IPv6? + * NULL for 'reject *:*' */ + struct short_policy_t *ipv6_exit_policy; + long uptime; /**< How many seconds the router claims to have been up */ + smartlist_t *declared_family; /**< Nicknames of router which this router + * claims are its family. */ + char *contact_info; /**< Declared contact info for this router. */ + unsigned int is_hibernating:1; /**< Whether the router claims to be + * hibernating */ + unsigned int caches_extra_info:1; /**< Whether the router says it caches and + * serves extrainfo documents. */ + unsigned int allow_single_hop_exits:1; /**< Whether the router says + * it allows single hop exits. */ + + unsigned int wants_to_be_hs_dir:1; /**< True iff this router claims to be + * a hidden service directory. */ + unsigned int policy_is_reject_star:1; /**< True iff the exit policy for this + * router rejects everything. */ + /** True if, after we have added this router, we should re-launch + * tests for it. */ + unsigned int needs_retest_if_added:1; + + /** True iff this router included "tunnelled-dir-server" in its descriptor, + * implying it accepts tunnelled directory requests, or it advertised + * dir_port > 0. */ + unsigned int supports_tunnelled_dir_requests:1; + + /** Used during voting to indicate that we should not include an entry for + * this routerinfo. Used only during voting. */ + unsigned int omit_from_vote:1; + + /** Flags to summarize the protocol versions for this routerinfo_t. */ + protover_summary_flags_t pv; + +/** Tor can use this router for general positions in circuits; we got it + * from a directory server as usual, or we're an authority and a server + * uploaded it. */ +#define ROUTER_PURPOSE_GENERAL 0 +/** Tor should avoid using this router for circuit-building: we got it + * from a controller. If the controller wants to use it, it'll have to + * ask for it by identity. */ +#define ROUTER_PURPOSE_CONTROLLER 1 +/** Tor should use this router only for bridge positions in circuits: we got + * it via a directory request from the bridge itself, or a bridge + * authority. */ +#define ROUTER_PURPOSE_BRIDGE 2 +/** Tor should not use this router; it was marked in cached-descriptors with + * a purpose we didn't recognize. */ +#define ROUTER_PURPOSE_UNKNOWN 255 + + /** In what way did we find out about this router? One of ROUTER_PURPOSE_*. + * Routers of different purposes are kept segregated and used for different + * things; see notes on ROUTER_PURPOSE_* macros above. + */ + uint8_t purpose; +}; + +#endif + diff --git a/src/or/routerkeys.c b/src/or/routerkeys.c index 43460da8cc..b6d4d83d6e 100644 --- a/src/or/routerkeys.c +++ b/src/or/routerkeys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,13 +14,14 @@ * (TODO: The keys in router.c should go here too.) */ -#include "or.h" -#include "config.h" -#include "crypto_util.h" -#include "router.h" -#include "crypto_pwbox.h" -#include "routerkeys.h" -#include "torcert.h" +#include "or/or.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/router.h" +#include "lib/crypt_ops/crypto_pwbox.h" +#include "or/routerkeys.h" +#include "or/torcert.h" +#include "lib/term/getpass.h" #define ENC_KEY_HEADER "Boxed Ed25519 key" #define ENC_KEY_TAG "master" @@ -44,7 +45,7 @@ do_getpass(const char *prompt, char *buf, size_t buflen, if (options->use_keygen_passphrase_fd) { twice = 0; fd = options->keygen_passphrase_fd; - length = read_all(fd, buf, buflen-1, 0); + length = read_all_from_fd(fd, buf, buflen-1); if (length >= 0) buf[length] = 0; goto done_reading; @@ -1403,4 +1404,3 @@ routerkeys_free_all(void) rsa_ed_crosscert = NULL; // redundant rsa_ed_crosscert_len = 0; } - diff --git a/src/or/routerkeys.h b/src/or/routerkeys.h index 3e67952ea0..a6f06f6e20 100644 --- a/src/or/routerkeys.h +++ b/src/or/routerkeys.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_ROUTERKEYS_H #define TOR_ROUTERKEYS_H -#include "crypto_ed25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" #define INIT_ED_KEY_CREATE (1u<<0) #define INIT_ED_KEY_REPLACE (1u<<1) diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 97d83213af..98e1f69bb8 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -91,39 +91,54 @@ **/ #define ROUTERLIST_PRIVATE -#include "or.h" -#include "backtrace.h" -#include "bridges.h" -#include "crypto_ed25519.h" -#include "circuitstats.h" -#include "config.h" -#include "connection.h" -#include "control.h" -#include "crypto_rand.h" -#include "directory.h" -#include "dirserv.h" -#include "entrynodes.h" -#include "fp_pair.h" -#include "geoip.h" -#include "hibernate.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "reasons.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "sandbox.h" -#include "torcert.h" - -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" +#include "or/or.h" +#include "lib/err/backtrace.h" +#include "or/bridges.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "or/circuitstats.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/directory.h" +#include "or/dirserv.h" +#include "or/entrynodes.h" +#include "or/fp_pair.h" +#include "or/geoip.h" +#include "or/hibernate.h" +#include "or/main.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/reasons.h" +#include "or/rendcommon.h" +#include "or/rendservice.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/routerset.h" +#include "lib/sandbox/sandbox.h" +#include "or/torcert.h" +#include "lib/math/fp.h" + +#include "or/dirauth/dirvote.h" +#include "or/dirauth/mode.h" + +#include "or/authority_cert_st.h" +#include "or/dir_connection_st.h" +#include "or/dir_server_st.h" +#include "or/document_signature_st.h" +#include "or/extrainfo_st.h" +#include "or/networkstatus_st.h" +#include "or/networkstatus_voter_info_st.h" +#include "or/node_st.h" +#include "or/routerinfo_st.h" +#include "or/routerlist_st.h" +#include "or/vote_routerstatus_st.h" + +#include "lib/crypt_ops/digestset.h" // #define DEBUG_ROUTERLIST @@ -2746,10 +2761,15 @@ compute_weighted_bandwidths(const smartlist_t *sl, /** For all nodes in <b>sl</b>, return the fraction of those nodes, weighted * by their weighted bandwidths with rule <b>rule</b>, for which we have - * descriptors. */ + * descriptors. + * + * If <b>for_direct_connect</b> is true, we intend to connect to the node + * directly, as the first hop of a circuit; otherwise, we intend to connect + * to it indirectly, or use it as if we were connecting to it indirectly. */ double frac_nodes_with_descriptors(const smartlist_t *sl, - bandwidth_weight_rule_t rule) + bandwidth_weight_rule_t rule, + int for_direct_conn) { double *bandwidths = NULL; double total, present; @@ -2761,7 +2781,7 @@ frac_nodes_with_descriptors(const smartlist_t *sl, total <= 0.0) { int n_with_descs = 0; SMARTLIST_FOREACH(sl, const node_t *, node, { - if (node_has_any_descriptor(node)) + if (node_has_preferred_descriptor(node, for_direct_conn)) n_with_descs++; }); tor_free(bandwidths); @@ -2770,7 +2790,7 @@ frac_nodes_with_descriptors(const smartlist_t *sl, present = 0.0; SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) { - if (node_has_any_descriptor(node)) + if (node_has_preferred_descriptor(node, for_direct_conn)) present += bandwidths[node_sl_idx]; } SMARTLIST_FOREACH_END(node); @@ -4098,7 +4118,8 @@ routerlist_remove_old_cached_routers_with_id(time_t now, signed_descriptor_t *r_next; lifespans[i-lo].idx = i; if (r->last_listed_as_valid_until >= now || - (retain && digestset_contains(retain, r->signed_descriptor_digest))) { + (retain && digestset_probably_contains(retain, + r->signed_descriptor_digest))) { must_keep[i-lo] = 1; } if (i < hi) { @@ -4193,7 +4214,7 @@ routerlist_remove_old_routers(void) router = smartlist_get(routerlist->routers, i); if (router->cache_info.published_on <= cutoff && router->cache_info.last_listed_as_valid_until < now && - !digestset_contains(retain, + !digestset_probably_contains(retain, router->cache_info.signed_descriptor_digest)) { /* Too old: remove it. (If we're a cache, just move it into * old_routers.) */ @@ -4214,7 +4235,7 @@ routerlist_remove_old_routers(void) sd = smartlist_get(routerlist->old_routers, i); if (sd->published_on <= cutoff && sd->last_listed_as_valid_until < now && - !digestset_contains(retain, sd->signed_descriptor_digest)) { + !digestset_probably_contains(retain, sd->signed_descriptor_digest)) { /* Too old. Remove it. */ routerlist_remove_old(routerlist, sd, i--); } diff --git a/src/or/routerlist.h b/src/or/routerlist.h index 83f4d1002f..6d1e2a0b8a 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,7 +11,7 @@ #ifndef TOR_ROUTERLIST_H #define TOR_ROUTERLIST_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" int get_n_authorities(dirinfo_type_t type); int trusted_dirs_reload_certs(void); @@ -74,7 +74,8 @@ uint32_t router_get_advertised_bandwidth_capped(const routerinfo_t *router); const node_t *node_sl_choose_by_bandwidth(const smartlist_t *sl, bandwidth_weight_rule_t rule); double frac_nodes_with_descriptors(const smartlist_t *sl, - bandwidth_weight_rule_t rule); + bandwidth_weight_rule_t rule, + int for_direct_conn); const node_t *router_choose_random_node(smartlist_t *excludedsmartlist, struct routerset_t *excludedset, diff --git a/src/or/routerlist_st.h b/src/or/routerlist_st.h new file mode 100644 index 0000000000..0b94a4dfcd --- /dev/null +++ b/src/or/routerlist_st.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef ROUTERLIST_ST_H +#define ROUTERLIST_ST_H + +#include "or/desc_store_st.h" + +/** Contents of a directory of onion routers. */ +struct routerlist_t { + /** Map from server identity digest to a member of routers. */ + struct digest_ri_map_t *identity_map; + /** Map from server descriptor digest to a signed_descriptor_t from + * routers or old_routers. */ + struct digest_sd_map_t *desc_digest_map; + /** Map from extra-info digest to an extrainfo_t. Only exists for + * routers in routers or old_routers. */ + struct digest_ei_map_t *extra_info_map; + /** Map from extra-info digests to a signed_descriptor_t for a router + * descriptor having that extra-info digest. Only exists for + * routers in routers or old_routers. */ + struct digest_sd_map_t *desc_by_eid_map; + /** List of routerinfo_t for all currently live routers we know. */ + smartlist_t *routers; + /** List of signed_descriptor_t for older router descriptors we're + * caching. */ + smartlist_t *old_routers; + /** Store holding server descriptors. If present, any router whose + * cache_info.saved_location == SAVED_IN_CACHE is stored in this file + * starting at cache_info.saved_offset */ + desc_store_t desc_store; + /** Store holding extra-info documents. */ + desc_store_t extrainfo_store; +}; + +#endif + diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 7af41c3baf..dfc298286b 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -55,35 +55,54 @@ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "circuitstats.h" -#include "config.h" -#include "crypto_util.h" -#include "dirauth/shared_random.h" -#include "dirserv.h" -#include "entrynodes.h" -#include "memarea.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "parsecommon.h" -#include "policies.h" -#include "protover.h" -#include "rendcommon.h" -#include "rephist.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "routerparse.h" -#include "sandbox.h" -#include "shared_random_client.h" -#include "torcert.h" -#include "voting_schedule.h" +#include "or/or.h" +#include "or/circuitstats.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/dirauth/shared_random.h" +#include "or/dirserv.h" +#include "or/entrynodes.h" +#include "lib/memarea/memarea.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/parsecommon.h" +#include "or/policies.h" +#include "or/protover.h" +#include "or/rendcommon.h" +#include "or/rephist.h" +#include "or/router.h" +#include "or/routerkeys.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "lib/sandbox/sandbox.h" +#include "or/shared_random_client.h" +#include "or/torcert.h" +#include "or/voting_schedule.h" + +#include "or/dirauth/dirvote.h" + +#include "or/authority_cert_st.h" +#include "or/document_signature_st.h" +#include "or/extend_info_st.h" +#include "or/extrainfo_st.h" +#include "or/microdesc_st.h" +#include "or/networkstatus_st.h" +#include "or/networkstatus_voter_info_st.h" +#include "or/ns_detached_signatures_st.h" +#include "or/rend_authorized_client_st.h" +#include "or/rend_intro_point_st.h" +#include "or/rend_service_descriptor_st.h" +#include "or/routerinfo_st.h" +#include "or/routerlist_st.h" +#include "or/tor_version_st.h" +#include "or/vote_microdesc_hash_st.h" +#include "or/vote_routerstatus_st.h" + +#include "lib/container/bloomfilt.h" #undef log #include <math.h> -#include "dirauth/dirvote.h" - /****************************************************************************/ /** List of tokens recognized in router descriptors */ @@ -5667,4 +5686,3 @@ routerparse_free_all(void) { dump_desc_fifo_cleanup(); } - diff --git a/src/or/routerparse.h b/src/or/routerparse.h index 418fd3acdb..314c81dcd1 100644 --- a/src/or/routerparse.h +++ b/src/or/routerparse.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -43,6 +43,7 @@ routerinfo_t *router_parse_entry_from_string(const char *s, const char *end, int allow_annotations, const char *prepend_annotations, int *can_dl_again_out); +struct digest_ri_map_t; extrainfo_t *extrainfo_parse_entry_from_string(const char *s, const char *end, int cache_copy, struct digest_ri_map_t *routermap, int *can_dl_again_out); diff --git a/src/or/routerset.c b/src/or/routerset.c index a2599b316c..61b7dc121e 100644 --- a/src/or/routerset.c +++ b/src/or/routerset.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. +n * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,14 +27,19 @@ #define ROUTERSET_PRIVATE -#include "or.h" -#include "bridges.h" -#include "geoip.h" -#include "nodelist.h" -#include "policies.h" -#include "router.h" -#include "routerparse.h" -#include "routerset.h" +#include "or/or.h" +#include "or/bridges.h" +#include "or/geoip.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/router.h" +#include "or/routerparse.h" +#include "or/routerset.h" + +#include "or/extend_info_st.h" +#include "or/node_st.h" +#include "or/routerinfo_st.h" +#include "or/routerstatus_st.h" /** Return a new empty routerset. */ routerset_t * @@ -455,4 +460,3 @@ routerset_free_(routerset_t *routerset) bitarray_free(routerset->countries); tor_free(routerset); } - diff --git a/src/or/routerset.h b/src/or/routerset.h index 53e8c66c5e..8a13ca042a 100644 --- a/src/or/routerset.h +++ b/src/or/routerset.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -45,6 +45,8 @@ void routerset_free_(routerset_t *routerset); int routerset_len(const routerset_t *set); #ifdef ROUTERSET_PRIVATE +#include "lib/container/bitarray.h" + STATIC char * routerset_get_countryname(const char *c); STATIC int routerset_contains(const routerset_t *set, const tor_addr_t *addr, uint16_t orport, @@ -85,4 +87,3 @@ struct routerset_t { }; #endif /* defined(ROUTERSET_PRIVATE) */ #endif /* !defined(TOR_ROUTERSET_H) */ - diff --git a/src/or/routerstatus_st.h b/src/or/routerstatus_st.h new file mode 100644 index 0000000000..3de4a40ae4 --- /dev/null +++ b/src/or/routerstatus_st.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef ROUTERSTATUS_ST_H +#define ROUTERSTATUS_ST_H + +#include "or/download_status_st.h" + +/** Contents of a single router entry in a network status object. + */ +struct routerstatus_t { + time_t published_on; /**< When was this router published? */ + char nickname[MAX_NICKNAME_LEN+1]; /**< The nickname this router says it + * has. */ + char identity_digest[DIGEST_LEN]; /**< Digest of the router's identity + * key. */ + /** Digest of the router's most recent descriptor or microdescriptor. + * If it's a descriptor, we only use the first DIGEST_LEN bytes. */ + char descriptor_digest[DIGEST256_LEN]; + uint32_t addr; /**< IPv4 address for this router, in host order. */ + uint16_t or_port; /**< IPv4 OR port for this router. */ + uint16_t dir_port; /**< Directory port for this router. */ + tor_addr_t ipv6_addr; /**< IPv6 address for this router. */ + uint16_t ipv6_orport; /**< IPv6 OR port for this router. */ + unsigned int is_authority:1; /**< True iff this router is an authority. */ + unsigned int is_exit:1; /**< True iff this router is a good exit. */ + unsigned int is_stable:1; /**< True iff this router stays up a long time. */ + unsigned int is_fast:1; /**< True iff this router has good bandwidth. */ + /** True iff this router is called 'running' in the consensus. We give it + * this funny name so that we don't accidentally use this bit as a view of + * whether we think the router is *currently* running. If that's what you + * want to know, look at is_running in node_t. */ + unsigned int is_flagged_running:1; + unsigned int is_named:1; /**< True iff "nickname" belongs to this router. */ + unsigned int is_unnamed:1; /**< True iff "nickname" belongs to another + * router. */ + unsigned int is_valid:1; /**< True iff this router isn't invalid. */ + unsigned int is_possible_guard:1; /**< True iff this router would be a good + * choice as an entry guard. */ + unsigned int is_bad_exit:1; /**< True iff this node is a bad choice for + * an exit node. */ + unsigned int is_hs_dir:1; /**< True iff this router is a v2-or-later hidden + * service directory. */ + unsigned int is_v2_dir:1; /** True iff this router publishes an open DirPort + * or it claims to accept tunnelled dir requests. + */ + + unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */ + unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */ + unsigned int bw_is_unmeasured:1; /**< This is a consensus entry, with + * the Unmeasured flag set. */ + + /** Flags to summarize the protocol versions for this routerstatus_t. */ + protover_summary_flags_t pv; + + uint32_t bandwidth_kb; /**< Bandwidth (capacity) of the router as reported in + * the vote/consensus, in kilobytes/sec. */ + + /** The consensus has guardfraction information for this router. */ + unsigned int has_guardfraction:1; + /** The guardfraction value of this router. */ + uint32_t guardfraction_percentage; + + char *exitsummary; /**< exit policy summary - + * XXX weasel: this probably should not stay a string. */ + + /* ---- The fields below aren't derived from the networkstatus; they + * hold local information only. */ + + time_t last_dir_503_at; /**< When did this router last tell us that it + * was too busy to serve directory info? */ + download_status_t dl_status; + +}; + +#endif + diff --git a/src/or/scheduler.c b/src/or/scheduler.c index da894294bf..960972de86 100644 --- a/src/or/scheduler.c +++ b/src/or/scheduler.c @@ -1,17 +1,19 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "config.h" +#include "or/or.h" +#include "or/config.h" -#include "compat_libevent.h" +#include "common/compat_libevent.h" #define SCHEDULER_PRIVATE_ #define SCHEDULER_KIST_PRIVATE -#include "scheduler.h" -#include "main.h" -#include "buffers.h" +#include "or/scheduler.h" +#include "or/main.h" +#include "lib/container/buffers.h" #define TOR_CHANNEL_INTERNAL_ -#include "channeltls.h" +#include "or/channeltls.h" + +#include "or/or_connection_st.h" /** * \file scheduler.c diff --git a/src/or/scheduler.h b/src/or/scheduler.h index 08b02e286f..856923f9a7 100644 --- a/src/or/scheduler.h +++ b/src/or/scheduler.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2017, The Tor Project, Inc. */ +/* * Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,9 +9,9 @@ #ifndef TOR_SCHEDULER_H #define TOR_SCHEDULER_H -#include "or.h" -#include "channel.h" -#include "testsupport.h" +#include "or/or.h" +#include "or/channel.h" +#include "lib/testsupport/testsupport.h" /** Scheduler type, we build an ordered list with those values from the * parsed strings in Schedulers. The reason to do such a thing is so we can diff --git a/src/or/scheduler_kist.c b/src/or/scheduler_kist.c index c6e9b72c48..3059952b92 100644 --- a/src/or/scheduler_kist.c +++ b/src/or/scheduler_kist.c @@ -1,18 +1,21 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define SCHEDULER_KIST_PRIVATE -#include "or.h" -#include "buffers.h" -#include "config.h" -#include "connection.h" -#include "networkstatus.h" +#include "or/or.h" +#include "lib/container/buffers.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/networkstatus.h" #define TOR_CHANNEL_INTERNAL_ -#include "channel.h" -#include "channeltls.h" +#include "or/channel.h" +#include "or/channeltls.h" #define SCHEDULER_PRIVATE_ -#include "scheduler.h" +#include "or/scheduler.h" +#include "lib/math/fp.h" + +#include "or/or_connection_st.h" #define TLS_PER_CELL_OVERHEAD 29 @@ -833,4 +836,3 @@ scheduler_can_use_kist(void) } #endif /* defined(HAVE_KIST_SUPPORT) */ - diff --git a/src/or/scheduler_vanilla.c b/src/or/scheduler_vanilla.c index b674d8256c..0346af2ada 100644 --- a/src/or/scheduler_vanilla.c +++ b/src/or/scheduler_vanilla.c @@ -1,12 +1,12 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "config.h" +#include "or/or.h" +#include "or/config.h" #define TOR_CHANNEL_INTERNAL_ -#include "channel.h" +#include "or/channel.h" #define SCHEDULER_PRIVATE_ -#include "scheduler.h" +#include "or/scheduler.h" /***************************************************************************** * Other internal data diff --git a/src/or/server_port_cfg_st.h b/src/or/server_port_cfg_st.h new file mode 100644 index 0000000000..e1a9ca496a --- /dev/null +++ b/src/or/server_port_cfg_st.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef SERVER_PORT_CFG_ST_H +#define SERVER_PORT_CFG_ST_H + +struct server_port_cfg_t { + /* Server port types (or, dir) only: */ + unsigned int no_advertise : 1; + unsigned int no_listen : 1; + unsigned int all_addrs : 1; + unsigned int bind_ipv4_only : 1; + unsigned int bind_ipv6_only : 1; +}; + +#endif + diff --git a/src/or/shared_random_client.c b/src/or/shared_random_client.c index 3aef83cef4..9a6c0f6644 100644 --- a/src/or/shared_random_client.c +++ b/src/or/shared_random_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,13 +9,15 @@ **/ #define SHARED_RANDOM_CLIENT_PRIVATE -#include "shared_random_client.h" +#include "or/shared_random_client.h" -#include "config.h" -#include "voting_schedule.h" -#include "networkstatus.h" -#include "util.h" -#include "util_format.h" +#include "or/config.h" +#include "or/voting_schedule.h" +#include "or/networkstatus.h" +#include "common/util.h" +#include "lib/encoding/binascii.h" + +#include "or/networkstatus_st.h" /* Convert a given srv object to a string for the control port. This doesn't * fail and the srv object MUST be valid. */ diff --git a/src/or/shared_random_client.h b/src/or/shared_random_client.h index 89c608d45f..079829496c 100644 --- a/src/or/shared_random_client.h +++ b/src/or/shared_random_client.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,7 +10,7 @@ #define TOR_SHARED_RANDOM_CLIENT_H /* Dirauth module. */ -#include "dirauth/shared_random.h" +#include "or/dirauth/shared_random.h" /* Helper functions. */ void sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv); diff --git a/src/or/signed_descriptor_st.h b/src/or/signed_descriptor_st.h new file mode 100644 index 0000000000..90cd4a2703 --- /dev/null +++ b/src/or/signed_descriptor_st.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef SIGNED_DESCRIPTOR_ST_H +#define SIGNED_DESCRIPTOR_ST_H + +#include "or/download_status_st.h" + +/** Information need to cache an onion router's descriptor. */ +struct signed_descriptor_t { + /** Pointer to the raw server descriptor, preceded by annotations. Not + * necessarily NUL-terminated. If saved_location is SAVED_IN_CACHE, this + * pointer is null. */ + char *signed_descriptor_body; + /** Length of the annotations preceding the server descriptor. */ + size_t annotations_len; + /** Length of the server descriptor. */ + size_t signed_descriptor_len; + /** Digest of the server descriptor, computed as specified in + * dir-spec.txt. */ + char signed_descriptor_digest[DIGEST_LEN]; + /** Identity digest of the router. */ + char identity_digest[DIGEST_LEN]; + /** Declared publication time of the descriptor. */ + time_t published_on; + /** For routerdescs only: digest of the corresponding extrainfo. */ + char extra_info_digest[DIGEST_LEN]; + /** For routerdescs only: A SHA256-digest of the extrainfo (if any) */ + char extra_info_digest256[DIGEST256_LEN]; + /** Certificate for ed25519 signing key. */ + struct tor_cert_st *signing_key_cert; + /** For routerdescs only: Status of downloading the corresponding + * extrainfo. */ + download_status_t ei_dl_status; + /** Where is the descriptor saved? */ + saved_location_t saved_location; + /** If saved_location is SAVED_IN_CACHE or SAVED_IN_JOURNAL, the offset of + * this descriptor in the corresponding file. */ + off_t saved_offset; + /** What position is this descriptor within routerlist->routers or + * routerlist->old_routers? -1 for none. */ + int routerlist_index; + /** The valid-until time of the most recent consensus that listed this + * descriptor. 0 for "never listed in a consensus, so far as we know." */ + time_t last_listed_as_valid_until; + /* If true, we do not ever try to save this object in the cache. */ + unsigned int do_not_cache : 1; + /* If true, this item is meant to represent an extrainfo. */ + unsigned int is_extrainfo : 1; + /* If true, we got an extrainfo for this item, and the digest was right, + * but it was incompatible. */ + unsigned int extrainfo_is_bogus : 1; + /* If true, we are willing to transmit this item unencrypted. */ + unsigned int send_unencrypted : 1; +}; + +#endif + diff --git a/src/or/socks_request_st.h b/src/or/socks_request_st.h new file mode 100644 index 0000000000..c650a57739 --- /dev/null +++ b/src/or/socks_request_st.h @@ -0,0 +1,59 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef SOCKS_REQUEST_ST_H +#define SOCKS_REQUEST_ST_H + +/** State of a SOCKS request from a user to an OP. Also used to encode other + * information for non-socks user request (such as those on TransPort and + * DNSPort) */ +struct socks_request_t { + /** Which version of SOCKS did the client use? One of "0, 4, 5" -- where + * 0 means that no socks handshake ever took place, and this is just a + * stub connection (e.g. see connection_ap_make_link()). */ + uint8_t socks_version; + /** If using socks5 authentication, which authentication type did we + * negotiate? currently we support 0 (no authentication) and 2 + * (username/password). */ + uint8_t auth_type; + /** What is this stream's goal? One of the SOCKS_COMMAND_* values */ + uint8_t command; + /** Which kind of listener created this stream? */ + uint8_t listener_type; + size_t replylen; /**< Length of <b>reply</b>. */ + uint8_t reply[MAX_SOCKS_REPLY_LEN]; /**< Write an entry into this string if + * we want to specify our own socks reply, + * rather than using the default socks4 or + * socks5 socks reply. We use this for the + * two-stage socks5 handshake. + */ + char address[MAX_SOCKS_ADDR_LEN]; /**< What address did the client ask to + connect to/resolve? */ + uint16_t port; /**< What port did the client ask to connect to? */ + unsigned int has_finished : 1; /**< Has the SOCKS handshake finished? Used to + * make sure we send back a socks reply for + * every connection. */ + unsigned int got_auth : 1; /**< Have we received any authentication data? */ + /** If this is set, we will choose "no authentication" instead of + * "username/password" authentication if both are offered. Used as input to + * parse_socks. */ + unsigned int socks_prefer_no_auth : 1; + + /** Number of bytes in username; 0 if username is NULL */ + size_t usernamelen; + /** Number of bytes in password; 0 if password is NULL */ + uint8_t passwordlen; + /** The negotiated username value if any (for socks5), or the entire + * authentication string (for socks4). This value is NOT nul-terminated; + * see usernamelen for its length. */ + char *username; + /** The negotiated password value if any (for socks5). This value is NOT + * nul-terminated; see passwordlen for its length. */ + char *password; +}; + +#endif + diff --git a/src/or/statefile.c b/src/or/statefile.c index c81ea44e06..80c56b2d52 100644 --- a/src/or/statefile.c +++ b/src/or/statefile.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -29,19 +29,19 @@ */ #define STATEFILE_PRIVATE -#include "or.h" -#include "circuitstats.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "control.h" -#include "entrynodes.h" -#include "hibernate.h" -#include "main.h" -#include "rephist.h" -#include "router.h" -#include "sandbox.h" -#include "statefile.h" +#include "or/or.h" +#include "or/circuitstats.h" +#include "or/config.h" +#include "or/confparse.h" +#include "or/connection.h" +#include "or/control.h" +#include "or/entrynodes.h" +#include "or/hibernate.h" +#include "or/main.h" +#include "or/rephist.h" +#include "or/router.h" +#include "lib/sandbox/sandbox.h" +#include "or/statefile.h" /** A list of state-file "abbreviations," for compatibility. */ static config_abbrev_t state_abbrevs_[] = { diff --git a/src/or/statefile.h b/src/or/statefile.h index 5aa2ca9320..ed21dd14e7 100644 --- a/src/or/statefile.h +++ b/src/or/statefile.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_STATEFILE_H diff --git a/src/or/status.c b/src/or/status.c index 4b8033d114..d0b3bc5536 100644 --- a/src/or/status.c +++ b/src/or/status.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,24 +14,26 @@ #define STATUS_PRIVATE -#include "or.h" -#include "circuituse.h" -#include "config.h" -#include "status.h" -#include "nodelist.h" -#include "relay.h" -#include "router.h" -#include "circuitlist.h" -#include "main.h" -#include "rephist.h" -#include "hibernate.h" -#include "statefile.h" -#include "hs_stats.h" -#include "hs_service.h" -#include "dos.h" +#include "or/or.h" +#include "or/circuituse.h" +#include "or/config.h" +#include "or/status.h" +#include "or/nodelist.h" +#include "or/relay.h" +#include "or/router.h" +#include "or/circuitlist.h" +#include "or/main.h" +#include "or/rephist.h" +#include "or/hibernate.h" +#include "or/statefile.h" +#include "or/hs_stats.h" +#include "or/hs_service.h" +#include "or/dos.h" + +#include "or/routerinfo_st.h" static void log_accounting(const time_t now, const or_options_t *options); -#include "geoip.h" +#include "or/geoip.h" /** Return the total number of circuits. */ STATIC int diff --git a/src/or/status.h b/src/or/status.h index 49da6abc0f..7258ed5939 100644 --- a/src/or/status.h +++ b/src/or/status.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_STATUS_H #define TOR_STATUS_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" int log_heartbeat(time_t now); diff --git a/src/or/tor_api.c b/src/or/tor_api.c index 4260cc88f4..efedf2dc78 100644 --- a/src/or/tor_api.c +++ b/src/or/tor_api.c @@ -1,15 +1,15 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file tor_api.c **/ -#include "tor_api.h" -#include "tor_api_internal.h" +#include "or/tor_api.h" +#include "or/tor_api_internal.h" // Include this after the above headers, to insure that they don't // depend on anything else. diff --git a/src/or/tor_api.h b/src/or/tor_api.h index 6d4a9518e0..ead9493c1f 100644 --- a/src/or/tor_api.h +++ b/src/or/tor_api.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/tor_api_internal.h b/src/or/tor_api_internal.h index 10b6278b7b..2c392a68de 100644 --- a/src/or/tor_api_internal.h +++ b/src/or/tor_api_internal.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_API_INTERNAL_H diff --git a/src/or/tor_main.c b/src/or/tor_main.c index 703669ac99..8c497fff8a 100644 --- a/src/or/tor_main.c +++ b/src/or/tor_main.c @@ -1,6 +1,6 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/or/tor_version_st.h b/src/or/tor_version_st.h new file mode 100644 index 0000000000..5950c5d5c4 --- /dev/null +++ b/src/or/tor_version_st.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_VERSION_ST_H +#define TOR_VERSION_ST_H + +#define MAX_STATUS_TAG_LEN 32 +/** Structure to hold parsed Tor versions. This is a little messier + * than we would like it to be, because we changed version schemes with 0.1.0. + * + * See version-spec.txt for the whole business. + */ +struct tor_version_t { + int major; + int minor; + int micro; + /** Release status. For version in the post-0.1 format, this is always + * VER_RELEASE. */ + enum { VER_PRE=0, VER_RC=1, VER_RELEASE=2, } status; + int patchlevel; + char status_tag[MAX_STATUS_TAG_LEN]; + int svn_revision; + + int git_tag_len; + char git_tag[DIGEST_LEN]; +}; + +#endif + diff --git a/src/or/torcert.c b/src/or/torcert.c index 1c5afd965a..785132c174 100644 --- a/src/or/torcert.c +++ b/src/or/torcert.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -25,15 +25,16 @@ * that one is authority_cert_t, and it's mostly handled in routerlist.c. */ -#include "or.h" -#include "config.h" -#include "crypto_util.h" -#include "torcert.h" -#include "ed25519_cert.h" -#include "torlog.h" -#include "util.h" -#include "compat.h" -#include "link_handshake.h" +#include "or/or.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_util.h" +#include "or/torcert.h" +#include "trunnel/ed25519_cert.h" +#include "lib/log/torlog.h" +#include "common/util.h" +#include "trunnel/link_handshake.h" + +#include "or/or_handshake_certs_st.h" /** Helper for tor_cert_create(): signs any 32 bytes, not just an ed25519 * key. diff --git a/src/or/torcert.h b/src/or/torcert.h index 18ca60b5a8..ba5787934b 100644 --- a/src/or/torcert.h +++ b/src/or/torcert.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TORCERT_H_INCLUDED #define TORCERT_H_INCLUDED -#include "crypto_ed25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" #define SIGNED_KEY_TYPE_ED25519 0x01 diff --git a/src/or/transports.c b/src/or/transports.c index 614fc81da8..34161fd16e 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ +/* Copyright (c) 2011-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -90,17 +90,20 @@ **/ #define PT_PRIVATE -#include "or.h" -#include "bridges.h" -#include "config.h" -#include "circuitbuild.h" -#include "transports.h" -#include "util.h" -#include "router.h" -#include "statefile.h" -#include "connection_or.h" -#include "ext_orport.h" -#include "control.h" +#include "or/or.h" +#include "or/bridges.h" +#include "or/config.h" +#include "or/circuitbuild.h" +#include "or/transports.h" +#include "common/util.h" +#include "or/router.h" +#include "or/statefile.h" +#include "or/connection_or.h" +#include "or/ext_orport.h" +#include "or/control.h" + +#include "lib/process/env.h" +#include "lib/process/subprocess.h" static process_environment_t * create_managed_proxy_environment(const managed_proxy_t *mp); @@ -1697,3 +1700,39 @@ pt_free_all(void) } } +/** Return a newly allocated string equal to <b>string</b>, except that every + * character in <b>chars_to_escape</b> is preceded by a backslash. */ +char * +tor_escape_str_for_pt_args(const char *string, const char *chars_to_escape) +{ + char *new_string = NULL; + char *new_cp = NULL; + size_t length, new_length; + + tor_assert(string); + + length = strlen(string); + + if (!length) /* If we were given the empty string, return the same. */ + return tor_strdup(""); + /* (new_length > SIZE_MAX) => ((length * 2) + 1 > SIZE_MAX) => + (length*2 > SIZE_MAX - 1) => (length > (SIZE_MAX - 1)/2) */ + if (length > (SIZE_MAX - 1)/2) /* check for overflow */ + return NULL; + + /* this should be enough even if all characters must be escaped */ + new_length = (length * 2) + 1; + + new_string = new_cp = tor_malloc(new_length); + + while (*string) { + if (strchr(chars_to_escape, *string)) + *new_cp++ = '\\'; + + *new_cp++ = *string++; + } + + *new_cp = '\0'; /* NUL-terminate the new string */ + + return new_string; +} diff --git a/src/or/transports.h b/src/or/transports.h index 022b926a03..d304dcd485 100644 --- a/src/or/transports.h +++ b/src/or/transports.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -66,6 +66,9 @@ char *pt_stringify_socks_args(const smartlist_t *socks_args); char *pt_get_socks_args_for_proxy_addrport(const tor_addr_t *addr, uint16_t port); +char *tor_escape_str_for_pt_args(const char *string, + const char *chars_to_escape); + #ifdef PT_PRIVATE /** State of the managed proxy configuration protocol. */ enum pt_proto_state { @@ -78,6 +81,8 @@ enum pt_proto_state { PT_PROTO_FAILED_LAUNCH /* failed while launching */ }; +struct process_handle_t; + /** Structure containing information of a managed proxy. */ typedef struct { enum pt_proto_state conf_state; /* the current configuration state */ @@ -90,7 +95,7 @@ typedef struct { int is_server; /* is it a server proxy? */ /* A pointer to the process handle of this managed proxy. */ - process_handle_t *process_handle; + struct process_handle_t *process_handle; int pid; /* The Process ID this managed proxy is using. */ @@ -140,4 +145,3 @@ STATIC void free_execve_args(char **arg); #endif /* defined(PT_PRIVATE) */ #endif /* !defined(TOR_TRANSPORTS_H) */ - diff --git a/src/or/var_cell_st.h b/src/or/var_cell_st.h new file mode 100644 index 0000000000..514afc44b1 --- /dev/null +++ b/src/or/var_cell_st.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef VAR_CELL_ST_H +#define VAR_CELL_ST_H + +/** Parsed variable-length onion routing cell. */ +struct var_cell_t { + /** Type of the cell: CELL_VERSIONS, etc. */ + uint8_t command; + /** Circuit thich received the cell */ + circid_t circ_id; + /** Number of bytes actually stored in <b>payload</b> */ + uint16_t payload_len; + /** Payload of this cell */ + uint8_t payload[FLEXIBLE_ARRAY_MEMBER]; +}; + +#endif + diff --git a/src/or/vote_microdesc_hash_st.h b/src/or/vote_microdesc_hash_st.h new file mode 100644 index 0000000000..31fc98040e --- /dev/null +++ b/src/or/vote_microdesc_hash_st.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef VOTE_MICRODESC_HASH_ST_H +#define VOTE_MICRODESC_HASH_ST_H + +/** Linked list of microdesc hash lines for a single router in a directory + * vote. + */ +struct vote_microdesc_hash_t { + /** Next element in the list, or NULL. */ + struct vote_microdesc_hash_t *next; + /** The raw contents of the microdesc hash line, from the "m" through the + * newline. */ + char *microdesc_hash_line; +}; + +#endif + diff --git a/src/or/vote_routerstatus_st.h b/src/or/vote_routerstatus_st.h new file mode 100644 index 0000000000..7ec0c962fe --- /dev/null +++ b/src/or/vote_routerstatus_st.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef VOTE_ROUTERSTATUS_ST_H +#define VOTE_ROUTERSTATUS_ST_H + +#include "or/routerstatus_st.h" + +/** The claim about a single router, made in a vote. */ +struct vote_routerstatus_t { + routerstatus_t status; /**< Underlying 'status' object for this router. + * Flags are redundant. */ + /** How many known-flags are allowed in a vote? This is the width of + * the flags field of vote_routerstatus_t */ +#define MAX_KNOWN_FLAGS_IN_VOTE 64 + uint64_t flags; /**< Bit-field for all recognized flags; index into + * networkstatus_t.known_flags. */ + char *version; /**< The version that the authority says this router is + * running. */ + char *protocols; /**< The protocols that this authority says this router + * provides. */ + unsigned int has_measured_bw:1; /**< The vote had a measured bw */ + /** True iff the vote included an entry for ed25519 ID, or included + * "id ed25519 none" to indicate that there was no ed25519 ID. */ + unsigned int has_ed25519_listing:1; + /** True if the Ed25519 listing here is the consensus-opinion for the + * Ed25519 listing; false if there was no consensus on Ed25519 key status, + * or if this VRS doesn't reflect it. */ + unsigned int ed25519_reflects_consensus:1; + uint32_t measured_bw_kb; /**< Measured bandwidth (capacity) of the router */ + /** The hash or hashes that the authority claims this microdesc has. */ + vote_microdesc_hash_t *microdesc; + /** Ed25519 identity for this router, or zero if it has none. */ + uint8_t ed25519_id[ED25519_PUBKEY_LEN]; +}; + +#endif + diff --git a/src/or/vote_timing_st.h b/src/or/vote_timing_st.h new file mode 100644 index 0000000000..14c13eed28 --- /dev/null +++ b/src/or/vote_timing_st.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef VOTE_TIMING_ST_H +#define VOTE_TIMING_ST_H + +/** Describes the schedule by which votes should be generated. */ +struct vote_timing_t { + /** Length in seconds between one consensus becoming valid and the next + * becoming valid. */ + int vote_interval; + /** For how many intervals is a consensus valid? */ + int n_intervals_valid; + /** Time in seconds allowed to propagate votes */ + int vote_delay; + /** Time in seconds allowed to propagate signatures */ + int dist_delay; +}; + +#endif + diff --git a/src/or/voting_schedule.c b/src/or/voting_schedule.c index d230a6dbcd..6edde3f229 100644 --- a/src/or/voting_schedule.c +++ b/src/or/voting_schedule.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,11 +9,13 @@ **/ #define VOTING_SCHEDULE_PRIVATE -#include "voting_schedule.h" +#include "or/voting_schedule.h" -#include "or.h" -#include "config.h" -#include "networkstatus.h" +#include "or/or.h" +#include "or/config.h" +#include "or/networkstatus.h" + +#include "or/networkstatus_st.h" /* ===== * Vote scheduling diff --git a/src/or/voting_schedule.h b/src/or/voting_schedule.h index 087701408e..0f27d36d52 100644 --- a/src/or/voting_schedule.h +++ b/src/or/voting_schedule.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,7 +9,7 @@ #ifndef TOR_VOTING_SCHEDULE_H #define TOR_VOTING_SCHEDULE_H -#include "or.h" +#include "or/or.h" /** Scheduling information for a voting interval. */ typedef struct { diff --git a/src/rust/build.rs b/src/rust/build.rs index b943aa5535..4e401f5275 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -138,9 +138,9 @@ pub fn main() { cfg.from_cflags("TOR_LDFLAGS_openssl"); cfg.from_cflags("TOR_LDFLAGS_libevent"); + cfg.link_relpath("src/lib"); cfg.link_relpath("src/common"); cfg.link_relpath("src/ext/keccak-tiny"); - cfg.link_relpath("src/ext/keccak-tiny"); cfg.link_relpath("src/ext/ed25519/ref10"); cfg.link_relpath("src/ext/ed25519/donna"); cfg.link_relpath("src/trunnel"); @@ -149,11 +149,25 @@ pub fn main() { // will have dependencies on all the other rust packages that // tor uses. We must be careful with factoring and dependencies // moving forward! - cfg.component("or-crypto-testing"); - cfg.component("or-ctime-testing"); + cfg.component("tor-crypt-ops-testing"); cfg.component("or-testing"); + cfg.component("tor-sandbox"); + cfg.component("tor-encoding-testing"); + cfg.component("tor-net"); + cfg.component("tor-thread-testing"); + cfg.component("tor-memarea-testing"); + cfg.component("tor-log"); + cfg.component("tor-lock"); + cfg.component("tor-fdio"); + cfg.component("tor-container-testing"); + cfg.component("tor-smartlist-core-testing"); + cfg.component("tor-string-testing"); + cfg.component("tor-malloc"); + cfg.component("tor-wallclock"); + cfg.component("tor-err-testing"); cfg.component("or-event-testing"); - cfg.component("or-ctime-testing"); + cfg.component("tor-intmath-testing"); + cfg.component("tor-ctime-testing"); cfg.component("curve25519_donna"); cfg.component("keccak-tiny"); cfg.component("ed25519_ref10"); diff --git a/src/rust/external/external.rs b/src/rust/external/external.rs index b9e17f021d..66317f2128 100644 --- a/src/rust/external/external.rs +++ b/src/rust/external/external.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ use libc::{c_char, c_int}; diff --git a/src/rust/protover/ffi.rs b/src/rust/protover/ffi.rs index e3e545db75..cd49e5f931 100644 --- a/src/rust/protover/ffi.rs +++ b/src/rust/protover/ffi.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ //! FFI functions, only to be called from C. diff --git a/src/rust/protover/lib.rs b/src/rust/protover/lib.rs index ce964196fd..5da562c1e0 100644 --- a/src/rust/protover/lib.rs +++ b/src/rust/protover/lib.rs @@ -1,4 +1,4 @@ -//! Copyright (c) 2016-2017, The Tor Project, Inc. */ +//! Copyright (c) 2016-2018, The Tor Project, Inc. */ //! See LICENSE for licensing information */ //! Versioning information for different pieces of the Tor protocol. diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs index d6ed2739fe..f50419ed19 100644 --- a/src/rust/protover/protover.rs +++ b/src/rust/protover/protover.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ use std::collections::HashMap; diff --git a/src/rust/protover/tests/protover.rs b/src/rust/protover/tests/protover.rs index 2db01a1634..ac78d34b7a 100644 --- a/src/rust/protover/tests/protover.rs +++ b/src/rust/protover/tests/protover.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ extern crate protover; diff --git a/src/rust/smartlist/lib.rs b/src/rust/smartlist/lib.rs index 14a8148315..2716842af2 100644 --- a/src/rust/smartlist/lib.rs +++ b/src/rust/smartlist/lib.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ extern crate libc; diff --git a/src/rust/smartlist/smartlist.rs b/src/rust/smartlist/smartlist.rs index 2a822d89f4..747d22f78c 100644 --- a/src/rust/smartlist/smartlist.rs +++ b/src/rust/smartlist/smartlist.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ use std::slice; diff --git a/src/rust/tor_allocate/lib.rs b/src/rust/tor_allocate/lib.rs index 937a5dcf63..5a355bc8d6 100644 --- a/src/rust/tor_allocate/lib.rs +++ b/src/rust/tor_allocate/lib.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ //! Allocation helper functions that allow data to be allocated in Rust diff --git a/src/rust/tor_allocate/tor_allocate.rs b/src/rust/tor_allocate/tor_allocate.rs index 3c0037f139..47fa5fc593 100644 --- a/src/rust/tor_allocate/tor_allocate.rs +++ b/src/rust/tor_allocate/tor_allocate.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ // No-op defined purely for testing at the module level use libc::c_char; diff --git a/src/rust/tor_log/lib.rs b/src/rust/tor_log/lib.rs index 72f9e38339..21855ae73b 100644 --- a/src/rust/tor_log/lib.rs +++ b/src/rust/tor_log/lib.rs @@ -1,4 +1,4 @@ -//! Copyright (c) 2016-2017, The Tor Project, Inc. */ +//! Copyright (c) 2016-2018, The Tor Project, Inc. */ //! See LICENSE for licensing information */ //! Logging wrapper for Rust to utilize Tor's logger, found at diff --git a/src/rust/tor_log/tor_log.rs b/src/rust/tor_log/tor_log.rs index ad6725f0f2..963c68afa8 100644 --- a/src/rust/tor_log/tor_log.rs +++ b/src/rust/tor_log/tor_log.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ // Note that these functions are untested due to the fact that there are no diff --git a/src/rust/tor_util/ffi.rs b/src/rust/tor_util/ffi.rs index 32779ed476..4be154ff1e 100644 --- a/src/rust/tor_util/ffi.rs +++ b/src/rust/tor_util/ffi.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ //! FFI functions to announce Rust support during tor startup, only to be diff --git a/src/rust/tor_util/lib.rs b/src/rust/tor_util/lib.rs index 94697b6069..4ce5fc9374 100644 --- a/src/rust/tor_util/lib.rs +++ b/src/rust/tor_util/lib.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ //! Small module to announce Rust support during startup for demonstration diff --git a/src/rust/tor_util/strings.rs b/src/rust/tor_util/strings.rs index 505191d913..c365564e97 100644 --- a/src/rust/tor_util/strings.rs +++ b/src/rust/tor_util/strings.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ //! Utilities for working with static strings. diff --git a/src/test/bench.c b/src/test/bench.c index 9ab23c9921..6653f4942f 100644 --- a/src/test/bench.c +++ b/src/test/bench.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,21 +10,26 @@ #include "orconfig.h" -#include "or.h" -#include "onion_tap.h" -#include "relay_crypto.h" +#include "or/or.h" +#include "or/onion_tap.h" +#include "or/relay_crypto.h" #include <openssl/opensslv.h> #include <openssl/evp.h> #include <openssl/ec.h> #include <openssl/ecdh.h> #include <openssl/obj_mac.h> -#include "config.h" -#include "crypto_curve25519.h" -#include "onion_ntor.h" -#include "crypto_ed25519.h" -#include "crypto_rand.h" -#include "consdiff.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "or/onion_ntor.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/consdiff.h" + +#include "or/cell_st.h" +#include "or/or_circuit_st.h" + +#include "lib/crypt_ops/digestset.h" #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) static uint64_t nanostart; @@ -371,7 +376,7 @@ bench_dmap(void) crypto_rand(d, 20); smartlist_add(sl2, tor_memdup(d, 20)); } - printf("nbits=%d\n", ds->mask+1); + //printf("nbits=%d\n", ds->mask+1); reset_perftime(); @@ -399,18 +404,20 @@ bench_dmap(void) NANOCOUNT(pt3, pt4, iters*elts)); for (i = 0; i < iters; ++i) { - SMARTLIST_FOREACH(sl, const char *, cp, n += digestset_contains(ds, cp)); - SMARTLIST_FOREACH(sl2, const char *, cp, n += digestset_contains(ds, cp)); + SMARTLIST_FOREACH(sl, const char *, cp, + n += digestset_probably_contains(ds, cp)); + SMARTLIST_FOREACH(sl2, const char *, cp, + n += digestset_probably_contains(ds, cp)); } end = perftime(); - printf("digestset_contains: %.2f ns per element.\n", + printf("digestset_probably_contains: %.2f ns per element.\n", NANOCOUNT(pt4, end, iters*elts*2)); /* We need to use this, or else the whole loop gets optimized out. */ printf("Hits == %d\n", n); for (i = 0; i < fpostests; ++i) { crypto_rand(d, 20); - if (digestset_contains(ds, d)) ++fp; + if (digestset_probably_contains(ds, d)) ++fp; } printf("False positive rate on digestset: %.2f%%\n", (fp/(double)fpostests)*100); @@ -738,4 +745,3 @@ main(int argc, const char **argv) return 0; } - diff --git a/src/test/bt_test.py b/src/test/bt_test.py index 4cb3326042..0eeb58c16c 100755 --- a/src/test/bt_test.py +++ b/src/test/bt_test.py @@ -1,4 +1,4 @@ -# Copyright 2013-2017, The Tor Project, Inc +# Copyright 2013-2018, The Tor Project, Inc # See LICENSE for licensing information """ diff --git a/src/test/ed25519_exts_ref.py b/src/test/ed25519_exts_ref.py index f84d3002d3..a9090c9ed2 100644 --- a/src/test/ed25519_exts_ref.py +++ b/src/test/ed25519_exts_ref.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright 2014-2017, The Tor Project, Inc +# Copyright 2014-2018, The Tor Project, Inc # See LICENSE for licensing information """ diff --git a/src/test/fakechans.h b/src/test/fakechans.h index ab5d8461b6..0770be8e04 100644 --- a/src/test/fakechans.h +++ b/src/test/fakechans.h @@ -1,4 +1,4 @@ - /* Copyright (c) 2014-2017, The Tor Project, Inc. */ + /* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_FAKECHANS_H diff --git a/src/test/fuzz/dict/http b/src/test/fuzz/dict/http index 3b0531579d..63627ac380 100644 --- a/src/test/fuzz/dict/http +++ b/src/test/fuzz/dict/http @@ -4,7 +4,7 @@ # # Extracted from directory_handle_command() in the tor source code # -# Copyright (c) 2016-2017, The Tor Project, Inc. +# Copyright (c) 2016-2018, The Tor Project, Inc. # See LICENSE for licensing information # # Usage: diff --git a/src/test/fuzz/fuzz_consensus.c b/src/test/fuzz/fuzz_consensus.c index 6610ade7ad..de54da61b8 100644 --- a/src/test/fuzz/fuzz_consensus.c +++ b/src/test/fuzz/fuzz_consensus.c @@ -1,10 +1,10 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "networkstatus.h" -#include "fuzzing.h" +#include "or/or.h" +#include "or/routerparse.h" +#include "or/networkstatus.h" +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) diff --git a/src/test/fuzz/fuzz_descriptor.c b/src/test/fuzz/fuzz_descriptor.c index 1a50beae17..d28793fdf3 100644 --- a/src/test/fuzz/fuzz_descriptor.c +++ b/src/test/fuzz/fuzz_descriptor.c @@ -1,11 +1,11 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "routerlist.h" -#include "routerkeys.h" -#include "fuzzing.h" +#include "or/or.h" +#include "or/routerparse.h" +#include "or/routerlist.h" +#include "or/routerkeys.h" +#include "test/fuzz/fuzzing.h" static int mock_check_tap_onion_key_crosscert__nocheck(const uint8_t *crosscert, diff --git a/src/test/fuzz/fuzz_diff.c b/src/test/fuzz/fuzz_diff.c index 642380b512..eb5fc27e08 100644 --- a/src/test/fuzz/fuzz_diff.c +++ b/src/test/fuzz/fuzz_diff.c @@ -1,13 +1,13 @@ -/* Copyright (c) 2016, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONSDIFF_PRIVATE #include "orconfig.h" -#include "or.h" -#include "consdiff.h" +#include "or/or.h" +#include "or/consdiff.h" -#include "fuzzing.h" +#include "test/fuzz/fuzzing.h" static int mock_consensus_compute_digest_(const char *c, consensus_digest_t *d) diff --git a/src/test/fuzz/fuzz_diff_apply.c b/src/test/fuzz/fuzz_diff_apply.c index 8d7bf751bf..76789fabcd 100644 --- a/src/test/fuzz/fuzz_diff_apply.c +++ b/src/test/fuzz/fuzz_diff_apply.c @@ -1,13 +1,13 @@ -/* Copyright (c) 2016, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONSDIFF_PRIVATE #include "orconfig.h" -#include "or.h" -#include "consdiff.h" +#include "or/or.h" +#include "or/consdiff.h" -#include "fuzzing.h" +#include "test/fuzz/fuzzing.h" static int mock_consensus_compute_digest_(const char *c, consensus_digest_t *d) diff --git a/src/test/fuzz/fuzz_extrainfo.c b/src/test/fuzz/fuzz_extrainfo.c index 2a3de7ecf7..274ecc7866 100644 --- a/src/test/fuzz/fuzz_extrainfo.c +++ b/src/test/fuzz/fuzz_extrainfo.c @@ -1,11 +1,11 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "routerlist.h" -#include "routerkeys.h" -#include "fuzzing.h" +#include "or/or.h" +#include "or/routerparse.h" +#include "or/routerlist.h" +#include "or/routerkeys.h" +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) diff --git a/src/test/fuzz/fuzz_hsdescv2.c b/src/test/fuzz/fuzz_hsdescv2.c index 19db265716..5cf2cffb88 100644 --- a/src/test/fuzz/fuzz_hsdescv2.c +++ b/src/test/fuzz/fuzz_hsdescv2.c @@ -1,10 +1,10 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "rendcommon.h" -#include "fuzzing.h" +#include "or/or.h" +#include "or/routerparse.h" +#include "or/rendcommon.h" +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) diff --git a/src/test/fuzz/fuzz_hsdescv3.c b/src/test/fuzz/fuzz_hsdescv3.c index 428774e330..ada9fa6c2d 100644 --- a/src/test/fuzz/fuzz_hsdescv3.c +++ b/src/test/fuzz/fuzz_hsdescv3.c @@ -1,17 +1,17 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE #define HS_DESCRIPTOR_PRIVATE -#include "or.h" -#include "ed25519_cert.h" /* Trunnel interface. */ -#include "crypto_ed25519.h" -#include "hs_descriptor.h" -#include "routerparse.h" -#include "util.h" +#include "or/or.h" +#include "trunnel/ed25519_cert.h" /* Trunnel interface. */ +#include "lib/crypt_ops/crypto_ed25519.h" +#include "or/hs_descriptor.h" +#include "or/routerparse.h" +#include "common/util.h" -#include "fuzzing.h" +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) diff --git a/src/test/fuzz/fuzz_http.c b/src/test/fuzz/fuzz_http.c index 2ffeb60244..772f2099b6 100644 --- a/src/test/fuzz/fuzz_http.c +++ b/src/test/fuzz/fuzz_http.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -6,15 +6,17 @@ #define BUFFERS_PRIVATE #define DIRECTORY_PRIVATE -#include "or.h" -#include "backtrace.h" -#include "buffers.h" -#include "config.h" -#include "connection.h" -#include "directory.h" -#include "torlog.h" +#include "or/or.h" +#include "lib/err/backtrace.h" +#include "lib/container/buffers.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/directory.h" +#include "lib/log/torlog.h" -#include "fuzzing.h" +#include "or/dir_connection_st.h" + +#include "test/fuzz/fuzzing.h" static void mock_connection_write_to_buf_impl_(const char *string, size_t len, diff --git a/src/test/fuzz/fuzz_http_connect.c b/src/test/fuzz/fuzz_http_connect.c index dc674070b2..bf0a9deba6 100644 --- a/src/test/fuzz/fuzz_http_connect.c +++ b/src/test/fuzz/fuzz_http_connect.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -6,16 +6,19 @@ #define BUFFERS_PRIVATE #define CONNECTION_EDGE_PRIVATE -#include "or.h" -#include "backtrace.h" -#include "buffers.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "proto_socks.h" -#include "torlog.h" +#include "or/or.h" +#include "lib/err/backtrace.h" +#include "lib/container/buffers.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/proto_socks.h" +#include "lib/log/torlog.h" -#include "fuzzing.h" +#include "or/entry_connection_st.h" +#include "or/socks_request_st.h" + +#include "test/fuzz/fuzzing.h" static void mock_connection_write_to_buf_impl_(const char *string, size_t len, diff --git a/src/test/fuzz/fuzz_iptsv2.c b/src/test/fuzz/fuzz_iptsv2.c index 4abde0c16d..7bf4d1282e 100644 --- a/src/test/fuzz/fuzz_iptsv2.c +++ b/src/test/fuzz/fuzz_iptsv2.c @@ -1,10 +1,13 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "rendcommon.h" -#include "fuzzing.h" +#include "or/or.h" +#include "or/routerparse.h" +#include "or/rendcommon.h" + +#include "or/rend_service_descriptor_st.h" + +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) diff --git a/src/test/fuzz/fuzz_microdesc.c b/src/test/fuzz/fuzz_microdesc.c index 396115026e..74e0ef4f46 100644 --- a/src/test/fuzz/fuzz_microdesc.c +++ b/src/test/fuzz/fuzz_microdesc.c @@ -1,10 +1,10 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "microdesc.h" -#include "fuzzing.h" +#include "or/or.h" +#include "or/routerparse.h" +#include "or/microdesc.h" +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) diff --git a/src/test/fuzz/fuzz_vrs.c b/src/test/fuzz/fuzz_vrs.c index baf0610a0b..0713f99c35 100644 --- a/src/test/fuzz/fuzz_vrs.c +++ b/src/test/fuzz/fuzz_vrs.c @@ -1,13 +1,17 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE #define NETWORKSTATUS_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "memarea.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "fuzzing.h" +#include "or/or.h" +#include "or/routerparse.h" +#include "lib/memarea/memarea.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" + +#include "or/networkstatus_st.h" +#include "or/vote_routerstatus_st.h" + +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) diff --git a/src/test/fuzz/fuzzing.h b/src/test/fuzz/fuzzing.h index aecdbb4e52..e90e5d58e0 100644 --- a/src/test/fuzz/fuzzing.h +++ b/src/test/fuzz/fuzzing.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef FUZZING_H #define FUZZING_H diff --git a/src/test/fuzz/fuzzing_common.c b/src/test/fuzz/fuzzing_common.c index a96552f0fc..9e736ea69d 100644 --- a/src/test/fuzz/fuzzing_common.c +++ b/src/test/fuzz/fuzzing_common.c @@ -1,13 +1,13 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CRYPTO_ED25519_PRIVATE #include "orconfig.h" -#include "or.h" -#include "backtrace.h" -#include "config.h" -#include "fuzzing.h" -#include "crypto.h" -#include "crypto_ed25519.h" +#include "or/or.h" +#include "lib/err/backtrace.h" +#include "or/config.h" +#include "test/fuzz/fuzzing.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_ed25519.h" static or_options_t *mock_options = NULL; static const or_options_t * diff --git a/src/test/fuzz/include.am b/src/test/fuzz/include.am index cd16dc05be..b09e32d431 100644 --- a/src/test/fuzz/include.am +++ b/src/test/fuzz/include.am @@ -7,31 +7,17 @@ FUZZING_CFLAGS = \ FUZZING_LDFLAG = \ @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@ FUZZING_LIBS = \ - src/or/libtor-testing.a \ - src/common/libor-crypto-testing.a \ - $(LIBKECCAK_TINY) \ - $(LIBDONNA) \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-event-testing.a \ - src/trunnel/libor-trunnel-testing.a \ + $(TOR_INTERNAL_TESTING_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \ @TOR_SYSTEMD_LIBS@ \ @TOR_LZMA_LIBS@ \ @TOR_ZSTD_LIBS@ oss-fuzz-prereqs: \ - src/or/libtor-testing.a \ - src/common/libor-crypto-testing.a \ - $(LIBKECCAK_TINY) \ - $(LIBDONNA) \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-event-testing.a \ - src/trunnel/libor-trunnel-testing.a + $(TOR_INTERNAL_TESTING_LIBS) noinst_HEADERS += \ src/test/fuzz/fuzzing.h diff --git a/src/test/fuzz_static_testcases.sh b/src/test/fuzz_static_testcases.sh index 3cb45ad5e6..138f85b106 100755 --- a/src/test/fuzz_static_testcases.sh +++ b/src/test/fuzz_static_testcases.sh @@ -1,6 +1,6 @@ #!/bin/sh -# Copyright (c) 2016-2017, The Tor Project, Inc. +# Copyright (c) 2016-2018, The Tor Project, Inc. # See LICENSE for licensing information set -e diff --git a/src/test/hs_ntor_ref.py b/src/test/hs_ntor_ref.py index 2ed9324e1f..f892cd8f84 100644 --- a/src/test/hs_ntor_ref.py +++ b/src/test/hs_ntor_ref.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright 2017, The Tor Project, Inc +# Copyright 2017-2018, The Tor Project, Inc # See LICENSE for licensing information """ diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c index 5c1b9123d8..cb7b1fe1b7 100644 --- a/src/test/hs_test_helpers.c +++ b/src/test/hs_test_helpers.c @@ -1,13 +1,13 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "crypto_ed25519.h" -#include "test.h" -#include "torcert.h" +#include "or/or.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "test/test.h" +#include "or/torcert.h" -#include "hs_common.h" -#include "hs_test_helpers.h" +#include "or/hs_common.h" +#include "test/hs_test_helpers.h" hs_desc_intro_point_t * hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now, diff --git a/src/test/hs_test_helpers.h b/src/test/hs_test_helpers.h index b1b0490f05..5c0262207a 100644 --- a/src/test/hs_test_helpers.h +++ b/src/test/hs_test_helpers.h @@ -1,11 +1,11 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_HS_TEST_HELPERS_H #define TOR_HS_TEST_HELPERS_H -#include "ed25519_cert.h" -#include "hs_descriptor.h" +#include "trunnel/ed25519_cert.h" +#include "or/hs_descriptor.h" /* Set of functions to help build and test descriptors. */ hs_desc_intro_point_t *hs_helper_build_intro_point( diff --git a/src/test/include.am b/src/test/include.am index 6b35c248e6..1be56bbffc 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -74,10 +74,8 @@ endif src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \ -DLOCALSTATEDIR="\"$(localstatedir)\"" \ -DBINDIR="\"$(bindir)\"" \ - -I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext" \ - -I"$(top_srcdir)/src/trunnel" \ - -I"$(top_srcdir)/src/ext/trunnel" \ - -DTOR_UNIT_TESTS + -DTOR_UNIT_TESTS \ + $(AM_CPPFLAGS) # -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 @@ -159,7 +157,6 @@ src_test_test_SOURCES += \ src/test/test_proto_misc.c \ src/test/test_protover.c \ src/test/test_pt.c \ - src/test/test_pubsub.c \ src/test/test_relay.c \ src/test/test_relaycell.c \ src/test/test_relaycrypt.c \ @@ -222,27 +219,19 @@ src_test_test_switch_id_CPPFLAGS= $(src_test_AM_CPPFLAGS) src_test_test_switch_id_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_test_test_switch_id_LDFLAGS = @TOR_LDFLAGS_zlib@ src_test_test_switch_id_LDADD = \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ + $(TOR_UTIL_TESTING_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ - @TOR_LIB_WS32@ @TOR_LIB_USERENV@ \ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@ \ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ @TOR_LDFLAGS_libevent@ -src_test_test_LDADD = src/or/libtor-testing.a \ - src/common/libor-crypto-testing.a \ - $(LIBKECCAK_TINY) \ - $(LIBDONNA) \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-event-testing.a \ - src/trunnel/libor-trunnel-testing.a \ - src/trace/libor-trace.a \ +src_test_test_LDADD = \ + $(TOR_INTERNAL_TESTING_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ - @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @@ -261,41 +250,33 @@ src_test_test_memwipe_LDFLAGS = $(src_test_test_LDFLAGS) @CFLAGS_BUGTRAP@ src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ @TOR_LDFLAGS_libevent@ -src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \ - src/common/libor-ctime.a \ - src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \ - src/common/libor-event.a src/trunnel/libor-trunnel.a \ - src/trace/libor-trace.a \ +src_test_bench_LDADD = \ + $(TOR_INTERNAL_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ - @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ @TOR_LDFLAGS_libevent@ -src_test_test_workqueue_LDADD = src/or/libtor-testing.a \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \ - src/common/libor-event-testing.a \ - src/trace/libor-trace.a \ +src_test_test_workqueue_LDADD = \ + $(TOR_INTERNAL_TESTING_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ - @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ src_test_test_timers_CPPFLAGS = $(src_test_test_CPPFLAGS) src_test_test_timers_CFLAGS = $(src_test_test_CFLAGS) src_test_test_timers_LDADD = \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ src/common/libor-event-testing.a \ - src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \ + $(TOR_CRYPTO_TESTING_LIBS) \ + $(TOR_UTIL_TESTING_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ - @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @TOR_LZMA_LIBS@ src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS) @@ -321,36 +302,32 @@ noinst_PROGRAMS+= src/test/test-ntor-cl noinst_PROGRAMS+= src/test/test-hs-ntor-cl src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ -src_test_test_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \ - src/common/libor-ctime.a \ - src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \ - src/trace/libor-trace.a \ +src_test_test_ntor_cl_LDADD = \ + $(TOR_INTERNAL_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ - @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ @TOR_LZMA_LIBS@ src_test_test_ntor_cl_AM_CPPFLAGS = \ - -I"$(top_srcdir)/src/or" + $(AM_CPPFLAGS) src_test_test_hs_ntor_cl_SOURCES = src/test/test_hs_ntor_cl.c src_test_test_hs_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ -src_test_test_hs_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \ - src/common/libor-ctime.a \ - src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \ +src_test_test_hs_ntor_cl_LDADD = \ + $(TOR_INTERNAL_LIBS) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ - @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ src_test_test_hs_ntor_cl_AM_CPPFLAGS = \ - -I"$(top_srcdir)/src/or" + $(AM_CPPFLAGS) noinst_PROGRAMS += src/test/test-bt-cl src_test_test_bt_cl_SOURCES = src/test/test_bt_cl.c -src_test_test_bt_cl_LDADD = src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/trace/libor-trace.a \ +src_test_test_bt_cl_LDADD = \ + $(TOR_UTIL_TESTING_LIBS) \ $(rust_ldadd) \ @TOR_LIB_MATH@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS) diff --git a/src/test/log_test_helpers.c b/src/test/log_test_helpers.c index d5a39cfeee..e814555ba1 100644 --- a/src/test/log_test_helpers.c +++ b/src/test/log_test_helpers.c @@ -1,8 +1,8 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define LOG_PRIVATE -#include "torlog.h" -#include "log_test_helpers.h" +#include "lib/log/torlog.h" +#include "test/log_test_helpers.h" /** * \file log_test_helpers.c diff --git a/src/test/log_test_helpers.h b/src/test/log_test_helpers.h index f5bbfcf3ff..7c38504527 100644 --- a/src/test/log_test_helpers.h +++ b/src/test/log_test_helpers.h @@ -1,7 +1,7 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" +#include "or/or.h" #ifndef TOR_LOG_TEST_HELPERS_H #define TOR_LOG_TEST_HELPERS_H diff --git a/src/test/ntor_ref.py b/src/test/ntor_ref.py index c753588f97..9294827e13 100755 --- a/src/test/ntor_ref.py +++ b/src/test/ntor_ref.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright 2012-2017, The Tor Project, Inc +# Copyright 2012-2018, The Tor Project, Inc # See LICENSE for licensing information """ diff --git a/src/test/rend_test_helpers.c b/src/test/rend_test_helpers.c index 9ac3894b0b..31af58c278 100644 --- a/src/test/rend_test_helpers.c +++ b/src/test/rend_test_helpers.c @@ -1,11 +1,15 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "crypto_rand.h" -#include "test.h" -#include "rendcommon.h" -#include "rend_test_helpers.h" +#include "or/or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "test/test.h" +#include "or/rendcommon.h" +#include "test/rend_test_helpers.h" + +#include "or/extend_info_st.h" +#include "or/rend_intro_point_st.h" +#include "or/rend_service_descriptor_st.h" void generate_desc(int time_diff, rend_encoded_v2_service_descriptor_t **desc, diff --git a/src/test/rend_test_helpers.h b/src/test/rend_test_helpers.h index abf4324988..aca675b2a4 100644 --- a/src/test/rend_test_helpers.h +++ b/src/test/rend_test_helpers.h @@ -1,7 +1,7 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" +#include "or/or.h" #ifndef TOR_REND_TEST_HELPERS_H #define TOR_REND_TEST_HELPERS_H diff --git a/src/test/test-child.c b/src/test/test-child.c index f78a829107..14df1a9b76 100644 --- a/src/test/test-child.c +++ b/src/test/test-child.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ +/* Copyright (c) 2011-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c index aaaf2e7f68..552cbbc551 100644 --- a/src/test/test-memwipe.c +++ b/src/test/test-memwipe.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -7,9 +7,8 @@ #include <sys/types.h> #include <stdlib.h> -#include "crypto_util.h" -#include "compat.h" -#include "util.h" +#include "lib/crypt_ops/crypto_util.h" +#include "common/util.h" static unsigned fill_a_buffer_memset(void) __attribute__((noinline)); static unsigned fill_a_buffer_memwipe(void) __attribute__((noinline)); diff --git a/src/test/test-timers.c b/src/test/test-timers.c index f20f29578b..f6ff9a5f80 100644 --- a/src/test/test-timers.c +++ b/src/test/test-timers.c @@ -1,4 +1,4 @@ -/* Copyright 2016-2017, The Tor Project, Inc. */ +/* Copyright 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -7,11 +7,10 @@ #include <stdio.h> #include <string.h> -#include "compat.h" -#include "compat_libevent.h" -#include "crypto_rand.h" -#include "timers.h" -#include "util.h" +#include "common/compat_libevent.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "common/timers.h" +#include "common/util.h" #define N_TIMERS 1000 #define MAX_DURATION 30 diff --git a/src/test/test.c b/src/test/test.c index f0e8b9b728..e3121293c3 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,7 +9,7 @@ **/ #include "orconfig.h" -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_rand.h" #include <stdio.h> #ifdef HAVE_FCNTL_H @@ -39,28 +39,34 @@ long int lround(double x); double fabs(double x); -#include "or.h" -#include "backtrace.h" -#include "buffers.h" -#include "circuitlist.h" -#include "circuitstats.h" -#include "compress.h" -#include "config.h" -#include "connection_edge.h" -#include "rendcommon.h" -#include "rendcache.h" -#include "test.h" -#include "main.h" -#include "memarea.h" -#include "onion.h" -#include "onion_ntor.h" -#include "onion_fast.h" -#include "onion_tap.h" -#include "policies.h" -#include "rephist.h" -#include "routerparse.h" -#include "statefile.h" -#include "crypto_curve25519.h" +#include "or/or.h" +#include "lib/err/backtrace.h" +#include "lib/container/buffers.h" +#include "or/circuitlist.h" +#include "or/circuitstats.h" +#include "lib/compress/compress.h" +#include "or/config.h" +#include "or/connection_edge.h" +#include "or/rendcommon.h" +#include "or/rendcache.h" +#include "test/test.h" +#include "or/main.h" +#include "lib/memarea/memarea.h" +#include "or/onion.h" +#include "or/onion_ntor.h" +#include "or/onion_fast.h" +#include "or/onion_tap.h" +#include "or/policies.h" +#include "or/rephist.h" +#include "or/routerparse.h" +#include "or/statefile.h" +#include "lib/crypt_ops/crypto_curve25519.h" + +#include "or/extend_info_st.h" +#include "or/or_circuit_st.h" +#include "or/rend_encoded_v2_service_descriptor_st.h" +#include "or/rend_intro_point_st.h" +#include "or/rend_service_descriptor_st.h" /** Run unit tests for the onion handshake code. */ static void @@ -911,10 +917,8 @@ struct testgroup_t testgroups[] = { { "util/format/", util_format_tests }, { "util/logging/", logging_tests }, { "util/process/", util_process_tests }, - { "util/pubsub/", pubsub_tests }, { "util/thread/", thread_tests }, { "util/handle/", handle_tests }, { "dns/", dns_tests }, END_OF_GROUPS }; - diff --git a/src/test/test.h b/src/test/test.h index 63b2b30746..c231bc5f87 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TEST_H @@ -13,7 +13,6 @@ #define DEBUG_SMARTLIST 1 -#include "compat.h" #include "tinytest.h" #define TT_EXIT_TEST_FUNCTION STMT_BEGIN goto done; STMT_END #include "tinytest_macros.h" @@ -248,7 +247,6 @@ extern struct testcase_t procmon_tests[]; extern struct testcase_t proto_http_tests[]; extern struct testcase_t proto_misc_tests[]; extern struct testcase_t protover_tests[]; -extern struct testcase_t pubsub_tests[]; extern struct testcase_t pt_tests[]; extern struct testcase_t relay_tests[]; extern struct testcase_t relaycell_tests[]; @@ -292,4 +290,3 @@ extern const char AUTHORITY_SIGNKEY_C_DIGEST[]; extern const char AUTHORITY_SIGNKEY_C_DIGEST256[]; #endif /* !defined(TOR_TEST_H) */ - diff --git a/src/test/test_accounting.c b/src/test/test_accounting.c index b0d37b2989..ce8e08f7c9 100644 --- a/src/test/test_accounting.c +++ b/src/test/test_accounting.c @@ -1,13 +1,13 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "test.h" +#include "or/or.h" +#include "test/test.h" #define HIBERNATE_PRIVATE -#include "hibernate.h" -#include "config.h" +#include "or/hibernate.h" +#include "or/config.h" #define STATEFILE_PRIVATE -#include "statefile.h" +#include "or/statefile.h" #define NS_MODULE accounting diff --git a/src/test/test_addr.c b/src/test/test_addr.c index 40db31320f..0a3212adbc 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -1,15 +1,15 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ADDRESSMAP_PRIVATE #include "orconfig.h" -#include "or.h" -#include "crypto_rand.h" -#include "test.h" -#include "addressmap.h" -#include "log_test_helpers.h" +#include "or/or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "test/test.h" +#include "or/addressmap.h" +#include "test/log_test_helpers.h" /** Mocking replacement: only handles localhost. */ static int diff --git a/src/test/test_address.c b/src/test/test_address.c index 9c88d37a41..52ca5137e6 100644 --- a/src/test/test_address.c +++ b/src/test/test_address.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ADDRESS_PRIVATE @@ -23,10 +23,10 @@ #include <net/if.h> #endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */ -#include "or.h" -#include "address.h" -#include "test.h" -#include "log_test_helpers.h" +#include "or/or.h" +#include "lib/net/address.h" +#include "test/test.h" +#include "test/log_test_helpers.h" /** Return 1 iff <b>sockaddr1</b> and <b>sockaddr2</b> represent * the same IP address and port combination. Otherwise, return 0. diff --git a/src/test/test_address_set.c b/src/test/test_address_set.c index f7441a6491..3699685848 100644 --- a/src/test/test_address_set.c +++ b/src/test/test_address_set.c @@ -1,16 +1,21 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "crypto_rand.h" -#include "address_set.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "routerlist.h" -#include "torcert.h" - -#include "test.h" +#include "or/or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "common/address_set.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/routerlist.h" +#include "or/torcert.h" + +#include "or/microdesc_st.h" +#include "or/networkstatus_st.h" +#include "or/routerinfo_st.h" +#include "or/routerstatus_st.h" + +#include "test/test.h" static networkstatus_t *dummy_ns = NULL; static networkstatus_t * diff --git a/src/test/test_bridges.c b/src/test/test_bridges.c index c44f791e0d..98e85cd6d8 100644 --- a/src/test/test_bridges.c +++ b/src/test/test_bridges.c @@ -11,16 +11,15 @@ #include <stdbool.h> -#include "or.h" -#include "address.h" -#include "bridges.h" -#include "config.h" -#include "container.h" -#include "transports.h" -#include "util.h" +#include "or/or.h" +#include "lib/net/address.h" +#include "or/bridges.h" +#include "or/config.h" +#include "or/transports.h" +#include "common/util.h" /* Test suite stuff */ -#include "test.h" +#include "test/test.h" /** * A mocked transport_t, constructed via mock_transport_get_by_name(). diff --git a/src/test/test_bt_cl.c b/src/test/test_bt_cl.c index b5c8d7cf9e..c64ca8e2b3 100644 --- a/src/test/test_bt_cl.c +++ b/src/test/test_bt_cl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -7,10 +7,10 @@ /* To prevent 'assert' from going away. */ #undef TOR_COVERAGE -#include "or.h" -#include "util.h" -#include "backtrace.h" -#include "torlog.h" +#include "or/or.h" +#include "common/util.h" +#include "lib/err/backtrace.h" +#include "lib/log/torlog.h" /* -1: no crash. * 0: crash with a segmentation fault. diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c index 868f6a8ba4..66ee997225 100644 --- a/src/test/test_buffers.c +++ b/src/test/test_buffers.c @@ -1,17 +1,17 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define BUFFERS_PRIVATE #define PROTO_HTTP_PRIVATE -#include "or.h" -#include "buffers.h" -#include "buffers_tls.h" -#include "crypto_rand.h" -#include "proto_http.h" -#include "proto_socks.h" -#include "test.h" +#include "or/or.h" +#include "lib/container/buffers.h" +#include "lib/tls/buffers_tls.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/proto_http.h" +#include "or/proto_socks.h" +#include "test/test.h" /** Run unit tests for buffers.c */ static void diff --git a/src/test/test_bwmgt.c b/src/test/test_bwmgt.c index 268917005e..90c1b457d7 100644 --- a/src/test/test_bwmgt.c +++ b/src/test/test_bwmgt.c @@ -8,10 +8,10 @@ #define TOKEN_BUCKET_PRIVATE -#include "or.h" -#include "test.h" +#include "or/or.h" +#include "test/test.h" -#include "token_bucket.h" +#include "common/token_bucket.h" // an imaginary time, in timestamp units. Chosen so it will roll over. static const uint32_t START_TS = UINT32_MAX-10; diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c index 54d9716780..844fa4a16c 100644 --- a/src/test/test_cell_formats.c +++ b/src/test/test_cell_formats.c @@ -1,24 +1,29 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define CONNECTION_EDGE_PRIVATE #define RELAY_PRIVATE -#include "or.h" -#include "channel.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "config.h" -#include "crypto_rand.h" -#include "onion.h" -#include "onion_tap.h" -#include "onion_fast.h" -#include "onion_ntor.h" -#include "relay.h" -#include "test.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/connection_edge.h" +#include "or/connection_or.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/onion.h" +#include "or/onion_tap.h" +#include "or/onion_fast.h" +#include "or/onion_ntor.h" +#include "or/relay.h" + +#include "or/cell_st.h" +#include "or/cell_queue_st.h" +#include "or/var_cell_st.h" + +#include "test/test.h" #include <stdlib.h> #include <string.h> diff --git a/src/test/test_cell_queue.c b/src/test/test_cell_queue.c index df987f82ce..3369511afc 100644 --- a/src/test/test_cell_queue.c +++ b/src/test/test_cell_queue.c @@ -1,12 +1,17 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITLIST_PRIVATE #define RELAY_PRIVATE -#include "or.h" -#include "circuitlist.h" -#include "relay.h" -#include "test.h" +#include "or/or.h" +#include "or/circuitlist.h" +#include "or/relay.h" +#include "test/test.h" + +#include "or/cell_st.h" +#include "or/cell_queue_st.h" +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" static void test_cq_manip(void *arg) diff --git a/src/test/test_channel.c b/src/test/test_channel.c index 76124a6e75..d236580fbd 100644 --- a/src/test/test_channel.c +++ b/src/test/test_channel.c @@ -1,29 +1,35 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TOR_CHANNEL_INTERNAL_ #define CHANNEL_PRIVATE_ -#include "or.h" -#include "channel.h" +#include "or/or.h" +#include "or/channel.h" /* For channel_note_destroy_not_pending */ #define CIRCUITLIST_PRIVATE -#include "circuitlist.h" -#include "circuitmux.h" -#include "circuitmux_ewma.h" +#include "or/circuitlist.h" +#include "or/circuitmux.h" +#include "or/circuitmux_ewma.h" /* For var_cell_free */ -#include "connection_or.h" -#include "crypto_rand.h" +#include "or/connection_or.h" +#include "lib/crypt_ops/crypto_rand.h" /* For packed_cell stuff */ #define RELAY_PRIVATE -#include "relay.h" +#include "or/relay.h" /* For init/free stuff */ -#include "scheduler.h" -#include "networkstatus.h" +#include "or/scheduler.h" +#include "or/networkstatus.h" + +#include "or/cell_st.h" +#include "or/networkstatus_st.h" +#include "or/origin_circuit_st.h" +#include "or/routerstatus_st.h" +#include "or/var_cell_st.h" /* Test suite stuff */ -#include "log_test_helpers.h" -#include "test.h" -#include "fakechans.h" +#include "test/log_test_helpers.h" +#include "test/test.h" +#include "test/fakechans.h" static int test_chan_accept_cells = 0; static int test_chan_fixed_cells_recved = 0; diff --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c index 4261bc1b67..4ae7e16361 100644 --- a/src/test/test_channelpadding.c +++ b/src/test/test_channelpadding.c @@ -1,24 +1,29 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TOR_CHANNEL_INTERNAL_ #define MAIN_PRIVATE #define NETWORKSTATUS_PRIVATE #define TOR_TIMERS_PRIVATE -#include "or.h" -#include "test.h" -#include "testsupport.h" -#include "connection.h" -#include "connection_or.h" -#include "channel.h" -#include "channeltls.h" -#include "channelpadding.h" -#include "compat_libevent.h" -#include "config.h" -#include "compat_time.h" -#include "main.h" -#include "networkstatus.h" -#include "log_test_helpers.h" +#include "or/or.h" +#include "test/test.h" +#include "lib/testsupport/testsupport.h" +#include "or/connection.h" +#include "or/connection_or.h" +#include "or/channel.h" +#include "or/channeltls.h" +#include "or/channelpadding.h" +#include "common/compat_libevent.h" +#include "or/config.h" +#include "lib/time/compat_time.h" +#include "or/main.h" +#include "or/networkstatus.h" +#include "test/log_test_helpers.h" + +#include "or/cell_st.h" +#include "or/networkstatus_st.h" +#include "or/or_connection_st.h" +#include "or/routerstatus_st.h" int channelpadding_get_netflow_inactive_timeout_ms(channel_t *chan); int64_t channelpadding_compute_time_until_pad_for_netflow(channel_t *chan); diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c index 94f1893cae..aed766fc00 100644 --- a/src/test/test_channeltls.c +++ b/src/test/test_channeltls.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -6,20 +6,22 @@ #include <math.h> #define TOR_CHANNEL_INTERNAL_ -#include "or.h" -#include "address.h" -#include "buffers.h" -#include "channel.h" -#include "channeltls.h" -#include "connection_or.h" -#include "config.h" +#include "or/or.h" +#include "lib/net/address.h" +#include "lib/container/buffers.h" +#include "or/channel.h" +#include "or/channeltls.h" +#include "or/connection_or.h" +#include "or/config.h" /* For init/free stuff */ -#include "scheduler.h" -#include "tortls.h" +#include "or/scheduler.h" +#include "lib/tls/tortls.h" + +#include "or/or_connection_st.h" /* Test suite stuff */ -#include "test.h" -#include "fakechans.h" +#include "test/test.h" +#include "test/fakechans.h" /* The channeltls unit tests */ static void test_channeltls_create(void *arg); diff --git a/src/test/test_checkdir.c b/src/test/test_checkdir.c index bf6a8376b3..d0c899a07e 100644 --- a/src/test/test_checkdir.c +++ b/src/test/test_checkdir.c @@ -1,8 +1,8 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "or.h" +#include "or/or.h" #ifdef _WIN32 #include <direct.h> @@ -10,9 +10,9 @@ #include <dirent.h> #endif -#include "config.h" -#include "test.h" -#include "util.h" +#include "or/config.h" +#include "test/test.h" +#include "common/util.h" #ifdef _WIN32 #define mkdir(a,b) mkdir(a) diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c index a5282df69d..d17a04614c 100644 --- a/src/test/test_circuitbuild.c +++ b/src/test/test_circuitbuild.c @@ -1,16 +1,18 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2016, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITBUILD_PRIVATE -#include "or.h" -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" -#include "config.h" -#include "circuitbuild.h" +#include "or/or.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" +#include "or/config.h" +#include "or/circuitbuild.h" + +#include "or/extend_info_st.h" /* Dummy nodes smartlist for testing */ static smartlist_t dummy_nodes; diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c index 3794ffc2c6..4aa7c596ee 100644 --- a/src/test/test_circuitlist.c +++ b/src/test/test_circuitlist.c @@ -1,18 +1,23 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TOR_CHANNEL_INTERNAL_ #define CIRCUITBUILD_PRIVATE #define CIRCUITLIST_PRIVATE #define HS_CIRCUITMAP_PRIVATE -#include "or.h" -#include "channel.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitmux_ewma.h" -#include "hs_circuitmap.h" -#include "test.h" -#include "log_test_helpers.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuitmux_ewma.h" +#include "or/hs_circuitmap.h" +#include "test/test.h" +#include "test/log_test_helpers.h" + +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" + +#include "lib/container/bitarray.h" static channel_t * new_fake_channel(void) @@ -467,4 +472,3 @@ struct testcase_t circuitlist_tests[] = { TT_FORK, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_circuitmux.c b/src/test/test_circuitmux.c index 14c7598703..8a89927df9 100644 --- a/src/test/test_circuitmux.c +++ b/src/test/test_circuitmux.c @@ -1,17 +1,19 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TOR_CHANNEL_INTERNAL_ #define CIRCUITMUX_PRIVATE #define CIRCUITMUX_EWMA_PRIVATE #define RELAY_PRIVATE -#include "or.h" -#include "channel.h" -#include "circuitmux.h" -#include "circuitmux_ewma.h" -#include "relay.h" -#include "scheduler.h" -#include "test.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/circuitmux.h" +#include "or/circuitmux_ewma.h" +#include "or/relay.h" +#include "or/scheduler.h" +#include "test/test.h" + +#include "or/destroy_cell_queue_st.h" /* XXXX duplicated function from test_circuitlist.c */ static channel_t * diff --git a/src/test/test_circuitstats.c b/src/test/test_circuitstats.c index 8ebef659ca..94ba6ed448 100644 --- a/src/test/test_circuitstats.c +++ b/src/test/test_circuitstats.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITBUILD_PRIVATE @@ -6,16 +6,21 @@ #define CIRCUITLIST_PRIVATE #define CHANNEL_PRIVATE_ -#include "or.h" -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" -#include "config.h" -#include "circuitlist.h" -#include "circuitbuild.h" -#include "circuitstats.h" -#include "circuituse.h" -#include "channel.h" +#include "or/or.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" +#include "or/config.h" +#include "or/circuitlist.h" +#include "or/circuitbuild.h" +#include "or/circuitstats.h" +#include "or/circuituse.h" +#include "or/channel.h" + +#include "or/cpath_build_state_st.h" +#include "or/crypt_path_st.h" +#include "or/extend_info_st.h" +#include "or/origin_circuit_st.h" void test_circuitstats_timeout(void *arg); void test_circuitstats_hoplen(void *arg); diff --git a/src/test/test_circuituse.c b/src/test/test_circuituse.c index df1b43807f..2524e43c68 100644 --- a/src/test/test_circuituse.c +++ b/src/test/test_circuituse.c @@ -1,18 +1,21 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITLIST_PRIVATE -#include "or.h" -#include "test.h" -#include "test_helpers.h" -#include "config.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "circuitbuild.h" -#include "nodelist.h" +#include "or/or.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "or/config.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "or/circuitbuild.h" +#include "or/nodelist.h" + +#include "or/cpath_build_state_st.h" +#include "or/origin_circuit_st.h" static void test_circuit_is_available_for_use_ret_false_when_marked_for_close(void *arg) diff --git a/src/test/test_compat_libevent.c b/src/test/test_compat_libevent.c index 85f69bd626..8e59137856 100644 --- a/src/test/test_compat_libevent.c +++ b/src/test/test_compat_libevent.c @@ -1,17 +1,17 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define COMPAT_LIBEVENT_PRIVATE #include "orconfig.h" -#include "or.h" +#include "or/or.h" -#include "test.h" +#include "test/test.h" -#include "compat_libevent.h" +#include "common/compat_libevent.h" #include <event2/event.h> -#include "log_test_helpers.h" +#include "test/log_test_helpers.h" #define NS_MODULE compat_libevent diff --git a/src/test/test_config.c b/src/test/test_config.c index 461aa646d6..1138989826 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -8,41 +8,49 @@ #define CONFIG_PRIVATE #define PT_PRIVATE #define ROUTERSET_PRIVATE -#include "or.h" -#include "address.h" -#include "addressmap.h" -#include "bridges.h" -#include "circuitmux_ewma.h" -#include "circuitbuild.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "connection_edge.h" -#include "test.h" -#include "util.h" -#include "connection_or.h" -#include "control.h" -#include "cpuworker.h" -#include "dirserv.h" -#include "dirauth/dirvote.h" -#include "dns.h" -#include "entrynodes.h" -#include "transports.h" -#include "ext_orport.h" -#include "geoip.h" -#include "hibernate.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "rendclient.h" -#include "rendservice.h" -#include "router.h" -#include "routerlist.h" -#include "routerset.h" -#include "statefile.h" - -#include "test_helpers.h" +#include "or/or.h" +#include "lib/net/address.h" +#include "or/addressmap.h" +#include "or/bridges.h" +#include "or/circuitmux_ewma.h" +#include "or/circuitbuild.h" +#include "or/config.h" +#include "or/confparse.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "test/test.h" +#include "common/util.h" +#include "or/connection_or.h" +#include "or/control.h" +#include "or/cpuworker.h" +#include "or/dirserv.h" +#include "or/dirauth/dirvote.h" +#include "or/dns.h" +#include "or/entrynodes.h" +#include "or/transports.h" +#include "or/ext_orport.h" +#include "or/geoip.h" +#include "or/hibernate.h" +#include "or/main.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/rendclient.h" +#include "or/rendservice.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerset.h" +#include "or/statefile.h" + +#include "test/test_helpers.h" + +#include "or/dir_server_st.h" +#include "or/port_cfg_st.h" +#include "or/routerinfo_st.h" + +#include "lib/fs/conffile.h" +#include "lib/meminfo/meminfo.h" +#include "lib/net/gethostname.h" static void test_config_addressmap(void *arg) @@ -5727,4 +5735,3 @@ struct testcase_t config_tests[] = { CONFIG_TEST(compute_max_mem_in_queues, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_connection.c b/src/test/test_connection.c index dc0f6860d9..674e2284e6 100644 --- a/src/test/test_connection.c +++ b/src/test/test_connection.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -7,21 +7,29 @@ #define MAIN_PRIVATE #define CONNECTION_OR_PRIVATE -#include "or.h" -#include "test.h" - -#include "connection.h" -#include "hs_common.h" -#include "main.h" -#include "microdesc.h" -#include "nodelist.h" -#include "networkstatus.h" -#include "rendcache.h" -#include "directory.h" -#include "connection_or.h" - -#include "test_connection.h" -#include "test_helpers.h" +#include "or/or.h" +#include "test/test.h" + +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/hs_common.h" +#include "or/main.h" +#include "or/microdesc.h" +#include "or/nodelist.h" +#include "or/networkstatus.h" +#include "or/rendcache.h" +#include "or/directory.h" +#include "or/connection_or.h" + +#include "test/test_connection.h" +#include "test/test_helpers.h" + +#include "or/dir_connection_st.h" +#include "or/entry_connection_st.h" +#include "or/node_st.h" +#include "or/or_connection_st.h" +#include "or/routerinfo_st.h" +#include "or/socks_request_st.h" static void * test_conn_get_basic_setup(const struct testcase_t *tc); static int test_conn_get_basic_teardown(const struct testcase_t *tc, diff --git a/src/test/test_connection.h b/src/test/test_connection.h index 392783b53b..27c296504a 100644 --- a/src/test/test_connection.h +++ b/src/test/test_connection.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** Some constants used by test_connection and helpers */ diff --git a/src/test/test_conscache.c b/src/test/test_conscache.c index ffec3149b0..e3a617fe3e 100644 --- a/src/test/test_conscache.c +++ b/src/test/test_conscache.c @@ -1,10 +1,10 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "config.h" -#include "conscache.h" -#include "test.h" +#include "or/or.h" +#include "or/config.h" +#include "or/conscache.h" +#include "test/test.h" #ifdef HAVE_UTIME_H #include <utime.h> diff --git a/src/test/test_consdiff.c b/src/test/test_consdiff.c index fda3a7f186..38947a225b 100644 --- a/src/test/test_consdiff.c +++ b/src/test/test_consdiff.c @@ -1,15 +1,15 @@ /* Copyright (c) 2014, Daniel Martà - * Copyright (c) 2014, The Tor Project, Inc. */ + * Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONSDIFF_PRIVATE -#include "or.h" -#include "test.h" +#include "or/or.h" +#include "test/test.h" -#include "consdiff.h" -#include "memarea.h" -#include "log_test_helpers.h" +#include "or/consdiff.h" +#include "lib/memarea/memarea.h" +#include "test/log_test_helpers.h" #define tt_str_eq_line(a,b) \ tt_assert(line_str_eq((b),(a))) diff --git a/src/test/test_consdiffmgr.c b/src/test/test_consdiffmgr.c index 3b91baca39..c09586afcc 100644 --- a/src/test/test_consdiffmgr.c +++ b/src/test/test_consdiffmgr.c @@ -1,21 +1,23 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONSDIFFMGR_PRIVATE -#include "or.h" -#include "config.h" -#include "conscache.h" -#include "consdiff.h" -#include "consdiffmgr.h" -#include "cpuworker.h" -#include "crypto_rand.h" -#include "networkstatus.h" -#include "routerparse.h" -#include "workqueue.h" - -#include "test.h" -#include "log_test_helpers.h" +#include "or/or.h" +#include "or/config.h" +#include "or/conscache.h" +#include "or/consdiff.h" +#include "or/consdiffmgr.h" +#include "or/cpuworker.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/networkstatus.h" +#include "or/routerparse.h" +#include "common/workqueue.h" + +#include "or/networkstatus_st.h" + +#include "test/test.h" +#include "test/log_test_helpers.h" // ============================== Setup/teardown the consdiffmgr // These functions get run before/after each test in this module diff --git a/src/test/test_containers.c b/src/test/test_containers.c index 3fc3523af4..5c712a9b16 100644 --- a/src/test/test_containers.c +++ b/src/test/test_containers.c @@ -1,13 +1,17 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "or.h" -#include "crypto_rand.h" -#include "fp_pair.h" -#include "test.h" +#include "or/or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/fp_pair.h" +#include "test/test.h" + +#include "lib/container/bitarray.h" +#include "lib/container/order.h" +#include "lib/crypt_ops/digestset.h" /** Helper: return a tristate based on comparing the strings in *<b>a</b> and * *<b>b</b>. */ @@ -640,18 +644,18 @@ test_container_digestset(void *arg) } set = digestset_new(1000); SMARTLIST_FOREACH(included, const char *, cp, - if (digestset_contains(set, cp)) + if (digestset_probably_contains(set, cp)) ok = 0); tt_assert(ok); SMARTLIST_FOREACH(included, const char *, cp, digestset_add(set, cp)); SMARTLIST_FOREACH(included, const char *, cp, - if (!digestset_contains(set, cp)) + if (!digestset_probably_contains(set, cp)) ok = 0); tt_assert(ok); for (i = 0; i < 1000; ++i) { crypto_rand(d, DIGEST_LEN); - if (digestset_contains(set, d)) + if (digestset_probably_contains(set, d)) ++false_positives; } tt_int_op(50, OP_GT, false_positives); /* Should be far lower. */ @@ -1295,4 +1299,3 @@ struct testcase_t container_tests[] = { CONTAINER(smartlist_strings_eq, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_controller.c b/src/test/test_controller.c index 1a350f66c0..de8e4630cd 100644 --- a/src/test/test_controller.c +++ b/src/test/test_controller.c @@ -1,17 +1,23 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONTROL_PRIVATE -#include "or.h" -#include "bridges.h" -#include "control.h" -#include "entrynodes.h" -#include "hs_common.h" -#include "networkstatus.h" -#include "rendservice.h" -#include "routerlist.h" -#include "test.h" -#include "test_helpers.h" +#include "or/or.h" +#include "or/bridges.h" +#include "or/control.h" +#include "or/entrynodes.h" +#include "or/hs_common.h" +#include "or/networkstatus.h" +#include "or/rendservice.h" +#include "or/routerlist.h" +#include "or/nodelist.h" +#include "test/test.h" +#include "test/test_helpers.h" + +#include "or/control_connection_st.h" +#include "or/download_status_st.h" +#include "or/microdesc_st.h" +#include "or/node_st.h" static void test_add_onion_helper_keyarg_v3(void *arg) @@ -1525,6 +1531,80 @@ test_current_time(void *arg) return; } +static size_t n_nodelist_get_list = 0; +static smartlist_t *nodes = NULL; + +static smartlist_t * +mock_nodelist_get_list(void) +{ + n_nodelist_get_list++; + tor_assert(nodes); + + return nodes; +} + +static void +test_getinfo_md_all(void *arg) +{ + char *answer = NULL; + const char *errmsg = NULL; + int retval = 0; + + (void)arg; + + node_t *node1 = tor_malloc(sizeof(node_t)); + memset(node1, 0, sizeof(node_t)); + node1->md = tor_malloc(sizeof(microdesc_t)); + memset(node1->md, 0, sizeof(microdesc_t)); + node1->md->body = tor_strdup("md1\n"); + node1->md->bodylen = 4; + + node_t *node2 = tor_malloc(sizeof(node_t)); + memset(node2, 0, sizeof(node_t)); + node2->md = tor_malloc(sizeof(microdesc_t)); + memset(node2->md, 0, sizeof(microdesc_t)); + node2->md->body = tor_strdup("md2\n"); + node2->md->bodylen = 4; + + MOCK(nodelist_get_list, mock_nodelist_get_list); + + nodes = smartlist_new(); + + retval = getinfo_helper_dir(NULL, "md/all", &answer, &errmsg); + + tt_int_op(n_nodelist_get_list, OP_EQ, 1); + tt_int_op(retval, OP_EQ, 0); + tt_assert(answer != NULL); + tt_assert(errmsg == NULL); + tt_str_op(answer, OP_EQ, ""); + + tor_free(answer); + + smartlist_add(nodes, node1); + smartlist_add(nodes, node2); + + retval = getinfo_helper_dir(NULL, "md/all", &answer, &errmsg); + + tt_int_op(n_nodelist_get_list, OP_EQ, 2); + tt_int_op(retval, OP_EQ, 0); + tt_assert(answer != NULL); + tt_assert(errmsg == NULL); + + tt_str_op(answer, OP_EQ, "md1\nmd2\n"); + + done: + UNMOCK(nodelist_get_list); + tor_free(node1->md->body); + tor_free(node1->md); + tor_free(node1); + tor_free(node2->md->body); + tor_free(node2->md); + tor_free(node2); + tor_free(answer); + smartlist_free(nodes); + return; +} + struct testcase_t controller_tests[] = { { "add_onion_helper_keyarg_v2", test_add_onion_helper_keyarg_v2, 0, NULL, NULL }, @@ -1542,6 +1622,7 @@ struct testcase_t controller_tests[] = { { "download_status_desc", test_download_status_desc, 0, NULL, NULL }, { "download_status_bridge", test_download_status_bridge, 0, NULL, NULL }, { "current_time", test_current_time, 0, NULL, NULL }, + { "getinfo_md_all", test_getinfo_md_all, 0, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c index e81aea8d66..b642a37d22 100644 --- a/src/test/test_controller_events.c +++ b/src/test/test_controller_events.c @@ -1,15 +1,18 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONNECTION_PRIVATE #define TOR_CHANNEL_INTERNAL_ #define CONTROL_PRIVATE -#include "or.h" -#include "channel.h" -#include "channeltls.h" -#include "connection.h" -#include "control.h" -#include "test.h" +#include "or/or.h" +#include "or/channel.h" +#include "or/channeltls.h" +#include "or/connection.h" +#include "or/control.h" +#include "test/test.h" + +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" static void add_testing_cell_stats_entry(circuit_t *circ, uint8_t command, diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index bb2e340dd2..e8a2efe597 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -1,19 +1,19 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define CRYPTO_CURVE25519_PRIVATE #define CRYPTO_RAND_PRIVATE -#include "or.h" -#include "test.h" -#include "aes.h" -#include "util.h" +#include "or/or.h" +#include "test/test.h" +#include "lib/crypt_ops/aes.h" +#include "common/util.h" #include "siphash.h" -#include "crypto_curve25519.h" -#include "crypto_ed25519.h" -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_rand.h" #include "ed25519_vectors.inc" /** Run unit tests for Diffie-Hellman functionality. */ @@ -152,8 +152,13 @@ test_crypto_openssl_version(void *arg) const char *h_version = crypto_openssl_get_header_version_str(); tt_assert(version); tt_assert(h_version); - tt_assert(!strcmpstart(version, h_version)); /* "-fips" suffix, etc */ - tt_assert(!strstr(version, "OpenSSL")); + if (strcmpstart(version, h_version)) { /* "-fips" suffix, etc */ + TT_DIE(("OpenSSL library version %s did not begin with header version %s.", + version, h_version)); + } + if (strstr(version, "OpenSSL")) { + TT_DIE(("assertion failed: !strstr(\"%s\", \"OpenSSL\")", version)); + } int a=-1,b=-1,c=-1; if (!strcmpstart(version, "LibreSSL") || !strcmpstart(version, "BoringSSL")) return; @@ -1817,15 +1822,6 @@ test_crypto_hkdf_sha256(void *arg) key_material, 100) /* Test vectors generated with ntor_ref.py */ - memset(key_material, 0, sizeof(key_material)); - EXPAND(""); - tt_int_op(r, OP_EQ, 0); - test_memeq_hex(key_material, - "d3490ed48b12a48f9547861583573fe3f19aafe3f81dc7fc75" - "eeed96d741b3290f941576c1f9f0b2d463d1ec7ab2c6bf71cd" - "d7f826c6298c00dbfe6711635d7005f0269493edf6046cc7e7" - "dcf6abe0d20c77cf363e8ffe358927817a3d3e73712cee28d8"); - EXPAND("Tor"); tt_int_op(r, OP_EQ, 0); test_memeq_hex(key_material, diff --git a/src/test/test_crypto_openssl.c b/src/test/test_crypto_openssl.c index a016277508..d443ba6fd0 100644 --- a/src/test/test_crypto_openssl.c +++ b/src/test/test_crypto_openssl.c @@ -1,21 +1,20 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define CRYPTO_RAND_PRIVATE -#include "crypto_rand.h" -#include "util.h" -#include "util_format.h" -#include "compat.h" -#include "test.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "common/util.h" +#include "lib/encoding/binascii.h" +#include "test/test.h" #include <openssl/evp.h> #include <openssl/rand.h> -#include "compat_openssl.h" +#include "lib/crypt_ops/compat_openssl.h" /* Test for rectifying openssl RAND engine. */ static void diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c index 0e1f5bd227..9878a0d026 100644 --- a/src/test/test_crypto_slow.c +++ b/src/test/test_crypto_slow.c @@ -1,15 +1,15 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define CRYPTO_S2K_PRIVATE -#include "or.h" -#include "test.h" -#include "crypto_s2k.h" -#include "crypto_pwbox.h" -#include "crypto_rand.h" +#include "or/or.h" +#include "test/test.h" +#include "lib/crypt_ops/crypto_s2k.h" +#include "lib/crypt_ops/crypto_pwbox.h" +#include "lib/crypt_ops/crypto_rand.h" #if defined(HAVE_LIBSCRYPT_H) && defined(HAVE_LIBSCRYPT_SCRYPT) #define HAVE_LIBSCRYPT diff --git a/src/test/test_data.c b/src/test/test_data.c index ce6c3394f6..be8153258b 100644 --- a/src/test/test_data.c +++ b/src/test/test_data.c @@ -1,9 +1,9 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "test.h" +#include "test/test.h" /* Our unit test expect that the AUTHORITY_CERT_* public keys will sort * in this order. */ diff --git a/src/test/test_dir.c b/src/test/test_dir.c index b42755e351..498ecf942e 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -17,32 +17,47 @@ #define NETWORKSTATUS_PRIVATE #define RELAY_PRIVATE -#include "or.h" -#include "bridges.h" -#include "confparse.h" -#include "config.h" -#include "control.h" -#include "crypto_ed25519.h" -#include "crypto_rand.h" -#include "directory.h" -#include "dirserv.h" -#include "dirauth/dirvote.h" -#include "entrynodes.h" -#include "hibernate.h" -#include "memarea.h" -#include "networkstatus.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "dirauth/shared_random_state.h" -#include "test.h" -#include "test_dir_common.h" -#include "torcert.h" -#include "relay.h" -#include "log_test_helpers.h" -#include "voting_schedule.h" +#include "or/or.h" +#include "or/bridges.h" +#include "or/confparse.h" +#include "or/config.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/directory.h" +#include "or/dirserv.h" +#include "or/dirauth/dirvote.h" +#include "or/entrynodes.h" +#include "or/fp_pair.h" +#include "or/hibernate.h" +#include "lib/memarea/memarea.h" +#include "lib/osinfo/uname.h" +#include "or/networkstatus.h" +#include "or/router.h" +#include "or/routerkeys.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/routerset.h" +#include "or/dirauth/shared_random_state.h" +#include "test/test.h" +#include "test/test_dir_common.h" +#include "or/torcert.h" +#include "or/relay.h" +#include "test/log_test_helpers.h" +#include "or/voting_schedule.h" + +#include "or/authority_cert_st.h" +#include "or/document_signature_st.h" +#include "or/extrainfo_st.h" +#include "or/networkstatus_st.h" +#include "or/networkstatus_voter_info_st.h" +#include "or/ns_detached_signatures_st.h" +#include "or/port_cfg_st.h" +#include "or/routerinfo_st.h" +#include "or/routerlist_st.h" +#include "or/tor_version_st.h" +#include "or/vote_microdesc_hash_st.h" +#include "or/vote_routerstatus_st.h" #define NS_MODULE dir @@ -6028,4 +6043,3 @@ struct testcase_t dir_tests[] = { DIR(networkstatus_consensus_has_ipv6, TT_FORK), END_OF_TESTCASES }; - diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c index 230410f7fa..a758421cde 100644 --- a/src/test/test_dir_common.c +++ b/src/test/test_dir_common.c @@ -1,18 +1,24 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define DIRVOTE_PRIVATE -#include "test.h" -#include "container.h" -#include "or.h" -#include "dirauth/dirvote.h" -#include "nodelist.h" -#include "routerlist.h" -#include "test_dir_common.h" -#include "voting_schedule.h" +#include "test/test.h" +#include "or/or.h" +#include "or/dirauth/dirvote.h" +#include "or/nodelist.h" +#include "or/routerlist.h" +#include "test/test_dir_common.h" +#include "or/voting_schedule.h" + +#include "or/authority_cert_st.h" +#include "or/networkstatus_st.h" +#include "or/networkstatus_voter_info_st.h" +#include "or/routerinfo_st.h" +#include "or/vote_microdesc_hash_st.h" +#include "or/vote_routerstatus_st.h" void dir_common_setup_vote(networkstatus_t **vote, time_t now); networkstatus_t * dir_common_add_rs_and_parse(networkstatus_t *vote, diff --git a/src/test/test_dir_common.h b/src/test/test_dir_common.h index 65b9cf6436..7d5f55afe6 100644 --- a/src/test/test_dir_common.h +++ b/src/test/test_dir_common.h @@ -1,11 +1,11 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "networkstatus.h" -#include "routerparse.h" +#include "or/or.h" +#include "or/networkstatus.h" +#include "or/routerparse.h" #define TEST_DIR_ROUTER_ID_1 3 #define TEST_DIR_ROUTER_ID_2 5 diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c index 688d26bdc1..90ca7d357c 100644 --- a/src/test/test_dir_handle_get.c +++ b/src/test/test_dir_handle_get.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define RENDCOMMON_PRIVATE @@ -9,30 +9,37 @@ #define CONFIG_PRIVATE #define RENDCACHE_PRIVATE -#include "or.h" -#include "config.h" -#include "connection.h" -#include "consdiffmgr.h" -#include "directory.h" -#include "test.h" -#include "compress.h" -#include "rendcommon.h" -#include "rendcache.h" -#include "router.h" -#include "routerlist.h" -#include "rend_test_helpers.h" -#include "microdesc.h" -#include "test_helpers.h" -#include "nodelist.h" -#include "entrynodes.h" -#include "routerparse.h" -#include "networkstatus.h" -#include "proto_http.h" -#include "geoip.h" -#include "dirserv.h" -#include "dirauth/dirvote.h" -#include "log_test_helpers.h" -#include "voting_schedule.h" +#include "or/or.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/consdiffmgr.h" +#include "or/directory.h" +#include "test/test.h" +#include "lib/compress/compress.h" +#include "or/rendcommon.h" +#include "or/rendcache.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "test/rend_test_helpers.h" +#include "or/microdesc.h" +#include "test/test_helpers.h" +#include "or/nodelist.h" +#include "or/entrynodes.h" +#include "or/routerparse.h" +#include "or/networkstatus.h" +#include "or/proto_http.h" +#include "or/geoip.h" +#include "or/dirserv.h" +#include "or/dirauth/dirvote.h" +#include "test/log_test_helpers.h" +#include "or/voting_schedule.h" + +#include "or/dir_connection_st.h" +#include "or/dir_server_st.h" +#include "or/networkstatus_st.h" +#include "or/rend_encoded_v2_service_descriptor_st.h" +#include "or/routerinfo_st.h" +#include "or/routerlist_st.h" #ifdef _WIN32 /* For mkdir() */ diff --git a/src/test/test_dns.c b/src/test/test_dns.c index 1fee01d2c0..3bcef0aa7c 100644 --- a/src/test/test_dns.c +++ b/src/test/test_dns.c @@ -1,14 +1,17 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "test.h" +#include "or/or.h" +#include "test/test.h" #define DNS_PRIVATE -#include "dns.h" -#include "connection.h" -#include "router.h" +#include "or/dns.h" +#include "or/connection.h" +#include "or/router.h" + +#include "or/edge_connection_st.h" +#include "or/or_circuit_st.h" #define NS_MODULE dns diff --git a/src/test/test_dos.c b/src/test/test_dos.c index 8ae967f3ae..4ba24292ca 100644 --- a/src/test/test_dos.c +++ b/src/test/test_dos.c @@ -5,18 +5,23 @@ #define TOR_CHANNEL_INTERNAL_ #define CIRCUITLIST_PRIVATE -#include "or.h" -#include "dos.h" -#include "circuitlist.h" -#include "crypto_rand.h" -#include "geoip.h" -#include "channel.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "routerlist.h" -#include "test.h" -#include "log_test_helpers.h" +#include "or/or.h" +#include "or/dos.h" +#include "or/circuitlist.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/geoip.h" +#include "or/channel.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/routerlist.h" + +#include "or/networkstatus_st.h" +#include "or/or_connection_st.h" +#include "or/routerstatus_st.h" + +#include "test/test.h" +#include "test/log_test_helpers.h" static networkstatus_t *dummy_ns = NULL; static networkstatus_t * diff --git a/src/test/test_entryconn.c b/src/test/test_entryconn.c index 9d8a072c77..d6ac5e1d38 100644 --- a/src/test/test_entryconn.c +++ b/src/test/test_entryconn.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -6,18 +6,21 @@ #define CONNECTION_PRIVATE #define CONNECTION_EDGE_PRIVATE -#include "or.h" -#include "test.h" +#include "or/or.h" +#include "test/test.h" -#include "addressmap.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "connection_edge.h" -#include "nodelist.h" +#include "or/addressmap.h" +#include "or/config.h" +#include "or/confparse.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/nodelist.h" -#include "hs_cache.h" -#include "rendcache.h" +#include "or/hs_cache.h" +#include "or/rendcache.h" + +#include "or/entry_connection_st.h" +#include "or/socks_request_st.h" static void * entryconn_rewrite_setup(const struct testcase_t *tc) diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index cfcb88a66e..4d37d0fe88 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -10,28 +10,40 @@ #define ROUTERLIST_PRIVATE #define DIRECTORY_PRIVATE -#include "or.h" -#include "test.h" - -#include "bridges.h" -#include "circuitlist.h" -#include "circuitbuild.h" -#include "config.h" -#include "confparse.h" -#include "crypto_rand.h" -#include "directory.h" -#include "entrynodes.h" -#include "nodelist.h" -#include "networkstatus.h" -#include "policies.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "statefile.h" -#include "util.h" - -#include "test_helpers.h" -#include "log_test_helpers.h" +#include "or/or.h" +#include "test/test.h" + +#include "or/bridges.h" +#include "or/circuitlist.h" +#include "or/circuitbuild.h" +#include "or/config.h" +#include "or/confparse.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/directory.h" +#include "or/entrynodes.h" +#include "or/nodelist.h" +#include "or/networkstatus.h" +#include "or/policies.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/routerset.h" +#include "or/statefile.h" +#include "common/util.h" + +#include "or/cpath_build_state_st.h" +#include "or/crypt_path_st.h" +#include "or/dir_connection_st.h" +#include "or/microdesc_st.h" +#include "or/networkstatus_st.h" +#include "or/node_st.h" +#include "or/origin_circuit_st.h" +#include "or/routerinfo_st.h" +#include "or/routerstatus_st.h" + +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" + +#include "lib/container/bloomfilt.h" /* TODO: * choose_random_entry() test with state set. @@ -3064,4 +3076,3 @@ struct testcase_t entrynodes_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c index e05342cb8a..0032ef5b78 100644 --- a/src/test/test_extorport.c +++ b/src/test/test_extorport.c @@ -1,19 +1,22 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONNECTION_PRIVATE #define EXT_ORPORT_PRIVATE #define MAIN_PRIVATE -#include "or.h" -#include "buffers.h" -#include "connection.h" -#include "connection_or.h" -#include "config.h" -#include "control.h" -#include "crypto_rand.h" -#include "ext_orport.h" -#include "main.h" -#include "test.h" +#include "or/or.h" +#include "lib/container/buffers.h" +#include "or/connection.h" +#include "or/connection_or.h" +#include "or/config.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/ext_orport.h" +#include "or/main.h" + +#include "or/or_connection_st.h" + +#include "test/test.h" /* Test connection_or_remove_from_ext_or_id_map and * connection_or_set_ext_or_identifier */ diff --git a/src/test/test_geoip.c b/src/test/test_geoip.c index 6f849f436b..d50dd134e0 100644 --- a/src/test/test_geoip.c +++ b/src/test/test_geoip.c @@ -8,10 +8,10 @@ /* These macros pull in declarations for some functions and structures that * are typically file-private. */ #define GEOIP_PRIVATE -#include "or.h" -#include "config.h" -#include "geoip.h" -#include "test.h" +#include "or/or.h" +#include "or/config.h" +#include "or/geoip.h" +#include "test/test.h" /* Record odd numbered fake-IPs using ipv6, even numbered fake-IPs * using ipv4. Since our fake geoip database is the same between diff --git a/src/test/test_guardfraction.c b/src/test/test_guardfraction.c index 51ca8f08ec..b7737cafa8 100644 --- a/src/test/test_guardfraction.c +++ b/src/test/test_guardfraction.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DIRSERV_PRIVATE @@ -6,18 +6,21 @@ #define NETWORKSTATUS_PRIVATE #include "orconfig.h" -#include "or.h" -#include "config.h" -#include "dirserv.h" -#include "container.h" -#include "entrynodes.h" -#include "util.h" -#include "routerparse.h" -#include "networkstatus.h" - -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" +#include "or/or.h" +#include "or/config.h" +#include "or/dirserv.h" +#include "or/entrynodes.h" +#include "common/util.h" +#include "or/routerparse.h" +#include "or/networkstatus.h" + +#include "or/networkstatus_st.h" +#include "or/vote_microdesc_hash_st.h" +#include "or/vote_routerstatus_st.h" + +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" /** Generate a vote_routerstatus_t for a router with identity digest * <b>digest_in_hex</b>. */ diff --git a/src/test/test_handles.c b/src/test/test_handles.c index eb1e1f1bbe..153ac5787b 100644 --- a/src/test/test_handles.c +++ b/src/test/test_handles.c @@ -1,11 +1,11 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "test.h" +#include "test/test.h" -#include "util.h" -#include "handles.h" +#include "common/util.h" +#include "common/handles.h" typedef struct demo_t { HANDLE_ENTRY(demo, demo_t); diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c index 1db5e9064f..ba279c790b 100644 --- a/src/test/test_helpers.c +++ b/src/test/test_helpers.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,21 +12,27 @@ #define MAIN_PRIVATE #include "orconfig.h" -#include "or.h" - -#include "buffers.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "crypto_rand.h" -#include "main.h" -#include "nodelist.h" -#include "relay.h" -#include "routerlist.h" - -#include "test.h" -#include "test_helpers.h" -#include "test_connection.h" +#include "or/or.h" + +#include "lib/container/buffers.h" +#include "or/config.h" +#include "or/confparse.h" +#include "or/connection.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/main.h" +#include "or/nodelist.h" +#include "or/relay.h" +#include "or/routerlist.h" + +#include "or/cell_st.h" +#include "or/connection_st.h" +#include "or/node_st.h" +#include "or/origin_circuit_st.h" +#include "or/routerlist_st.h" + +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/test_connection.h" #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS DISABLE_GCC_WARNING(overlength-strings) @@ -34,7 +40,7 @@ DISABLE_GCC_WARNING(overlength-strings) * at large. */ #endif #include "test_descriptors.inc" -#include "circuitlist.h" +#include "or/circuitlist.h" #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS ENABLE_GCC_WARNING(overlength-strings) #endif diff --git a/src/test/test_helpers.h b/src/test/test_helpers.h index 9bc8553257..c6339d97fa 100644 --- a/src/test/test_helpers.h +++ b/src/test/test_helpers.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TEST_HELPERS_H #define TOR_TEST_HELPERS_H -#include "or.h" +#include "or/or.h" const char *get_yesterday_date_str(void); diff --git a/src/test/test_hs.c b/src/test/test_hs.c index 07daebc164..84598d9cc4 100644 --- a/src/test/test_hs.c +++ b/src/test/test_hs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,16 +12,22 @@ #define RENDSERVICE_PRIVATE #define HS_SERVICE_PRIVATE -#include "or.h" -#include "test.h" -#include "control.h" -#include "config.h" -#include "hs_common.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "routerset.h" -#include "circuitbuild.h" -#include "test_helpers.h" +#include "or/or.h" +#include "test/test.h" +#include "or/control.h" +#include "or/config.h" +#include "or/hs_common.h" +#include "or/rendcommon.h" +#include "or/rendservice.h" +#include "or/routerset.h" +#include "or/circuitbuild.h" + +#include "or/node_st.h" +#include "or/rend_encoded_v2_service_descriptor_st.h" +#include "or/rend_intro_point_st.h" +#include "or/routerinfo_st.h" + +#include "test/test_helpers.h" /* mock ID digest and longname for node that's in nodelist */ #define HSDIR_EXIST_ID "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" \ diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c index 458ce1a92e..ccad3062b7 100644 --- a/src/test/test_hs_cache.c +++ b/src/test/test_hs_cache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,17 +10,20 @@ #define DIRECTORY_PRIVATE #define HS_CACHE_PRIVATE -#include "ed25519_cert.h" -#include "hs_cache.h" -#include "rendcache.h" -#include "directory.h" -#include "networkstatus.h" -#include "connection.h" -#include "proto_http.h" - -#include "hs_test_helpers.h" -#include "test_helpers.h" -#include "test.h" +#include "trunnel/ed25519_cert.h" +#include "or/hs_cache.h" +#include "or/rendcache.h" +#include "or/directory.h" +#include "or/networkstatus.h" +#include "or/connection.h" +#include "or/proto_http.h" + +#include "or/dir_connection_st.h" +#include "or/networkstatus_st.h" + +#include "test/hs_test_helpers.h" +#include "test/test_helpers.h" +#include "test/test.h" /* Static variable used to encoded the HSDir query. */ static char query_b64[256]; diff --git a/src/test/test_hs_cell.c b/src/test/test_hs_cell.c index 5c5236b391..4bb3c3f77d 100644 --- a/src/test/test_hs_cell.c +++ b/src/test/test_hs_cell.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,18 +9,18 @@ #define HS_INTROPOINT_PRIVATE #define HS_SERVICE_PRIVATE -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" -#include "crypto_ed25519.h" -#include "crypto_rand.h" -#include "hs_cell.h" -#include "hs_intropoint.h" -#include "hs_service.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/hs_cell.h" +#include "or/hs_intropoint.h" +#include "or/hs_service.h" /* Trunnel. */ -#include "hs/cell_establish_intro.h" +#include "trunnel/hs/cell_establish_intro.h" /** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we * parse it from the receiver side. */ diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c index 50dca588ed..58002d6292 100644 --- a/src/test/test_hs_client.c +++ b/src/test/test_hs_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,28 +14,37 @@ #define CIRCUITLIST_PRIVATE #define CONNECTION_PRIVATE -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" -#include "rend_test_helpers.h" -#include "hs_test_helpers.h" - -#include "config.h" -#include "crypto.h" -#include "channeltls.h" -#include "main.h" -#include "nodelist.h" -#include "routerset.h" - -#include "hs_circuit.h" -#include "hs_client.h" -#include "hs_ident.h" -#include "hs_cache.h" -#include "circuitlist.h" -#include "circuitbuild.h" -#include "connection.h" -#include "connection_edge.h" -#include "networkstatus.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" +#include "test/rend_test_helpers.h" +#include "test/hs_test_helpers.h" + +#include "or/config.h" +#include "lib/crypt_ops/crypto.h" +#include "or/channeltls.h" +#include "or/main.h" +#include "or/nodelist.h" +#include "or/routerset.h" + +#include "or/hs_circuit.h" +#include "or/hs_client.h" +#include "or/hs_ident.h" +#include "or/hs_cache.h" +#include "or/circuitlist.h" +#include "or/circuitbuild.h" +#include "or/connection.h" +#include "or/connection_edge.h" +#include "or/networkstatus.h" + +#include "or/cpath_build_state_st.h" +#include "or/crypt_path_st.h" +#include "or/dir_connection_st.h" +#include "or/entry_connection_st.h" +#include "or/extend_info_st.h" +#include "or/networkstatus_st.h" +#include "or/origin_circuit_st.h" +#include "or/socks_request_st.h" static int mock_connection_ap_handshake_send_begin(entry_connection_t *ap_conn) diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c index 7348eb746c..934b26450d 100644 --- a/src/test/test_hs_common.c +++ b/src/test/test_hs_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,27 +11,33 @@ #define HS_SERVICE_PRIVATE #define NODELIST_PRIVATE -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" -#include "hs_test_helpers.h" - -#include "connection_edge.h" -#include "crypto_rand.h" -#include "hs_common.h" -#include "hs_client.h" -#include "hs_service.h" -#include "config.h" -#include "networkstatus.h" -#include "directory.h" -#include "dirauth/dirvote.h" -#include "nodelist.h" -#include "routerlist.h" -#include "statefile.h" -#include "circuitlist.h" -#include "dirauth/shared_random.h" -#include "util.h" -#include "voting_schedule.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" +#include "test/hs_test_helpers.h" + +#include "or/connection_edge.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/hs_common.h" +#include "or/hs_client.h" +#include "or/hs_service.h" +#include "or/config.h" +#include "or/networkstatus.h" +#include "or/directory.h" +#include "or/dirauth/dirvote.h" +#include "or/nodelist.h" +#include "or/routerlist.h" +#include "or/statefile.h" +#include "or/circuitlist.h" +#include "or/dirauth/shared_random.h" +#include "common/util.h" +#include "or/voting_schedule.h" + +#include "or/microdesc_st.h" +#include "or/networkstatus_st.h" +#include "or/node_st.h" +#include "or/routerinfo_st.h" +#include "or/routerstatus_st.h" /** Test the validation of HS v3 addresses */ static void diff --git a/src/test/test_hs_config.c b/src/test/test_hs_config.c index a76be301d3..33ad09313c 100644 --- a/src/test/test_hs_config.c +++ b/src/test/test_hs_config.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,15 +9,15 @@ #define CONFIG_PRIVATE #define HS_SERVICE_PRIVATE -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" -#include "config.h" -#include "hs_common.h" -#include "hs_config.h" -#include "hs_service.h" -#include "rendservice.h" +#include "or/config.h" +#include "or/hs_common.h" +#include "or/hs_config.h" +#include "or/hs_service.h" +#include "or/rendservice.h" static int helper_config_service(const char *conf, int validate_only) diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c index 308843e9b8..f5beced45f 100644 --- a/src/test/test_hs_control.c +++ b/src/test/test_hs_control.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,23 +7,19 @@ **/ #define CONTROL_PRIVATE -#define CIRCUITBUILD_PRIVATE -#define RENDCOMMON_PRIVATE -#define RENDSERVICE_PRIVATE -#define HS_SERVICE_PRIVATE - -#include "or.h" -#include "test.h" -#include "control.h" -#include "config.h" -#include "hs_common.h" -#include "hs_control.h" -#include "nodelist.h" -//#include "rendcommon.h" -//#include "rendservice.h" -//#include "routerset.h" -//#include "circuitbuild.h" -#include "test_helpers.h" + +#include "or/or.h" +#include "test/test.h" +#include "or/control.h" +#include "or/config.h" +#include "or/hs_common.h" +#include "or/hs_control.h" +#include "or/nodelist.h" + +#include "or/node_st.h" +#include "or/routerstatus_st.h" + +#include "test/test_helpers.h" /* mock ID digest and longname for node that's in nodelist */ #define HSDIR_EXIST_ID \ diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c index 14f1a664e7..43d4955905 100644 --- a/src/test/test_hs_descriptor.c +++ b/src/test/test_hs_descriptor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,18 +8,18 @@ #define HS_DESCRIPTOR_PRIVATE -#include "crypto_ed25519.h" -#include "crypto_digest.h" -#include "crypto_rand.h" -#include "ed25519_cert.h" -#include "or.h" -#include "hs_descriptor.h" -#include "test.h" -#include "torcert.h" - -#include "hs_test_helpers.h" -#include "test_helpers.h" -#include "log_test_helpers.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "trunnel/ed25519_cert.h" +#include "or/or.h" +#include "or/hs_descriptor.h" +#include "test/test.h" +#include "or/torcert.h" + +#include "test/hs_test_helpers.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS DISABLE_GCC_WARNING(overlength-strings) diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c index 1671fa9e7a..2445a8fcf1 100644 --- a/src/test/test_hs_intropoint.c +++ b/src/test/test_hs_intropoint.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,27 +11,29 @@ #define RENDSERVICE_PRIVATE #define CIRCUITLIST_PRIVATE -#include "test.h" -#include "log_test_helpers.h" -#include "crypto_rand.h" +#include "test/test.h" +#include "test/log_test_helpers.h" +#include "lib/crypt_ops/crypto_rand.h" -#include "or.h" -#include "circuitlist.h" -#include "circuituse.h" +#include "or/or.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" #include "ht.h" -#include "relay.h" -#include "rendservice.h" +#include "or/relay.h" +#include "or/rendservice.h" -#include "hs_cell.h" -#include "hs_circuitmap.h" -#include "hs_common.h" -#include "hs_intropoint.h" -#include "hs_service.h" +#include "or/hs_cell.h" +#include "or/hs_circuitmap.h" +#include "or/hs_common.h" +#include "or/hs_intropoint.h" +#include "or/hs_service.h" + +#include "or/or_circuit_st.h" /* Trunnel. */ -#include "hs/cell_establish_intro.h" -#include "hs/cell_introduce1.h" -#include "hs/cell_common.h" +#include "trunnel/hs/cell_establish_intro.h" +#include "trunnel/hs/cell_introduce1.h" +#include "trunnel/hs/cell_common.h" static size_t new_establish_intro_cell(const char *circ_nonce, diff --git a/src/test/test_hs_ntor.c b/src/test/test_hs_ntor.c index 8eee54d4b4..51373af645 100644 --- a/src/test/test_hs_ntor.c +++ b/src/test/test_hs_ntor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,11 +6,11 @@ * \brief Test hidden service ntor functionality. */ -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" -#include "hs_ntor.h" +#include "or/hs_ntor.h" /* Test the HS ntor handshake. Simulate the sending of an encrypted INTRODUCE1 * cell, and verify the proper derivation of decryption keys on the other end. diff --git a/src/test/test_hs_ntor_cl.c b/src/test/test_hs_ntor_cl.c index ed1eda58ea..5475f3b38c 100644 --- a/src/test/test_hs_ntor_cl.c +++ b/src/test/test_hs_ntor_cl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** This is a wrapper over the little-t-tor HS ntor functions. The wrapper is @@ -13,13 +13,12 @@ #include <stdlib.h> #define ONION_NTOR_PRIVATE -#include "or.h" -#include "util.h" -#include "compat.h" -#include "crypto.h" -#include "crypto_curve25519.h" -#include "hs_ntor.h" -#include "onion_ntor.h" +#include "or/or.h" +#include "common/util.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "or/hs_ntor.h" +#include "or/onion_ntor.h" #define N_ARGS(n) STMT_BEGIN { \ if (argc < (n)) { \ diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c index 33b5e96070..684ac98f42 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -22,39 +22,46 @@ #define HS_CLIENT_PRIVATE #define ROUTERPARSE_PRIVATE -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" -#include "rend_test_helpers.h" -#include "hs_test_helpers.h" - -#include "or.h" -#include "config.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "crypto_rand.h" -#include "dirauth/dirvote.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "relay.h" -#include "routerparse.h" -#include "hs_common.h" -#include "hs_config.h" -#include "hs_ident.h" -#include "hs_intropoint.h" -#include "hs_ntor.h" -#include "hs_circuit.h" -#include "hs_service.h" -#include "hs_client.h" -#include "main.h" -#include "rendservice.h" -#include "statefile.h" -#include "dirauth/shared_random_state.h" -#include "voting_schedule.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" +#include "test/rend_test_helpers.h" +#include "test/hs_test_helpers.h" + +#include "or/or.h" +#include "or/config.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/circuituse.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/dirauth/dirvote.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/relay.h" +#include "or/routerparse.h" +#include "or/hs_common.h" +#include "or/hs_config.h" +#include "or/hs_ident.h" +#include "or/hs_intropoint.h" +#include "or/hs_ntor.h" +#include "or/hs_circuit.h" +#include "or/hs_service.h" +#include "or/hs_client.h" +#include "or/main.h" +#include "or/rendservice.h" +#include "or/statefile.h" +#include "or/dirauth/shared_random_state.h" +#include "or/voting_schedule.h" + +#include "or/cpath_build_state_st.h" +#include "or/crypt_path_st.h" +#include "or/networkstatus_st.h" +#include "or/node_st.h" +#include "or/origin_circuit_st.h" +#include "or/routerinfo_st.h" /* Trunnel */ -#include "hs/cell_establish_intro.h" +#include "trunnel/hs/cell_establish_intro.h" static networkstatus_t mock_ns; diff --git a/src/test/test_introduce.c b/src/test/test_introduce.c index d502bdddb1..f62c7f8808 100644 --- a/src/test/test_introduce.c +++ b/src/test/test_introduce.c @@ -1,13 +1,13 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "crypto.h" -#include "or.h" -#include "test.h" +#include "lib/crypt_ops/crypto.h" +#include "or/or.h" +#include "test/test.h" #define RENDSERVICE_PRIVATE -#include "rendservice.h" +#include "or/rendservice.h" static uint8_t v0_test_plaintext[] = /* 20 bytes of rendezvous point nickname */ diff --git a/src/test/test_keypin.c b/src/test/test_keypin.c index 79d7bac902..e7e7e62963 100644 --- a/src/test/test_keypin.c +++ b/src/test/test_keypin.c @@ -1,13 +1,13 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define KEYPIN_PRIVATE -#include "or.h" -#include "keypin.h" -#include "util.h" +#include "or/or.h" +#include "or/keypin.h" +#include "common/util.h" -#include "test.h" +#include "test/test.h" static void test_keypin_parse_line(void *arg) diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c index 6840072d76..ffb6c47b1e 100644 --- a/src/test/test_link_handshake.c +++ b/src/test/test_link_handshake.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -8,21 +8,24 @@ #define TOR_CHANNEL_INTERNAL_ #define TORTLS_PRIVATE -#include "compat.h" - -#include "or.h" -#include "config.h" -#include "connection.h" -#include "connection_or.h" -#include "channeltls.h" -#include "link_handshake.h" -#include "router.h" -#include "routerkeys.h" -#include "scheduler.h" -#include "torcert.h" - -#include "test.h" -#include "log_test_helpers.h" +#include "or/or.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_or.h" +#include "or/channeltls.h" +#include "trunnel/link_handshake.h" +#include "or/router.h" +#include "or/routerkeys.h" +#include "or/scheduler.h" +#include "or/torcert.h" + +#include "or/or_connection_st.h" +#include "or/or_handshake_certs_st.h" +#include "or/or_handshake_state_st.h" +#include "or/var_cell_st.h" + +#include "test/test.h" +#include "test/log_test_helpers.h" static var_cell_t *mock_got_var_cell = NULL; @@ -1576,4 +1579,3 @@ struct testcase_t link_handshake_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_logging.c b/src/test/test_logging.c index e373158e34..d979411469 100644 --- a/src/test/test_logging.c +++ b/src/test/test_logging.c @@ -1,10 +1,15 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +#define CONFIG_PRIVATE + #include "orconfig.h" -#include "or.h" -#include "torlog.h" -#include "test.h" +#include "or/or.h" +#include "or/config.h" +#include "lib/err/torerr.h" +#include "lib/log/torlog.h" +#include "test/test.h" +#include "lib/process/subprocess.h" static void dummy_cb_fn(int severity, uint32_t domain, const char *msg) @@ -89,7 +94,7 @@ test_sigsafe_err(void *arg) init_logging(1); mark_logs_temp(); - add_file_log(&include_bug, fn, 0); + open_and_add_file_log(&include_bug, fn, 0); tor_log_update_sigsafe_err_fds(); close_temp_logs(); @@ -170,4 +175,3 @@ struct testcase_t logging_tests[] = { { "ratelim", test_ratelim, 0, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_mainloop.c b/src/test/test_mainloop.c index 9da8a039dd..559bbe587a 100644 --- a/src/test/test_mainloop.c +++ b/src/test/test_mainloop.c @@ -6,11 +6,11 @@ * \brief Tests for functions closely related to the Tor main loop */ -#include "test.h" -#include "log_test_helpers.h" +#include "test/test.h" +#include "test/log_test_helpers.h" -#include "or.h" -#include "main.h" +#include "or/or.h" +#include "or/main.h" static const uint64_t BILLION = 1000000000; diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c index 4b168f49ed..1b680c02c5 100644 --- a/src/test/test_microdesc.c +++ b/src/test/test_microdesc.c @@ -1,19 +1,24 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "or.h" +#include "or/or.h" -#include "config.h" +#include "or/config.h" #define DIRVOTE_PRIVATE -#include "dirauth/dirvote.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "routerlist.h" -#include "routerparse.h" -#include "torcert.h" - -#include "test.h" +#include "or/dirauth/dirvote.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/torcert.h" + +#include "or/microdesc_st.h" +#include "or/networkstatus_st.h" +#include "or/routerinfo_st.h" +#include "or/routerstatus_st.h" + +#include "test/test.h" #ifdef _WIN32 /* For mkdir() */ diff --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c index 9499fd0380..1dc8bc2d24 100644 --- a/src/test/test_nodelist.c +++ b/src/test/test_nodelist.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,12 +6,19 @@ * \brief Unit tests for nodelist related functions. **/ -#include "or.h" -#include "crypto_rand.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "torcert.h" -#include "test.h" +#include "or/or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/torcert.h" + +#include "or/microdesc_st.h" +#include "or/networkstatus_st.h" +#include "or/node_st.h" +#include "or/routerinfo_st.h" +#include "or/routerstatus_st.h" + +#include "test/test.h" /** Test the case when node_get_by_id() returns NULL, * node_get_verbose_nickname_by_id should return the base 16 encoding diff --git a/src/test/test_ntor_cl.c b/src/test/test_ntor_cl.c index d0eea85d6f..75d5ccc126 100644 --- a/src/test/test_ntor_cl.c +++ b/src/test/test_ntor_cl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -6,12 +6,11 @@ #include <stdlib.h> #define ONION_NTOR_PRIVATE -#include "or.h" -#include "util.h" -#include "compat.h" -#include "crypto.h" -#include "crypto_curve25519.h" -#include "onion_ntor.h" +#include "or/or.h" +#include "common/util.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "or/onion_ntor.h" #define N_ARGS(n) STMT_BEGIN { \ if (argc < (n)) { \ diff --git a/src/test/test_oom.c b/src/test/test_oom.c index abf8896452..2e5989c0d0 100644 --- a/src/test/test_oom.c +++ b/src/test/test_oom.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Unit tests for OOM handling logic */ @@ -7,16 +7,21 @@ #define BUFFERS_PRIVATE #define CIRCUITLIST_PRIVATE #define CONNECTION_PRIVATE -#include "or.h" -#include "buffers.h" -#include "circuitlist.h" -#include "compat_libevent.h" -#include "connection.h" -#include "config.h" -#include "crypto_rand.h" -#include "relay.h" -#include "test.h" -#include "test_helpers.h" +#include "or/or.h" +#include "lib/container/buffers.h" +#include "or/circuitlist.h" +#include "common/compat_libevent.h" +#include "or/connection.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/relay.h" +#include "test/test.h" +#include "test/test_helpers.h" + +#include "or/cell_st.h" +#include "or/entry_connection_st.h" +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" /* small replacement mock for circuit_mark_for_close_ to avoid doing all * the other bookkeeping that comes with marking circuits. */ diff --git a/src/test/test_oos.c b/src/test/test_oos.c index e72fcf5de9..6ecb1a0786 100644 --- a/src/test/test_oos.c +++ b/src/test/test_oos.c @@ -1,16 +1,19 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Unit tests for OOS handler */ #define CONNECTION_PRIVATE -#include "or.h" -#include "config.h" -#include "connection.h" -#include "connection_or.h" -#include "main.h" -#include "test.h" +#include "or/or.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/connection_or.h" +#include "or/main.h" +#include "test/test.h" + +#include "or/dir_connection_st.h" +#include "or/or_connection_st.h" static or_options_t mock_options; diff --git a/src/test/test_options.c b/src/test/test_options.c index 65564f324c..ab8727c3db 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -1,24 +1,25 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONFIG_PRIVATE -#include "or.h" -#include "confparse.h" -#include "config.h" -#include "test.h" -#include "geoip.h" +#include "or/or.h" +#include "or/confparse.h" +#include "or/config.h" +#include "test/test.h" +#include "or/geoip.h" #define ROUTERSET_PRIVATE -#include "routerset.h" -#include "main.h" -#include "log_test_helpers.h" +#include "or/routerset.h" +#include "or/main.h" +#include "test/log_test_helpers.h" -#include "sandbox.h" -#include "memarea.h" -#include "policies.h" -#include "test_helpers.h" +#include "lib/sandbox/sandbox.h" +#include "lib/memarea/memarea.h" +#include "lib/osinfo/uname.h" +#include "or/policies.h" +#include "test/test_helpers.h" #define NS_MODULE test_options @@ -4237,4 +4238,3 @@ struct testcase_t options_tests[] = { LOCAL_VALIDATE_TEST(accel), END_OF_TESTCASES /* */ }; - diff --git a/src/test/test_periodic_event.c b/src/test/test_periodic_event.c index 34689b64f4..b353cf87a3 100644 --- a/src/test/test_periodic_event.c +++ b/src/test/test_periodic_event.c @@ -11,15 +11,15 @@ #define HS_SERVICE_PRIVATE #define MAIN_PRIVATE -#include "test.h" -#include "test_helpers.h" - -#include "or.h" -#include "config.h" -#include "hibernate.h" -#include "hs_service.h" -#include "main.h" -#include "periodic.h" +#include "test/test.h" +#include "test/test_helpers.h" + +#include "or/or.h" +#include "or/config.h" +#include "or/hibernate.h" +#include "or/hs_service.h" +#include "or/main.h" +#include "or/periodic.h" /** Helper function: This is replaced in some tests for the event callbacks so * we don't actually go into the code path of those callbacks. */ diff --git a/src/test/test_policy.c b/src/test/test_policy.c index e89d49aaf5..2c29bbb16a 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -1,14 +1,19 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" +#include "or/or.h" #define CONFIG_PRIVATE -#include "config.h" -#include "router.h" -#include "routerparse.h" +#include "or/config.h" +#include "or/router.h" +#include "or/routerparse.h" #define POLICIES_PRIVATE -#include "policies.h" -#include "test.h" +#include "or/policies.h" +#include "test/test.h" + +#include "or/node_st.h" +#include "or/port_cfg_st.h" +#include "or/routerinfo_st.h" +#include "or/routerstatus_st.h" /* Helper: assert that short_policy parses and writes back out as itself, or as <b>expected</b> if that's provided. */ diff --git a/src/test/test_procmon.c b/src/test/test_procmon.c index 5c52af8693..ae30bd00b6 100644 --- a/src/test/test_procmon.c +++ b/src/test/test_procmon.c @@ -1,14 +1,14 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define PROCMON_PRIVATE #include "orconfig.h" -#include "or.h" -#include "test.h" +#include "or/or.h" +#include "test/test.h" -#include "procmon.h" +#include "common/procmon.h" -#include "log_test_helpers.h" +#include "test/log_test_helpers.h" #define NS_MODULE procmon diff --git a/src/test/test_proto_http.c b/src/test/test_proto_http.c index 2f36fbccd7..57bfe24633 100644 --- a/src/test/test_proto_http.c +++ b/src/test/test_proto_http.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,11 +6,11 @@ * \brief Tests for our HTTP protocol parser code */ -#include "or.h" -#include "test.h" -#include "buffers.h" -#include "proto_http.h" -#include "log_test_helpers.h" +#include "or/or.h" +#include "test/test.h" +#include "lib/container/buffers.h" +#include "or/proto_http.h" +#include "test/log_test_helpers.h" #define S(str) str, sizeof(str)-1 diff --git a/src/test/test_proto_misc.c b/src/test/test_proto_misc.c index 263ca47447..7f066e14ad 100644 --- a/src/test/test_proto_misc.c +++ b/src/test/test_proto_misc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,14 +6,16 @@ * \brief Test our smaller buffer-based protocol functions */ -#include "or.h" -#include "test.h" -#include "buffers.h" -#include "connection_or.h" -#include "ext_orport.h" -#include "proto_cell.h" -#include "proto_control0.h" -#include "proto_ext_or.h" +#include "or/or.h" +#include "test/test.h" +#include "lib/container/buffers.h" +#include "or/connection_or.h" +#include "or/ext_orport.h" +#include "or/proto_cell.h" +#include "or/proto_control0.h" +#include "or/proto_ext_or.h" + +#include "or/var_cell_st.h" static void test_proto_var_cell(void *arg) diff --git a/src/test/test_protover.c b/src/test/test_protover.c index 70b7c9a85f..f17f68ced2 100644 --- a/src/test/test_protover.c +++ b/src/test/test_protover.c @@ -1,15 +1,15 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define PROTOVER_PRIVATE #include "orconfig.h" -#include "test.h" +#include "test/test.h" -#include "protover.h" +#include "or/protover.h" -#include "or.h" -#include "connection_or.h" +#include "or/or.h" +#include "or/connection_or.h" static void test_protover_parse(void *arg) diff --git a/src/test/test_pt.c b/src/test/test_pt.c index 07b6712ff9..c2c4e19897 100644 --- a/src/test/test_pt.c +++ b/src/test/test_pt.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -8,15 +8,17 @@ #define UTIL_PRIVATE #define STATEFILE_PRIVATE #define CONTROL_PRIVATE -#include "or.h" -#include "config.h" -#include "confparse.h" -#include "control.h" -#include "transports.h" -#include "circuitbuild.h" -#include "util.h" -#include "statefile.h" -#include "test.h" +#define SUBPROCESS_PRIVATE +#include "or/or.h" +#include "or/config.h" +#include "or/confparse.h" +#include "or/control.h" +#include "or/transports.h" +#include "or/circuitbuild.h" +#include "common/util.h" +#include "or/statefile.h" +#include "test/test.h" +#include "lib/process/subprocess.h" static void reset_mp(managed_proxy_t *mp) @@ -544,4 +546,3 @@ struct testcase_t pt_tests[] = { NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_pubsub.c b/src/test/test_pubsub.c deleted file mode 100644 index 2f047d9f2c..0000000000 --- a/src/test/test_pubsub.c +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file test_pubsub.c - * \brief Unit tests for publish-subscribe abstraction. - **/ - -#include "or.h" -#include "test.h" -#include "pubsub.h" - -DECLARE_PUBSUB_STRUCT_TYPES(foobar) -DECLARE_PUBSUB_TOPIC(foobar) -DECLARE_NOTIFY_PUBSUB_TOPIC(static, foobar) -IMPLEMENT_PUBSUB_TOPIC(static, foobar) - -struct foobar_event_data_t { - unsigned u; - const char *s; -}; - -struct foobar_subscriber_data_t { - const char *name; - long l; -}; - -static int -foobar_sub1(foobar_event_data_t *ev, foobar_subscriber_data_t *mine) -{ - ev->u += 10; - mine->l += 100; - return 0; -} - -static int -foobar_sub2(foobar_event_data_t *ev, foobar_subscriber_data_t *mine) -{ - ev->u += 5; - mine->l += 50; - return 0; -} - -static void -test_pubsub_basic(void *arg) -{ - (void)arg; - foobar_subscriber_data_t subdata1 = { "hi", 0 }; - foobar_subscriber_data_t subdata2 = { "wow", 0 }; - const foobar_subscriber_t *sub1; - const foobar_subscriber_t *sub2; - foobar_event_data_t ed = { 0, "x" }; - foobar_event_data_t ed2 = { 0, "y" }; - sub1 = foobar_subscribe(foobar_sub1, &subdata1, SUBSCRIBE_ATSTART, 100); - tt_assert(sub1); - - foobar_notify(&ed, 0); - tt_int_op(subdata1.l, OP_EQ, 100); - tt_int_op(subdata2.l, OP_EQ, 0); - tt_int_op(ed.u, OP_EQ, 10); - - sub2 = foobar_subscribe(foobar_sub2, &subdata2, 0, 5); - tt_assert(sub2); - - foobar_notify(&ed2, 0); - tt_int_op(subdata1.l, OP_EQ, 200); - tt_int_op(subdata2.l, OP_EQ, 50); - tt_int_op(ed2.u, OP_EQ, 15); - - foobar_unsubscribe(sub1); - - foobar_notify(&ed, 0); - tt_int_op(subdata1.l, OP_EQ, 200); - tt_int_op(subdata2.l, OP_EQ, 100); - tt_int_op(ed.u, OP_EQ, 15); - - done: - foobar_clear(); -} - -struct testcase_t pubsub_tests[] = { - { "pubsub_basic", test_pubsub_basic, TT_FORK, NULL, NULL }, - END_OF_TESTCASES -}; - diff --git a/src/test/test_relay.c b/src/test/test_relay.c index 73c0ed5586..777153d11b 100644 --- a/src/test/test_relay.c +++ b/src/test/test_relay.c @@ -1,17 +1,20 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" +#include "or/or.h" #define CIRCUITBUILD_PRIVATE -#include "circuitbuild.h" +#include "or/circuitbuild.h" #define RELAY_PRIVATE -#include "relay.h" +#include "or/relay.h" /* For init/free stuff */ -#include "scheduler.h" +#include "or/scheduler.h" + +#include "or/cell_st.h" +#include "or/or_circuit_st.h" /* Test suite stuff */ -#include "test.h" -#include "fakechans.h" +#include "test/test.h" +#include "test/fakechans.h" static or_circuit_t * new_fake_orcirc(channel_t *nchan, channel_t *pchan); diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c index 841174982c..9f314b7704 100644 --- a/src/test/test_relaycell.c +++ b/src/test/test_relaycell.c @@ -1,20 +1,26 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Unit tests for handling different kinds of relay cell */ #define RELAY_PRIVATE #define CIRCUITLIST_PRIVATE -#include "or.h" -#include "main.h" -#include "config.h" -#include "connection.h" -#include "crypto.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "connection_edge.h" -#include "relay.h" -#include "test.h" +#include "or/or.h" +#include "or/main.h" +#include "or/config.h" +#include "or/connection.h" +#include "lib/crypt_ops/crypto.h" +#include "or/circuitbuild.h" +#include "or/circuitlist.h" +#include "or/connection_edge.h" +#include "or/relay.h" +#include "test/test.h" + +#include "or/cell_st.h" +#include "or/crypt_path_st.h" +#include "or/entry_connection_st.h" +#include "or/origin_circuit_st.h" +#include "or/socks_request_st.h" static int srm_ncalls; static entry_connection_t *srm_conn; @@ -240,11 +246,26 @@ test_circbw_relay(void *arg) circ->cpath); ASSERT_UNCOUNTED_BW(); - /* Sendme on stream: not counted */ + /* Sendme on valid stream: counted */ ENTRY_TO_CONN(entryconn)->outbuf_flushlen = 0; PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); + ASSERT_COUNTED_BW(); + + /* Sendme on valid stream with full window: not counted */ + ENTRY_TO_CONN(entryconn)->outbuf_flushlen = 0; + PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); + edgeconn->package_window = 500; + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, + circ->cpath); + ASSERT_UNCOUNTED_BW(); + + /* Sendme on unknown stream: not counted */ + ENTRY_TO_CONN(entryconn)->outbuf_flushlen = 0; + PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); + connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, + circ->cpath); ASSERT_UNCOUNTED_BW(); /* Sendme on circuit with full window: not counted */ diff --git a/src/test/test_relaycrypt.c b/src/test/test_relaycrypt.c index 60bd479719..7f0ca06983 100644 --- a/src/test/test_relaycrypt.c +++ b/src/test/test_relaycrypt.c @@ -3,14 +3,19 @@ * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "circuitbuild.h" +#include "or/or.h" +#include "or/circuitbuild.h" #define CIRCUITLIST_PRIVATE -#include "circuitlist.h" -#include "crypto_rand.h" -#include "relay.h" -#include "relay_crypto.h" -#include "test.h" +#include "or/circuitlist.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/relay.h" +#include "or/relay_crypto.h" + +#include "or/cell_st.h" +#include "or/or_circuit_st.h" +#include "or/origin_circuit_st.h" + +#include "test/test.h" static const char KEY_MATERIAL[3][CPATH_KEY_MATERIAL_LEN] = { " 'My public key is in this signed x509 object', said Tom assertively.", diff --git a/src/test/test_rendcache.c b/src/test/test_rendcache.c index 9f6cfc4a22..3d606aac0d 100644 --- a/src/test/test_rendcache.c +++ b/src/test/test_rendcache.c @@ -1,18 +1,25 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "or.h" +#include "or/or.h" -#include "test.h" +#include "test/test.h" #define RENDCACHE_PRIVATE -#include "rendcache.h" -#include "router.h" -#include "routerlist.h" -#include "config.h" -#include "hs_common.h" -#include "rend_test_helpers.h" -#include "log_test_helpers.h" +#include "or/rendcache.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/config.h" +#include "or/hs_common.h" + +#include "or/extend_info_st.h" +#include "or/rend_encoded_v2_service_descriptor_st.h" +#include "or/rend_intro_point_st.h" +#include "or/rend_service_descriptor_st.h" +#include "or/routerinfo_st.h" + +#include "test/rend_test_helpers.h" +#include "test/log_test_helpers.h" #define NS_MODULE rend_cache diff --git a/src/test/test_replay.c b/src/test/test_replay.c index d8dcc7370c..7f9c0b09e4 100644 --- a/src/test/test_replay.c +++ b/src/test/test_replay.c @@ -1,12 +1,12 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define REPLAYCACHE_PRIVATE #include "orconfig.h" -#include "or.h" -#include "replaycache.h" -#include "test.h" +#include "or/or.h" +#include "or/replaycache.h" +#include "test/test.h" static const char *test_buffer = "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed do eiusmod" diff --git a/src/test/test_router.c b/src/test/test_router.c index 4e96e24534..6e9424a3ad 100644 --- a/src/test/test_router.c +++ b/src/test/test_router.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* Copyright (c) 2017, isis agora lovecruft */ /* See LICENSE for licensing information */ @@ -7,15 +7,17 @@ * \brief Unittests for code in src/or/router.c **/ -#include "or.h" -#include "config.h" -#include "crypto_curve25519.h" -#include "crypto_ed25519.h" -#include "router.h" -#include "routerlist.h" +#include "or/or.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "or/router.h" +#include "or/routerlist.h" + +#include "or/routerinfo_st.h" /* Test suite stuff */ -#include "test.h" +#include "test/test.h" NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void)); diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c index e4abcdb92d..948cf0d60c 100644 --- a/src/test/test_routerkeys.c +++ b/src/test/test_routerkeys.c @@ -1,18 +1,18 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define ROUTER_PRIVATE -#include "or.h" -#include "config.h" -#include "router.h" -#include "routerkeys.h" -#include "util.h" -#include "crypto.h" -#include "torcert.h" -#include "test.h" +#include "or/or.h" +#include "or/config.h" +#include "or/router.h" +#include "or/routerkeys.h" +#include "common/util.h" +#include "lib/crypt_ops/crypto.h" +#include "or/torcert.h" +#include "test/test.h" #ifdef _WIN32 /* For mkdir() */ diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c index 701227c1c7..5da42c1339 100644 --- a/src/test/test_routerlist.c +++ b/src/test/test_routerlist.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -13,29 +13,35 @@ #define NETWORKSTATUS_PRIVATE #define ROUTERLIST_PRIVATE #define TOR_UNIT_TESTING -#include "or.h" -#include "config.h" -#include "connection.h" -#include "container.h" -#include "control.h" -#include "crypto_rand.h" -#include "directory.h" -#include "dirauth/dirvote.h" -#include "entrynodes.h" -#include "hibernate.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "router.h" -#include "routerlist.h" -#include "routerset.h" -#include "routerparse.h" -#include "dirauth/shared_random.h" -#include "statefile.h" -#include "test.h" -#include "test_dir_common.h" -#include "log_test_helpers.h" +#include "or/or.h" +#include "or/config.h" +#include "or/connection.h" +#include "or/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/directory.h" +#include "or/dirauth/dirvote.h" +#include "or/entrynodes.h" +#include "or/hibernate.h" +#include "or/microdesc.h" +#include "or/networkstatus.h" +#include "or/nodelist.h" +#include "or/policies.h" +#include "or/router.h" +#include "or/routerlist.h" +#include "or/routerset.h" +#include "or/routerparse.h" +#include "or/dirauth/shared_random.h" +#include "or/statefile.h" + +#include "or/authority_cert_st.h" +#include "or/dir_connection_st.h" +#include "or/networkstatus_st.h" +#include "or/node_st.h" +#include "or/routerstatus_st.h" + +#include "test/test.h" +#include "test/test_dir_common.h" +#include "test/log_test_helpers.h" void construct_consensus(char **consensus_text_md, time_t now); diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c index c541324674..e64c24e89e 100644 --- a/src/test/test_routerset.c +++ b/src/test/test_routerset.c @@ -1,15 +1,21 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERSET_PRIVATE -#include "or.h" -#include "geoip.h" -#include "routerset.h" -#include "routerparse.h" -#include "policies.h" -#include "nodelist.h" -#include "test.h" +#include "or/or.h" +#include "or/geoip.h" +#include "or/routerset.h" +#include "or/routerparse.h" +#include "or/policies.h" +#include "or/nodelist.h" + +#include "or/extend_info_st.h" +#include "or/node_st.h" +#include "or/routerinfo_st.h" +#include "or/routerstatus_st.h" + +#include "test/test.h" #define NS_MODULE routerset diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c index 841fc69456..1087befa68 100644 --- a/src/test/test_scheduler.c +++ b/src/test/test_scheduler.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -8,19 +8,19 @@ #define SCHEDULER_KIST_PRIVATE #define TOR_CHANNEL_INTERNAL_ #define CHANNEL_PRIVATE_ -#include "or.h" -#include "config.h" -#include "compat_libevent.h" -#include "channel.h" -#include "channeltls.h" -#include "connection.h" -#include "networkstatus.h" +#include "or/or.h" +#include "or/config.h" +#include "common/compat_libevent.h" +#include "or/channel.h" +#include "or/channeltls.h" +#include "or/connection.h" +#include "or/networkstatus.h" #define SCHEDULER_PRIVATE_ -#include "scheduler.h" +#include "or/scheduler.h" /* Test suite stuff */ -#include "test.h" -#include "fakechans.h" +#include "test/test.h" +#include "test/fakechans.h" /* Shamelessly stolen from compat_libevent.c */ #define V(major, minor, patch) \ diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c index 2b3c8c93be..91ae20bff8 100644 --- a/src/test/test_shared_random.c +++ b/src/test/test_shared_random.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define SHARED_RANDOM_PRIVATE @@ -6,21 +6,24 @@ #define CONFIG_PRIVATE #define DIRVOTE_PRIVATE -#include "or.h" -#include "test.h" -#include "config.h" -#include "crypto_rand.h" -#include "dirauth/dirvote.h" -#include "dirauth/shared_random.h" -#include "dirauth/shared_random_state.h" -#include "log_test_helpers.h" -#include "networkstatus.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "routerparse.h" -#include "shared_random_client.h" -#include "voting_schedule.h" +#include "or/or.h" +#include "test/test.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/dirauth/dirvote.h" +#include "or/dirauth/shared_random.h" +#include "or/dirauth/shared_random_state.h" +#include "test/log_test_helpers.h" +#include "or/networkstatus.h" +#include "or/router.h" +#include "or/routerkeys.h" +#include "or/routerlist.h" +#include "or/routerparse.h" +#include "or/shared_random_client.h" +#include "or/voting_schedule.h" + +#include "or/dir_server_st.h" +#include "or/networkstatus_st.h" static authority_cert_t *mock_cert; diff --git a/src/test/test_slow.c b/src/test/test_slow.c index e640702499..951851ec07 100644 --- a/src/test/test_slow.c +++ b/src/test/test_slow.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,8 +15,8 @@ #include <fcntl.h> #endif -#include "or.h" -#include "test.h" +#include "or/or.h" +#include "test/test.h" struct testgroup_t testgroups[] = { { "slow/crypto/", slow_crypto_tests }, diff --git a/src/test/test_socks.c b/src/test/test_socks.c index 8da7191e82..3e4528af27 100644 --- a/src/test/test_socks.c +++ b/src/test/test_socks.c @@ -1,14 +1,16 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "buffers.h" -#include "config.h" -#include "proto_socks.h" -#include "test.h" -#include "log_test_helpers.h" +#include "or/or.h" +#include "lib/container/buffers.h" +#include "or/config.h" +#include "or/proto_socks.h" +#include "test/test.h" +#include "test/log_test_helpers.h" +#include "or/socks_request_st.h" +#include "common/socks5_status.h" typedef struct socks_test_data_t { socks_request_t *req; @@ -1046,4 +1048,3 @@ struct testcase_t socks_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_status.c b/src/test/test_status.c index b4ca17891b..09b9662b4c 100644 --- a/src/test/test_status.c +++ b/src/test/test_status.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define STATUS_PRIVATE @@ -11,20 +11,24 @@ #include <float.h> #include <math.h> -#include "or.h" -#include "torlog.h" +#include "or/or.h" +#include "lib/log/torlog.h" #include "tor_queue.h" -#include "status.h" -#include "circuitlist.h" -#include "config.h" -#include "hibernate.h" -#include "rephist.h" -#include "relay.h" -#include "router.h" -#include "main.h" -#include "nodelist.h" -#include "statefile.h" -#include "test.h" +#include "or/status.h" +#include "or/circuitlist.h" +#include "or/config.h" +#include "or/hibernate.h" +#include "or/rephist.h" +#include "or/relay.h" +#include "or/router.h" +#include "or/main.h" +#include "or/nodelist.h" +#include "or/statefile.h" + +#include "or/origin_circuit_st.h" +#include "or/routerinfo_st.h" + +#include "test/test.h" #define NS_MODULE status diff --git a/src/test/test_storagedir.c b/src/test/test_storagedir.c index 26606f9b6e..d07d35e096 100644 --- a/src/test/test_storagedir.c +++ b/src/test/test_storagedir.c @@ -1,10 +1,10 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "crypto_rand.h" -#include "storagedir.h" -#include "test.h" +#include "or/or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/fs/storagedir.h" +#include "test/test.h" #ifdef HAVE_UTIME_H #include <utime.h> diff --git a/src/test/test_switch_id.c b/src/test/test_switch_id.c index fe36d8c6e6..11fe53b7c5 100644 --- a/src/test/test_switch_id.c +++ b/src/test/test_switch_id.c @@ -1,7 +1,8 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" +#include "or/or.h" +#include "lib/process/setuid.h" #ifdef HAVE_SYS_CAPABILITY_H #include <sys/capability.h> @@ -189,4 +190,3 @@ main(int argc, char **argv) return (okay ? 0 : 1); #endif /* defined(_WIN32) */ } - diff --git a/src/test/test_threads.c b/src/test/test_threads.c index ed6d8f04aa..e698e4f618 100644 --- a/src/test/test_threads.c +++ b/src/test/test_threads.c @@ -1,12 +1,12 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "or.h" -#include "compat_threads.h" -#include "test.h" +#include "or/or.h" +#include "lib/thread/threads.h" +#include "test/test.h" /** mutex for thread test to stop the threads hitting data at the same time. */ static tor_mutex_t *thread_test_mutex_ = NULL; diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c index 388f6df325..b456734684 100644 --- a/src/test/test_tortls.c +++ b/src/test/test_tortls.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TORTLS_PRIVATE @@ -11,7 +11,7 @@ #endif #include <math.h> -#include "compat.h" +#include "lib/cc/compat_compiler.h" /* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */ @@ -30,13 +30,13 @@ DISABLE_GCC_WARNING(redundant-decls) ENABLE_GCC_WARNING(redundant-decls) -#include "or.h" -#include "torlog.h" -#include "config.h" -#include "tortls.h" +#include "or/or.h" +#include "lib/log/torlog.h" +#include "or/config.h" +#include "lib/tls/tortls.h" -#include "test.h" -#include "log_test_helpers.h" +#include "test/test.h" +#include "test/log_test_helpers.h" #define NS_MODULE tortls #ifndef HAVE_SSL_STATE @@ -2839,4 +2839,3 @@ struct testcase_t tortls_tests[] = { LOCAL_TEST_CASE(context_init_one, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_util.c b/src/test/test_util.c index ec11bfd5f5..7f37a2ab9c 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -8,16 +8,33 @@ #define COMPAT_TIME_PRIVATE #define CONTROL_PRIVATE #define UTIL_PRIVATE -#include "or.h" -#include "buffers.h" -#include "config.h" -#include "control.h" -#include "crypto_rand.h" -#include "test.h" -#include "memarea.h" -#include "util_process.h" -#include "log_test_helpers.h" -#include "compress_zstd.h" +#define UTIL_MALLOC_PRIVATE +#define SOCKET_PRIVATE +#define SUBPROCESS_PRIVATE +#include "lib/testsupport/testsupport.h" +#include "or/or.h" +#include "lib/container/buffers.h" +#include "or/config.h" +#include "or/control.h" +#include "or/transports.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "test/test.h" +#include "lib/memarea/memarea.h" +#include "lib/process/waitpid.h" +#include "test/log_test_helpers.h" +#include "lib/compress/compress_zstd.h" +#include "lib/encoding/keyval.h" +#include "lib/fdio/fdio.h" +#include "lib/fs/winlib.h" +#include "lib/process/env.h" +#include "lib/process/pidfile.h" +#include "lib/process/subprocess.h" +#include "lib/intmath/weakrng.h" +#include "lib/thread/numcpus.h" +#include "lib/math/fp.h" +#include "lib/math/laplace.h" +#include "lib/meminfo/meminfo.h" +#include "lib/time/tvdiff.h" #ifdef HAVE_PWD_H #include <pwd.h> @@ -2115,20 +2132,10 @@ test_util_parse_integer(void *arg) tt_int_op(1,OP_EQ, i); tt_str_op(cp,OP_EQ, " plus garbage"); /* Illogical min max */ - tor_capture_bugs_(1); tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,4,&i,NULL)); tt_int_op(0,OP_EQ, i); - tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); - tt_str_op("!(max < min)", OP_EQ, - smartlist_get(tor_get_captured_bug_log_(), 0)); - tor_end_capture_bugs_(); - tor_capture_bugs_(1); tt_int_op(0L,OP_EQ, tor_parse_long("-50",10,100,-100,&i,NULL)); tt_int_op(0,OP_EQ, i); - tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); - tt_str_op("!(max < min)", OP_EQ, - smartlist_get(tor_get_captured_bug_log_(), 0)); - tor_end_capture_bugs_(); /* Out of bounds */ tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,100,&i,NULL)); tt_int_op(0,OP_EQ, i); @@ -2139,11 +2146,8 @@ test_util_parse_integer(void *arg) tt_int_op(0L,OP_EQ, tor_parse_long("2",2,0,100,NULL,NULL)); tt_int_op(68284L,OP_EQ, tor_parse_long("10abc",16,0,70000,NULL,NULL)); tt_int_op(68284L,OP_EQ, tor_parse_long("10ABC",16,0,70000,NULL,NULL)); - tor_capture_bugs_(2); tt_int_op(0L,OP_EQ, tor_parse_long("10",-2,0,100,NULL,NULL)); tt_int_op(0,OP_EQ, tor_parse_long("10ABC",-1,0,70000,&i,NULL)); - tt_int_op(2, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); - tor_end_capture_bugs_(); tt_int_op(i,OP_EQ, 0); /* Test parse_ulong */ @@ -2156,10 +2160,7 @@ test_util_parse_integer(void *arg) tt_int_op(0UL,OP_EQ, tor_parse_ulong("8",8,0,100,NULL,NULL)); tt_int_op(50UL,OP_EQ, tor_parse_ulong("50",10,50,100,NULL,NULL)); tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,NULL,NULL)); - tor_capture_bugs_(1); tt_int_op(0UL,OP_EQ, tor_parse_ulong("50",-1,50,100,&i,NULL)); - tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); - tor_end_capture_bugs_(); tt_int_op(0,OP_EQ, i); tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,&i,NULL)); tt_int_op(0,OP_EQ, i); @@ -2175,11 +2176,8 @@ test_util_parse_integer(void *arg) tt_assert(U64_LITERAL(0) == tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp)); tt_int_op(0,OP_EQ, i); - tor_capture_bugs_(1); tt_assert(U64_LITERAL(0) == tor_parse_uint64("123",-1,0,INT32_MAX, &i, &cp)); - tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); - tor_end_capture_bugs_(); tt_int_op(0,OP_EQ, i); { @@ -2224,7 +2222,7 @@ test_util_parse_integer(void *arg) tt_int_op(i,OP_EQ, 0); } done: - tor_end_capture_bugs_(); + ; } static void @@ -4102,7 +4100,8 @@ test_util_ftruncate(void *ptr) tt_int_op(fd, OP_GE, 0); /* Make the file be there. */ - tt_int_op(strlen(message), OP_EQ, write_all(fd, message, strlen(message),0)); + tt_int_op(strlen(message), OP_EQ, + write_all_to_fd(fd, message, strlen(message))); tt_int_op((int)tor_fd_getpos(fd), OP_EQ, strlen(message)); tt_int_op(0, OP_EQ, fstat(fd, &st)); tt_int_op((int)st.st_size, OP_EQ, strlen(message)); @@ -4115,7 +4114,7 @@ test_util_ftruncate(void *ptr) /* Replace, and see if it got replaced */ tt_int_op(strlen(message2), OP_EQ, - write_all(fd, message2, strlen(message2), 0)); + write_all_to_fd(fd, message2, strlen(message2))); tt_int_op((int)tor_fd_getpos(fd), OP_EQ, strlen(message2)); tt_int_op(0, OP_EQ, fstat(fd, &st)); tt_int_op((int)st.st_size, OP_EQ, strlen(message2)); @@ -6316,4 +6315,3 @@ struct testcase_t util_tests[] = { UTIL_TEST(get_unquoted_path, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_util_format.c b/src/test/test_util_format.c index 10645fe117..44a00b9b77 100644 --- a/src/test/test_util_format.c +++ b/src/test/test_util_format.c @@ -1,14 +1,14 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "or.h" +#include "or/or.h" -#include "test.h" +#include "test/test.h" -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_rand.h" #define UTIL_FORMAT_PRIVATE -#include "util_format.h" +#include "lib/encoding/binascii.h" #define NS_MODULE util_format diff --git a/src/test/test_util_process.c b/src/test/test_util_process.c index 68ce6cfd40..9dce520d04 100644 --- a/src/test/test_util_process.c +++ b/src/test/test_util_process.c @@ -1,15 +1,15 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define UTIL_PROCESS_PRIVATE #include "orconfig.h" -#include "or.h" +#include "or/or.h" -#include "test.h" +#include "test/test.h" -#include "util_process.h" +#include "lib/process/waitpid.h" -#include "log_test_helpers.h" +#include "test/log_test_helpers.h" #ifndef _WIN32 #define NS_MODULE util_process diff --git a/src/test/test_util_slow.c b/src/test/test_util_slow.c index 2cd68cf118..aeb0d422c1 100644 --- a/src/test/test_util_slow.c +++ b/src/test/test_util_slow.c @@ -1,15 +1,17 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define UTIL_PRIVATE -#include "util.h" -#include "util_process.h" -#include "crypto.h" -#include "torlog.h" -#include "test.h" +#define SUBPROCESS_PRIVATE +#include "common/util.h" +#include "lib/process/waitpid.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/log/torlog.h" +#include "lib/process/subprocess.h" +#include "test/test.h" #ifndef BUILDDIR #define BUILDDIR "." @@ -388,4 +390,3 @@ struct testcase_t slow_util_tests[] = { UTIL_TEST(spawn_background_waitpid_notify, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_voting_schedule.c b/src/test/test_voting_schedule.c index df6058b74f..b5df596436 100644 --- a/src/test/test_voting_schedule.c +++ b/src/test/test_voting_schedule.c @@ -3,10 +3,10 @@ #include "orconfig.h" -#include "or.h" -#include "voting_schedule.h" +#include "or/or.h" +#include "or/voting_schedule.h" -#include "test.h" +#include "test/test.h" static void test_voting_schedule_interval_start(void *arg) diff --git a/src/test/test_workqueue.c b/src/test/test_workqueue.c index cc7073850c..dda724b78b 100644 --- a/src/test/test_workqueue.c +++ b/src/test/test_workqueue.c @@ -1,15 +1,17 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "compat_threads.h" -#include "onion.h" -#include "workqueue.h" -#include "crypto_curve25519.h" -#include "crypto_rand.h" -#include "compat_libevent.h" +#include "or/or.h" +#include "lib/thread/threads.h" +#include "or/onion.h" +#include "common/workqueue.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/net/alertsock.h" +#include "common/compat_libevent.h" +#include "lib/intmath/weakrng.h" #include <stdio.h> @@ -450,4 +452,3 @@ main(int argc, char **argv) return 0; } } - diff --git a/src/test/testing_common.c b/src/test/testing_common.c index 4c3fe15960..3baeb98031 100644 --- a/src/test/testing_common.c +++ b/src/test/testing_common.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,15 +10,15 @@ #define MAIN_PRIVATE #include "orconfig.h" -#include "or.h" -#include "control.h" -#include "config.h" -#include "crypto_rand.h" -#include "rephist.h" -#include "backtrace.h" -#include "test.h" -#include "channelpadding.h" -#include "main.h" +#include "or/or.h" +#include "or/control.h" +#include "or/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "or/rephist.h" +#include "lib/err/backtrace.h" +#include "test/test.h" +#include "or/channelpadding.h" +#include "or/main.h" #include <stdio.h> #ifdef HAVE_FCNTL_H @@ -32,11 +32,6 @@ #include <dirent.h> #endif /* defined(_WIN32) */ -#ifdef USE_DMALLOC -#include <dmalloc.h> -#include "main.h" -#endif - /** Temporary directory (set up by setup_directory) under which we store all * our files during testing. */ static char temp_dir[256]; @@ -231,13 +226,6 @@ main(int c, const char **v) /* We must initialise logs before we call tor_assert() */ init_logging(1); -#ifdef USE_DMALLOC - { - int r = crypto_use_tor_alloc_functions(); - tor_assert(r == 0); - } -#endif /* defined(USE_DMALLOC) */ - update_approx_time(time(NULL)); options = options_new(); tor_threads_init(); @@ -319,10 +307,7 @@ main(int c, const char **v) int have_failed = (tinytest_main(c, v, testgroups) != 0); free_pregenerated_keys(); -#ifdef USE_DMALLOC - tor_free_all(0); - dmalloc_log_unfreed(); -#endif + crypto_global_cleanup(); if (have_failed) @@ -330,4 +315,3 @@ main(int c, const char **v) else return 0; } - diff --git a/src/test/testing_rsakeys.c b/src/test/testing_rsakeys.c index 94d3db328a..087a14e649 100644 --- a/src/test/testing_rsakeys.c +++ b/src/test/testing_rsakeys.c @@ -1,12 +1,12 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_rand.h" #include "orconfig.h" -#include "or.h" -#include "test.h" +#include "or/or.h" +#include "test/test.h" /** Define this if unit tests spend too much time generating public keys. * This module is meant to save time by using a bunch of pregenerated RSA diff --git a/src/tools/include.am b/src/tools/include.am index 016cf3b124..e6465233b6 100644 --- a/src/tools/include.am +++ b/src/tools/include.am @@ -6,42 +6,39 @@ endif src_tools_tor_resolve_SOURCES = src/tools/tor-resolve.c src_tools_tor_resolve_LDFLAGS = -src_tools_tor_resolve_LDADD = src/common/libor.a \ - src/common/libor-ctime.a \ +src_tools_tor_resolve_LDADD = \ + $(TOR_UTIL_LIBS) \ $(rust_ldadd) \ - @TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_USERENV@ + @TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@ if COVERAGE_ENABLED src_tools_tor_cov_resolve_SOURCES = src/tools/tor-resolve.c src_tools_tor_cov_resolve_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_tools_tor_cov_resolve_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) -src_tools_tor_cov_resolve_LDADD = src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ +src_tools_tor_cov_resolve_LDADD = \ + $(TOR_UTIL_TESTING_LIBS) \ @TOR_LIB_MATH@ @TOR_LIB_WS32@ endif src_tools_tor_gencert_SOURCES = src/tools/tor-gencert.c src_tools_tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ -src_tools_tor_gencert_LDADD = src/common/libor.a src/common/libor-crypto.a \ - src/common/libor-ctime.a \ - $(LIBKECCAK_TINY) \ - $(LIBDONNA) \ +src_tools_tor_gencert_LDADD = \ + $(TOR_CRYPTO_LIBS) \ + $(TOR_UTIL_LIBS) \ $(rust_ldadd) \ @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ if COVERAGE_ENABLED src_tools_tor_cov_gencert_SOURCES = src/tools/tor-gencert.c src_tools_tor_cov_gencert_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_tools_tor_cov_gencert_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_tools_tor_cov_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ -src_tools_tor_cov_gencert_LDADD = src/common/libor-testing.a \ - src/common/libor-crypto-testing.a \ - src/common/libor-ctime-testing.a \ - $(LIBKECCAK_TINY) \ - $(LIBDONNA) \ +src_tools_tor_cov_gencert_LDADD = \ + $(TOR_CRYPTO_TESTING_LIBS) \ + $(TOR_UTIL_TESTING_LIBS) \ @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ endif if BUILD_LIBTORRUNNER diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c index aafefdad74..ce032ed643 100644 --- a/src/tools/tor-gencert.c +++ b/src/tools/tor-gencert.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -13,7 +13,7 @@ #include <unistd.h> #endif -#include "compat.h" +#include "lib/cc/compat_compiler.h" /* Some versions of OpenSSL declare X509_STORE_CTX_set_verify_cb twice in * x509.h and x509_vfy.h. Suppress the GCC warning so we can build with @@ -30,20 +30,20 @@ DISABLE_GCC_WARNING(redundant-decls) ENABLE_GCC_WARNING(redundant-decls) #include <errno.h> -#if 0 -#include <stdlib.h> -#include <stdarg.h> -#include <assert.h> -#endif -#include "util.h" -#include "torlog.h" -#include "crypto.h" -#include "crypto_digest.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "address.h" -#include "util_format.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/encoding/binascii.h" +#include "lib/encoding/time_fmt.h" +#include "lib/fs/files.h" +#include "lib/log/torlog.h" +#include "lib/malloc/util_malloc.h" +#include "lib/net/address.h" +#include "lib/net/ipv4.h" +#include "lib/string/compat_string.h" +#include "lib/string/printf.h" #define IDENTITY_KEY_BITS 3072 #define SIGNING_KEY_BITS 2048 @@ -78,29 +78,6 @@ show_help(void) "[--passphrase-fd <fd>]\n"); } -/* XXXX copied from crypto.c */ -static void -crypto_log_errors(int severity, const char *doing) -{ - unsigned long err; - const char *msg, *lib, *func; - 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 (!msg) msg = "(null)"; - if (!lib) lib = "(null)"; - if (!func) func = "(null)"; - if (doing) { - tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", - doing, msg, lib, func); - } else { - tor_log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)", - msg, lib, func); - } - } -} - /** Read the passphrase from the passphrase fd. */ static int load_passphrase(void) @@ -108,7 +85,7 @@ load_passphrase(void) char *cp; char buf[1024]; /* "Ought to be enough for anybody." */ memset(buf, 0, sizeof(buf)); /* should be needless */ - ssize_t n = read_all(passphrase_fd, buf, sizeof(buf), 0); + ssize_t n = read_all_from_fd(passphrase_fd, buf, sizeof(buf)); if (n < 0) { log_err(LD_GENERAL, "Couldn't read from passphrase fd: %s", strerror(errno)); @@ -599,4 +576,3 @@ main(int argc, char **argv) crypto_global_cleanup(); return r; } - diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c index 966b88b3e8..303c7af3ee 100644 --- a/src/tools/tor-resolve.c +++ b/src/tools/tor-resolve.c @@ -1,20 +1,25 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson - * Copyright (c) 2007-2017, The Tor Project, Inc. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "compat.h" -#include "util.h" -#include "address.h" -#include "torlog.h" -#include "sandbox.h" + +#include "lib/arch/bytes.h" +#include "lib/log/torlog.h" +#include "lib/malloc/util_malloc.h" +#include "lib/net/address.h" +#include "lib/net/resolve.h" +#include "lib/net/socket.h" +#include "lib/sandbox/sandbox.h" +#include "lib/string/util_string.h" + +#include "common/socks5_status.h" #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> -#include <assert.h> #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> @@ -225,11 +230,11 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport, if (version == 5) { char method_buf[2]; - if (write_all(s, "\x05\x01\x00", 3, 1) != 3) { + if (write_all_to_socket(s, "\x05\x01\x00", 3) != 3) { log_err(LD_NET, "Error sending SOCKS5 method list."); goto err; } - if (read_all(s, method_buf, 2, 1) != 2) { + if (read_all_from_socket(s, method_buf, 2) != 2) { log_err(LD_NET, "Error reading SOCKS5 methods."); goto err; } @@ -251,7 +256,7 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport, tor_assert(!req); goto err; } - if (write_all(s, req, len, 1) != len) { + if (write_all_to_socket(s, req, len) != len) { log_sock_error("sending SOCKS request", s); tor_free(req); goto err; @@ -260,7 +265,7 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport, if (version == 4) { char reply_buf[RESPONSE_LEN_4]; - if (read_all(s, reply_buf, RESPONSE_LEN_4, 1) != RESPONSE_LEN_4) { + if (read_all_from_socket(s, reply_buf, RESPONSE_LEN_4) != RESPONSE_LEN_4) { log_err(LD_NET, "Error reading SOCKS4 response."); goto err; } @@ -271,7 +276,7 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport, } } else { char reply_buf[16]; - if (read_all(s, reply_buf, 4, 1) != 4) { + if (read_all_from_socket(s, reply_buf, 4) != 4) { log_err(LD_NET, "Error reading SOCKS5 response."); goto err; } @@ -291,14 +296,14 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport, } if (reply_buf[3] == 1) { /* IPv4 address */ - if (read_all(s, reply_buf, 4, 1) != 4) { + if (read_all_from_socket(s, reply_buf, 4) != 4) { log_err(LD_NET, "Error reading address in socks5 response."); goto err; } tor_addr_from_ipv4n(result_addr, get_uint32(reply_buf)); } else if (reply_buf[3] == 4) { /* IPv6 address */ - if (read_all(s, reply_buf, 16, 1) != 16) { + if (read_all_from_socket(s, reply_buf, 16) != 16) { log_err(LD_NET, "Error reading address in socks5 response."); goto err; } @@ -306,13 +311,14 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport, } else if (reply_buf[3] == 3) { /* Domain name */ size_t result_len; - if (read_all(s, reply_buf, 1, 1) != 1) { + if (read_all_from_socket(s, reply_buf, 1) != 1) { log_err(LD_NET, "Error reading address_length in socks5 response."); goto err; } result_len = *(uint8_t*)(reply_buf); *result_hostname = tor_malloc(result_len+1); - if (read_all(s, *result_hostname, result_len, 1) != (int) result_len) { + if (read_all_from_socket(s, *result_hostname, result_len) + != (int) result_len) { log_err(LD_NET, "Error reading hostname in socks5 response."); goto err; } @@ -451,4 +457,3 @@ main(int argc, char **argv) } return 0; } - diff --git a/src/tools/tor_runner.c b/src/tools/tor_runner.c index 9ed2ee5775..8e74a06cd9 100644 --- a/src/tools/tor_runner.c +++ b/src/tools/tor_runner.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -23,8 +23,8 @@ * functions. Don't add more dependencies! */ -#include "tor_api.h" -#include "tor_api_internal.h" +#include "or/tor_api.h" +#include "or/tor_api_internal.h" #include "orconfig.h" #ifdef HAVE_UNISTD_H diff --git a/src/trace/include.am b/src/trace/include.am deleted file mode 100644 index 3285b04de6..0000000000 --- a/src/trace/include.am +++ /dev/null @@ -1,22 +0,0 @@ -# Include the src/ so we can use the trace/events.h statement when including -# any file in that directory. -AM_CPPFLAGS += -I$(srcdir)/src - -noinst_LIBRARIES += \ - src/trace/libor-trace.a -LIBOR_TRACE_A_SOURCES = \ - src/trace/trace.c - -TRACEHEADERS = \ - src/trace/trace.h \ - src/trace/events.h - -if USE_EVENT_TRACING_DEBUG -TRACEHEADERS += \ - src/trace/debug.h -endif - -# Library source files. -src_trace_libor_trace_a_SOURCES = $(LIBOR_TRACE_A_SOURCES) - -noinst_HEADERS+= $(TRACEHEADERS) diff --git a/src/trunnel/include.am b/src/trunnel/include.am index b249fb302c..5a0a79c3a0 100644 --- a/src/trunnel/include.am +++ b/src/trunnel/include.am @@ -6,8 +6,6 @@ noinst_LIBRARIES += \ src/trunnel/libor-trunnel-testing.a endif -AM_CPPFLAGS += -I$(srcdir)/src/ext/trunnel -I$(srcdir)/src/trunnel - TRUNNELINPUTS = \ src/trunnel/ed25519_cert.trunnel \ src/trunnel/link_handshake.trunnel \ @@ -39,7 +37,8 @@ TRUNNELHEADERS = \ src/trunnel/channelpadding_negotiation.h src_trunnel_libor_trunnel_a_SOURCES = $(TRUNNELSOURCES) -src_trunnel_libor_trunnel_a_CPPFLAGS = -DTRUNNEL_LOCAL_H $(AM_CPPFLAGS) +src_trunnel_libor_trunnel_a_CPPFLAGS = \ + -DTRUNNEL_LOCAL_H $(AM_CPPFLAGS) -I$(top_srcdir)/src/trunnel if UNITTESTS_ENABLED src_trunnel_libor_trunnel_testing_a_SOURCES = $(TRUNNELSOURCES) @@ -54,4 +53,3 @@ noinst_HEADERS+= $(TRUNNELHEADERS) EXTRA_DIST += \ src/trunnel/README - diff --git a/src/trunnel/trunnel-local.h b/src/trunnel/trunnel-local.h index 8aa6d0ddaa..e81396aeea 100644 --- a/src/trunnel/trunnel-local.h +++ b/src/trunnel/trunnel-local.h @@ -2,9 +2,9 @@ #ifndef TRUNNEL_LOCAL_H_INCLUDED #define TRUNNEL_LOCAL_H_INCLUDED -#include "util.h" -#include "compat.h" -#include "crypto_util.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/malloc/util_malloc.h" +#include "lib/log/util_bug.h" #define trunnel_malloc tor_malloc #define trunnel_calloc tor_calloc diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h index 757ea2945e..65a905debe 100644 --- a/src/win32/orconfig.h +++ b/src/win32/orconfig.h @@ -218,7 +218,7 @@ #define USING_TWOS_COMPLEMENT /* Version number of package */ -#define VERSION "0.3.4.3-alpha-dev" +#define VERSION "0.3.5.0-alpha-dev" |