diff options
62 files changed, 1214 insertions, 294 deletions
diff --git a/.gitignore b/.gitignore index 80c039a684..1cd99dfd38 100644 --- a/.gitignore +++ b/.gitignore @@ -116,6 +116,11 @@ uptime-*.json /doc/torify.html /doc/torify.html.in /doc/torify.1.xml +/doc/tor-print-ed-signing-cert.1 +/doc/tor-print-ed-signing-cert.1.in +/doc/tor-print-ed-signing-cert.html +/doc/tor-print-ed-signing-cert.html.in +/doc/tor-print-ed-signing-cert.1.xml # /doc/spec/ /doc/spec/Makefile @@ -258,6 +263,8 @@ uptime-*.json /src/tools/tor-resolve /src/tools/tor-cov-resolve /src/tools/tor-gencert +/src/tools/tor-print-ed-signing-cert +/src/tools/tor-print-ed-signing-cert.exe /src/tools/tor-cov-gencert /src/tools/tor-checkkey.exe /src/tools/tor-resolve.exe diff --git a/Makefile.am b/Makefile.am index 202197f5f5..3df35ad3f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -203,7 +203,7 @@ doxygen: test: all $(top_builddir)/src/test/test -check-local: check-spaces check-changes +check-local: check-spaces check-changes check-includes need-chutney-path: @if test ! -d "$$CHUTNEY_PATH"; then \ @@ -320,7 +320,7 @@ endif check-includes: if USEPYTHON - $(top_srcdir)/scripts/maint/checkIncludes.py + $(PYTHON) $(top_srcdir)/scripts/maint/checkIncludes.py endif check-docs: all diff --git a/changes/bug26485 b/changes/bug26485 new file mode 100644 index 0000000000..5a40b7a78e --- /dev/null +++ b/changes/bug26485 @@ -0,0 +1,4 @@ + o Minor bugfixes (directory authority): + - When voting for recommended versions, make sure that all of the + versions are well-formed and parsable. Fixes bug 26485; bugfix on + 0.1.1.6-alpha. diff --git a/changes/bug26627 b/changes/bug26627 new file mode 100644 index 0000000000..d28bd05d53 --- /dev/null +++ b/changes/bug26627 @@ -0,0 +1,7 @@ + o Minor bugfixes (v3 onion services): + - Stop sending ed25519 link specifiers in v3 onion service introduce + cells, when the rendezvous point doesn't support ed25519 link + authentication. Fixes bug 26627; bugfix on 0.3.2.4-alpha. + - Stop putting ed25519 link specifiers in v3 onion service descriptors, + when the intro point doesn't support ed25519 link authentication. + Fixes bug 26627; bugfix on 0.3.2.4-alpha. diff --git a/changes/bug26785 b/changes/bug26785 new file mode 100644 index 0000000000..e6392fcbdd --- /dev/null +++ b/changes/bug26785 @@ -0,0 +1,4 @@ + o Minor bugfixes (compilation, portability): + - Don't try to use a pragma to temporarily disable + -Wunused-const-variable if the compiler doesn't support it. + Fixes bug 26785; bugfix on 0.3.2.11. diff --git a/changes/bug26787 b/changes/bug26787 new file mode 100644 index 0000000000..b32e519a93 --- /dev/null +++ b/changes/bug26787 @@ -0,0 +1,3 @@ + o Minor bugfixes (testing): + - Disable core dumps in test_bt.sh, to avoid failures in "make + distcheck". Fixes bug 26787; bugfix on 0.2.5.2-alpha. diff --git a/changes/bug26853 b/changes/bug26853 new file mode 100644 index 0000000000..6ee47789b9 --- /dev/null +++ b/changes/bug26853 @@ -0,0 +1,3 @@ + o Minor bugfixes (continuous integration): + - Skip an unreliable key expiration test on Windows, until the underlying + issue in bug 26076 is resolved. Fixes bug 26853; bugfix on 0.3.2.1-alpha. diff --git a/changes/bug26876 b/changes/bug26876 new file mode 100644 index 0000000000..b661104236 --- /dev/null +++ b/changes/bug26876 @@ -0,0 +1,4 @@ + o Minor bugfixes (portability): + - Work around two different bugs in the OS X 10.10 and later SDKs that + would prevent us from successfully targeting earlier versions of OS X. + Fixes bug 26876; bugfix on 0.3.3.1-alpha. diff --git a/changes/bug26892 b/changes/bug26892 new file mode 100644 index 0000000000..6fc8a03204 --- /dev/null +++ b/changes/bug26892 @@ -0,0 +1,6 @@ + o Minor bugfixes (logging): + - As a precaution, do an early return from + log_addr_has_changed() if Tor is running as client. Also, + log a stack trace for debugging as this function should only + be called when Tor runs as server. Fixes bug 26892; + bugfix on 0.1.1.9-alpha. diff --git a/changes/bug26924 b/changes/bug26924 new file mode 100644 index 0000000000..882db56b40 --- /dev/null +++ b/changes/bug26924 @@ -0,0 +1,4 @@ + o Minor bugfixes (single onion services, Tor2web): + - Log a protocol warning when single onion services or Tor2web clients + fail to authenticate direct connections to relays. + Fixes bug 26924; bugfix on 0.2.9.1-alpha. diff --git a/changes/bug26927 b/changes/bug26927 new file mode 100644 index 0000000000..cd035bba8e --- /dev/null +++ b/changes/bug26927 @@ -0,0 +1,4 @@ + o Minor bugfixes (logging): + - Improve the log message when connection initiators fail to authenticate + direct connections to relays. + Fixes bug 26927; bugfix on 0.3.0.1-alpha. diff --git a/changes/bug26979 b/changes/bug26979 new file mode 100644 index 0000000000..e615207b74 --- /dev/null +++ b/changes/bug26979 @@ -0,0 +1,4 @@ + o Minor bugfixes (appveyor ci): + - Improve Appveyor CI IRC logging. Generate correct branches and URLs for + pull requests and tags. Use unambiguous short commits. + Fixes bug 26979; bugfix on master. diff --git a/changes/bug26986 b/changes/bug26986 new file mode 100644 index 0000000000..a3ab9ff25d --- /dev/null +++ b/changes/bug26986 @@ -0,0 +1,3 @@ + o Minor bugfixes (compilation): + - Use Windows-compatible format strings in tor-print-ed-signing-cert.c. + Fixes bug 26986; bugfix on master. diff --git a/changes/feature19506 b/changes/feature19506 new file mode 100644 index 0000000000..83ba9e245f --- /dev/null +++ b/changes/feature19506 @@ -0,0 +1,3 @@ + o Minor features (admin tools): + - Add new tool that prints expiration date of signing cert + in ed25519_signing_cert. Resolves issue 19506. diff --git a/changes/ticket21349 b/changes/ticket21349 new file mode 100644 index 0000000000..c072884062 --- /dev/null +++ b/changes/ticket21349 @@ -0,0 +1,6 @@ + o Code simplification and refactoring: + - Split sampled_guards_update_from_consensus() and + select_entry_guard_for_circuit() into subfunctions. + In entry_guards_update_primary() unite + three smartlist enumerations into one and move smartlist + comparison code out of the function. Closes ticket 21349. diff --git a/changes/ticket26447 b/changes/ticket26447 new file mode 100644 index 0000000000..757a4022ff --- /dev/null +++ b/changes/ticket26447 @@ -0,0 +1,5 @@ + o Minor features (code correctness, testing): + - Tor's build process now includes a "check-includes" make target + to verify that no module of Tor relies on any headers from a + higher-level module. We hope to use this feature over time to + help refactor our codebase. Closes ticket 26447. diff --git a/changes/ticket26647 b/changes/ticket26647 new file mode 100644 index 0000000000..1c2e917c6d --- /dev/null +++ b/changes/ticket26647 @@ -0,0 +1,4 @@ + o Minor features (controller): + - The control port now exposes the list of HTTPTunnelPorts and + ExtOrPorts via GETINFO net/listeners/httptunnel and net/listeners/extor + respectively. Closes ticket 26647. diff --git a/changes/ticket3723 b/changes/ticket3723 new file mode 100644 index 0000000000..3deefe27b0 --- /dev/null +++ b/changes/ticket3723 @@ -0,0 +1,3 @@ + o Minor features (directory authority): + - When a bandwidth file is used to obtain the bandwidth measurements, + include this bandwidth file headers in the votes. Closes ticket 3723. diff --git a/configure.ac b/configure.ac index 532476672a..32eed75bf9 100644 --- a/configure.ac +++ b/configure.ac @@ -600,7 +600,6 @@ AC_CHECK_FUNCS( llround \ localtime_r \ lround \ - mach_approximate_time \ memmem \ memset_s \ mmap \ @@ -629,9 +628,36 @@ AC_CHECK_FUNCS( _vscprintf ) -# Apple messed up when they added two functions functions in Sierra: they +# Apple messed up when they added some functions: they # forgot to decorate them with appropriate AVAILABLE_MAC_OS_VERSION -# checks. So we should only probe for those functions if we are sure that we +# checks. + +# We should only probe for these functions if we are sure that we +# are not targeting OS X 10.9 or earlier. +AC_MSG_CHECKING([for a pre-Yosemite OS X build target]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#ifdef __APPLE__ +# include <AvailabilityMacros.h> +# ifndef MAC_OS_X_VERSION_10_10 +# define MAC_OS_X_VERSION_10_10 101000 +# endif +# if defined(MAC_OS_X_VERSION_MIN_REQUIRED) +# if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10 +# error "Running on Mac OS X 10.9 or earlier" +# endif +# endif +#endif +]], [[]])], + [on_macos_pre_10_10=no ; AC_MSG_RESULT([no])], + [on_macos_pre_10_10=yes; AC_MSG_RESULT([yes])]) + +if test "$on_macos_pre_10_10" = "no"; then + AC_CHECK_FUNCS( + mach_approximate_time \ + ) +fi + +# We should only probe for these functions if we are sure that we # are not targeting OSX 10.11 or earlier. AC_MSG_CHECKING([for a pre-Sierra OSX build target]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @@ -902,6 +928,7 @@ AC_CHECK_MEMBERS([struct ssl_method_st.get_cipher_by_char], , , ]) AC_CHECK_FUNCS([ \ + ERR_load_KDF_strings \ SSL_SESSION_get_master_key \ SSL_get_server_random \ SSL_get_client_ciphers \ @@ -2252,6 +2279,9 @@ dnl -Wthread-safety-precise if test "$tor_cv_cflags__Woverlength_strings" = "yes"; then AC_DEFINE([HAVE_CFLAG_WOVERLENGTH_STRINGS], 1, [True if we have -Woverlength-strings]) fi + if test "$tor_cv_cflags__warn_unused_const_variable_2" = "yes"; then + AC_DEFINE([HAVE_CFLAG_WUNUSED_CONST_VARIABLE], 1, [True if we have -Wunused-const-variable]) + fi if test "x$enable_fatal_warnings" = "xyes"; then # I'd like to use TOR_CHECK_CFLAGS here, but I can't, since the diff --git a/doc/HACKING/HelpfulTools.md b/doc/HACKING/HelpfulTools.md index 13d1c4b0d7..d499238526 100644 --- a/doc/HACKING/HelpfulTools.md +++ b/doc/HACKING/HelpfulTools.md @@ -4,9 +4,16 @@ Useful tools These aren't strictly necessary for hacking on Tor, but they can help track down bugs. -Travis CI ---------- -It's CI. Looks like this: https://travis-ci.org/torproject/tor. +Travis/Appveyor CI +------------------ +It's CI. + +Looks like this: +* https://travis-ci.org/torproject/tor +* https://ci.appveyor.com/project/torproject/tor + +Travis builds and runs tests on Linux, and eventually macOS (#24629). +Appveyor builds and runs tests on Windows (using Windows Services for Linux). Runs automatically on Pull Requests sent to torproject/tor. You can set it up for your fork to build commits outside of PRs too: @@ -16,6 +23,8 @@ for your fork to build commits outside of PRs too: https://help.github.com/articles/fork-a-repo/ 3. follow https://docs.travis-ci.com/user/getting-started/#To-get-started-with-Travis-CI. skip steps involving `.travis.yml` (we already have one). +4. go to https://ci.appveyor.com/login , log in with github, and select + "NEW PROJECT" Builds should show up on the web at travis-ci.com and on IRC at #tor-ci on OFTC. If they don't, ask #tor-dev (also on OFTC). @@ -23,7 +32,16 @@ OFTC. If they don't, ask #tor-dev (also on OFTC). Jenkins ------- - https://jenkins.torproject.org +It's CI/builders. Looks like this: https://jenkins.torproject.org + +Runs automatically on commits merged to git.torproject.org. We CI the +master branch and all supported tor versions. We also build nightly debian +packages from master. + +Builds Linux and Windows cross-compilation. Runs Linux tests. + +Builds should show up on the web at jenkins.torproject.org and on IRC at +#tor-bots on OFTC. If they don't, ask #tor-dev (also on OFTC). Valgrind -------- diff --git a/doc/include.am b/doc/include.am index 0e533c1b3b..0a123aae11 100644 --- a/doc/include.am +++ b/doc/include.am @@ -12,7 +12,7 @@ # part of the source distribution, so that people without asciidoc can # just use the .1 and .html files. -all_mans = doc/tor doc/tor-gencert doc/tor-resolve doc/torify +all_mans = doc/tor doc/tor-gencert doc/tor-resolve doc/torify doc/tor-print-ed-signing-cert if USE_ASCIIDOC nodist_man1_MANS = $(all_mans:=.1) @@ -65,11 +65,13 @@ doc/tor.1.in: doc/tor.1.txt doc/torify.1.in: doc/torify.1.txt doc/tor-gencert.1.in: doc/tor-gencert.1.txt doc/tor-resolve.1.in: doc/tor-resolve.1.txt +doc/tor-print-ed-signing-cert.1.in: doc/tor-print-ed-signing-cert.1.txt doc/tor.html.in: doc/tor.1.txt doc/torify.html.in: doc/torify.1.txt doc/tor-gencert.html.in: doc/tor-gencert.1.txt doc/tor-resolve.html.in: doc/tor-resolve.1.txt +doc/tor-print-ed-signing-cert.html.in: doc/tor-print-ed-signing-cert.1.txt # use config.status to swap all machine-specific magic strings # in the asciidoc with their replacements. @@ -83,11 +85,13 @@ $(asciidoc_product) : doc/tor.html: doc/tor.html.in doc/tor-gencert.html: doc/tor-gencert.html.in doc/tor-resolve.html: doc/tor-resolve.html.in +doc/tor-print-ed-signing-cert.html: doc/tor-print-ed-signing-cert.html.in doc/torify.html: doc/torify.html.in doc/tor.1: doc/tor.1.in doc/tor-gencert.1: doc/tor-gencert.1.in doc/tor-resolve.1: doc/tor-resolve.1.in +doc/tor-print-ed-signing-cert.1: doc/tor-print-ed-signing-cert.1.in doc/torify.1: doc/torify.1.in CLEANFILES+= $(asciidoc_product) diff --git a/doc/tor-print-ed-signing-cert.1.txt b/doc/tor-print-ed-signing-cert.1.txt new file mode 100644 index 0000000000..1a3109df95 --- /dev/null +++ b/doc/tor-print-ed-signing-cert.1.txt @@ -0,0 +1,32 @@ +// Copyright (c) The Tor Project, Inc. +// See LICENSE for licensing information +// This is an asciidoc file used to generate the manpage/html reference. +// Learn asciidoc on http://www.methods.co.nz/asciidoc/userguide.html +:man source: Tor +:man manual: Tor Manual +tor-print-ed-signing-cert(1) +============================ +Tor Project, Inc. + +NAME +---- +tor-print-ed-signing-cert - print expiration date of ed25519 signing certificate + +SYNOPSIS +-------- +**tor-print-ed-signing-cert** __<path to ed25519_signing_cert file>__ + +DESCRIPTION +----------- +**tor-print-ed-signing-cert** is utility program for Tor relay operators to +check expiration date of ed25519 signing certificate. + +SEE ALSO +-------- +**tor**(1) + + +https://spec.torproject.org/cert-spec + +AUTHORS +------- +Roger Dingledine <arma@mit.edu>, Nick Mathewson <nickm@alum.mit.edu>. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index f42ad0dd3c..1db8cabf86 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -2747,7 +2747,9 @@ on the public Tor network. [[V3BandwidthsFile]] **V3BandwidthsFile** __FILENAME__:: V3 authoritative directories only. Configures the location of the bandwidth-authority generated file storing information on relays' measured - bandwidth capacities. (Default: unset) + bandwidth capacities. To avoid inconsistent reads, bandwidth data should + be written to temporary file, then renamed to the configured filename. + (Default: unset) [[V3AuthUseLegacyKey]] **V3AuthUseLegacyKey** **0**|**1**:: If set, the directory authority will sign consensuses not only with its diff --git a/scripts/maint/checkIncludes.py b/scripts/maint/checkIncludes.py index 5cf7ead47e..d13ff565cb 100755 --- a/scripts/maint/checkIncludes.py +++ b/scripts/maint/checkIncludes.py @@ -1,6 +1,21 @@ #!/usr/bin/python3 # Copyright 2018 The Tor Project, Inc. See LICENSE file for licensing info. +"""This script looks through all the directories for files matching *.c or + *.h, and checks their #include directives to make sure that only "permitted" + headers are included. + + Any #include directives with angle brackets (like #include <stdio.h>) are + ignored -- only directives with quotes (like #include "foo.h") are + considered. + + To decide what includes are permitted, this script looks at a .may_include + file in each directory. This file contains empty lines, #-prefixed + comments, filenames (like "lib/foo/bar.h") and file globs (like lib/*/*.h) + for files that are permitted. +""" + + from __future__ import print_function import fnmatch @@ -8,20 +23,26 @@ import os import re import sys +# Global: Have there been any errors? trouble = False def err(msg): + """ Declare that an error has happened, and remember that there has + been an error. """ global trouble trouble = True print(msg, file=sys.stderr) def fname_is_c(fname): + """ Return true iff 'fname' is the name of a file that we should + search for possibly disallowed #include directives. """ return fname.endswith(".h") or fname.endswith(".c") INCLUDE_PATTERN = re.compile(r'\s*#\s*include\s+"([^"]*)"') RULES_FNAME = ".may_include" class Rules(object): + """ A 'Rules' object is the parsed version of a .may_include file. """ def __init__(self, dirpath): self.dirpath = dirpath self.patterns = [] @@ -59,6 +80,7 @@ class Rules(object): print("Pattern {} in {} was never used.".format(p, self.dirpath)) def load_include_rules(fname): + """ Read a rules file from 'fname', and return it as a Rules object. """ result = Rules(os.path.split(fname)[0]) with open(fname, 'r') as f: for line in f: @@ -81,6 +103,6 @@ for dirpath, dirnames, fnames in os.walk("src"): if trouble: err( -"""To change which includes are allowed in a C file, edit the {} files in its -enclosing directory.""".format(RULES_FNAME)) +"""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/test/appveyor-irc-notify.py b/scripts/test/appveyor-irc-notify.py index 4ffea52684..cfe0afe7ae 100644 --- a/scripts/test/appveyor-irc-notify.py +++ b/scripts/test/appveyor-irc-notify.py @@ -22,6 +22,12 @@ # - Accept UTF-8 # - only guess github URLs # - stop using ANSI colors +# +# Modified by teor in 2018: +# - fix github provider detection ('gitHub' or 'gitHubEnterprise', apparently) +# - make short commits 10 hexdigits long (that's what git does for tor) +# - generate correct branches and URLs for pull requests and tags +# - switch to one URL per line # This program is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License as published by the Free Software Foundation; @@ -45,19 +51,19 @@ delineate multiple messages. Example: -export APPVEYOR_URL=https://ci.appveyor.com +export APPVEYOR_ACCOUNT_NAME=isislovecruft +export APPVEYOR_BUILD_VERSION=1 export APPVEYOR_PROJECT_NAME=tor -export APPVEYOR_REPO_COMMIT_AUTHOR=isislovecruft -export APPVEYOR_REPO_COMMIT_TIMESTAMP=2018-04-23 -export APPVEYOR_REPO_PROVIDER=gihub -export APPVEYOR_REPO_BRANCH=repo_branch +export APPVEYOR_PULL_REQUEST_NUMBER=pull_request_number export APPVEYOR_PULL_REQUEST_TITLE=pull_request_title -export APPVEYOR_BUILD_VERSION=1 +export APPVEYOR_REPO_BRANCH=repo_branch export APPVEYOR_REPO_COMMIT=22c95b72e29248dc4de9b85e590ee18f6f587de8 +export APPVEYOR_REPO_COMMIT_AUTHOR=isislovecruft export APPVEYOR_REPO_COMMIT_MESSAGE="some IRC test" -export APPVEYOR_ACCOUNT_NAME=isislovecruft -export APPVEYOR_PULL_REQUEST_NUMBER=pull_request_number +export APPVEYOR_REPO_COMMIT_TIMESTAMP=2018-04-23 export APPVEYOR_REPO_NAME=isislovecruft/tor +export APPVEYOR_REPO_PROVIDER=github +export APPVEYOR_URL=https://ci.appveyor.com python ./appveyor-irc-notify.py irc.oftc.net:6697 tor-ci '{repo_name} {repo_branch} {short_commit} - {repo_commit_author}: {repo_commit_message}','Build #{build_version} passed. Details: {build_url} | Commit: {commit_url} See also https://github.com/gridsync/gridsync/blob/master/appveyor.yml for examples @@ -82,7 +88,7 @@ import time def appveyor_vars(): """ - Return a dict of key value carfted from appveyor environment variables. + Return a dict of key value crafted from appveyor environment variables. """ vars = dict([ @@ -90,33 +96,52 @@ def appveyor_vars(): v.replace('APPVEYOR_', '').lower(), os.getenv(v, '').decode('utf-8') ) for v in [ - 'APPVEYOR_URL', - 'APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED', + 'APPVEYOR_ACCOUNT_NAME', + 'APPVEYOR_BUILD_VERSION', + 'APPVEYOR_PROJECT_NAME', + 'APPVEYOR_PULL_REQUEST_HEAD_COMMIT', + 'APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH', + 'APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME', + 'APPVEYOR_PULL_REQUEST_NUMBER', + 'APPVEYOR_PULL_REQUEST_TITLE', 'APPVEYOR_REPO_BRANCH', + 'APPVEYOR_REPO_COMMIT', 'APPVEYOR_REPO_COMMIT_AUTHOR', 'APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL', + 'APPVEYOR_REPO_COMMIT_MESSAGE', + 'APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED', 'APPVEYOR_REPO_COMMIT_TIMESTAMP', + 'APPVEYOR_REPO_NAME', 'APPVEYOR_REPO_PROVIDER', - 'APPVEYOR_PROJECT_NAME', - 'APPVEYOR_PULL_REQUEST_TITLE', - 'APPVEYOR_BUILD_VERSION', - 'APPVEYOR_REPO_COMMIT', - 'APPVEYOR_REPO_COMMIT_MESSAGE', - 'APPVEYOR_ACCOUNT_NAME', - 'APPVEYOR_PULL_REQUEST_NUMBER', - 'APPVEYOR_REPO_NAME' + 'APPVEYOR_REPO_TAG_NAME', + 'APPVEYOR_URL', ] ]) BUILD_FMT = u'{url}/project/{account_name}/{project_name}/build/{build_version}' - if vars["repo_provider"] == 'github': - COMMIT_FMT = u'https://{repo_provider}.com/{repo_name}/commit/{repo_commit}' + if vars["repo_tag_name"]: + BRANCH_FMT = u'{repo_name} {repo_tag_name} {short_commit}' + else: + BRANCH_FMT = u'{repo_name} {repo_branch} {short_commit}' + + vars.update(head_commit=vars["repo_commit"]) + + if vars["repo_provider"].lower().startswith('github'): + COMMIT_FMT = u'https://github.com/{repo_name}/commit/{repo_commit}' + if vars["pull_request_number"]: + vars.update(head_commit=vars["pull_request_head_commit"]) + BRANCH_FMT = u'{repo_name} {repo_branch} pull {pull_request_head_repo_name} {pull_request_head_repo_branch} {short_commit}' + COMMIT_FMT = u'https://github.com/{pull_request_head_repo_name}/commit/{pull_request_head_commit}' + PULL_FMT = u'https://github.com/{repo_name}/pull/{pull_request_number}' + vars.update(pull_url=PULL_FMT.format(**vars)) vars.update(commit_url=COMMIT_FMT.format(**vars)) + vars.update(short_commit=vars["head_commit"][:10]) + vars.update( build_url=BUILD_FMT.format(**vars), - short_commit=vars["repo_commit"][:7], + branch_detail=BRANCH_FMT.format(**vars), ) return vars @@ -134,17 +159,19 @@ def notify(): if success or failure: messages = [] - messages.append(u"{repo_name} {repo_branch} {short_commit} - {repo_commit_author}: {repo_commit_message}") + messages.append(u"{branch_detail} - {repo_commit_author}: {repo_commit_message}") if success: - m = u"Build #{build_version} passed. Details: {build_url}" + messages.append(u"Build #{build_version} passed. Details: {build_url}") if failure: - m = u"Build #{build_version} failed. Details: {build_url}" + messages.append(u"Build #{build_version} failed. Details: {build_url}") if "commit_url" in apvy_vars: - m += " Commit: {commit_url}" - - messages.append(m) + messages.append(u"Commit: {commit_url}") + + if "pull_url" in apvy_vars: + messages.append(u"Pull: {pull_url}") + else: messages = sys.argv[3:] messages = ' '.join(messages) diff --git a/src/app/config/config.c b/src/app/config/config.c index 1f4f099be7..1b1889779d 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -3544,6 +3544,16 @@ options_validate(or_options_t *old_options, or_options_t *options, !options->RecommendedServerVersions)) REJECT("Versioning authoritative dir servers must set " "Recommended*Versions."); + +#ifdef HAVE_MODULE_DIRAUTH + char *t; + /* Call these functions to produce warnings only. */ + t = format_recommended_version_list(options->RecommendedClientVersions, 1); + tor_free(t); + t = format_recommended_version_list(options->RecommendedServerVersions, 1); + tor_free(t); +#endif + if (options->UseEntryGuards) { log_info(LD_CONFIG, "Authoritative directory servers can't set " "UseEntryGuards. Disabling."); @@ -3560,7 +3570,7 @@ options_validate(or_options_t *old_options, or_options_t *options, "(Bridge/V3)AuthoritativeDir is set."); /* If we have a v3bandwidthsfile and it's broken, complain on startup */ if (options->V3BandwidthsFile && !old_options) { - dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL); + dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL, NULL); } /* same for guardfraction file */ if (options->GuardfractionFile && !old_options) { diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c index 159ee96266..c5ff10f6a3 100644 --- a/src/core/or/connection_or.c +++ b/src/core/or/connection_or.c @@ -52,6 +52,7 @@ #include "core/proto/proto_cell.h" #include "core/or/reasons.h" #include "core/or/relay.h" +#include "feature/rend/rendcommon.h" #include "feature/stats/rephist.h" #include "feature/relay/router.h" #include "feature/relay/routerkeys.h" @@ -1938,10 +1939,13 @@ connection_or_client_learned_peer_id(or_connection_t *conn, conn->identity_digest); const int is_authority_fingerprint = router_digest_is_trusted_dir( conn->identity_digest); + const int non_anonymous_mode = rend_non_anonymous_mode_enabled(options); int severity; const char *extra_log = ""; - if (server_mode(options)) { + /* Relays and Single Onion Services make direct connections using + * untrusted authentication keys. */ + if (server_mode(options) || non_anonymous_mode) { severity = LOG_PROTOCOL_WARN; } else { if (using_hardcoded_fingerprints) { @@ -1965,8 +1969,8 @@ connection_or_client_learned_peer_id(or_connection_t *conn, } log_fn(severity, LD_HANDSHAKE, - "Tried connecting to router at %s:%d, but RSA identity key was not " - "as expected: wanted %s + %s but got %s + %s.%s", + "Tried connecting to router at %s:%d, but RSA + ed25519 identity " + "keys were not as expected: wanted %s + %s but got %s + %s.%s", conn->base_.address, conn->base_.port, expected_rsa, expected_ed, seen_rsa, seen_ed, extra_log); @@ -1983,8 +1987,8 @@ connection_or_client_learned_peer_id(or_connection_t *conn, } if (!expected_ed_key && ed_peer_id) { - log_info(LD_HANDSHAKE, "(we had no Ed25519 ID in mind when we made this " - "connection."); + log_info(LD_HANDSHAKE, "(We had no Ed25519 ID in mind when we made this " + "connection.)"); connection_or_set_identity_digest(conn, (const char*)rsa_peer_id, ed_peer_id); changed_identity = 1; diff --git a/src/core/or/relay.c b/src/core/or/relay.c index 32bb69d25f..51084e2a17 100644 --- a/src/core/or/relay.c +++ b/src/core/or/relay.c @@ -2005,9 +2005,10 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, } if (connection_edge_send_command(conn, RELAY_COMMAND_DATA, - payload, length) < 0 ) + payload, length) < 0 ) { /* circuit got marked for close, don't continue, don't need to mark conn */ return 0; + } if (!cpath_layer) { /* non-rendezvous exit */ tor_assert(circ->package_window > 0); diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c index 664be8ce11..494ad33528 100644 --- a/src/feature/client/entrynodes.c +++ b/src/feature/client/entrynodes.c @@ -406,6 +406,17 @@ get_remove_unlisted_guards_after_days(void) DFLT_REMOVE_UNLISTED_GUARDS_AFTER_DAYS, 1, 365*10); } + +/** + * Return number of seconds that will make a guard no longer eligible + * for selection if unlisted for this long. + */ +static time_t +get_remove_unlisted_guards_after_seconds(void) +{ + return get_remove_unlisted_guards_after_days() * 24 * 60 * 60; +} + /** * We remove unconfirmed guards from the sample after this many days, * regardless of whether they are listed or unlisted. @@ -1237,30 +1248,28 @@ entry_guard_is_listed,(guard_selection_t *gs, const entry_guard_t *guard)) } /** - * Update the status of all sampled guards based on the arrival of a - * new consensus networkstatus document. This will include marking - * some guards as listed or unlisted, and removing expired guards. */ -STATIC void -sampled_guards_update_from_consensus(guard_selection_t *gs) + * Enumerate <b>sampled_entry_guards</b> smartlist in <b>gs</b>. + * For each <b>entry_guard_t</b> object in smartlist, do the following: + * * Update <b>currently_listed</b> field to reflect if guard is listed + * in guard selection <b>gs</b>. + * * Set <b>unlisted_since_date</b> to approximate UNIX time of + * unlisting if guard is unlisted (randomize within 20% of + * get_remove_unlisted_guards_after_seconds()). Otherwise, + * set it to 0. + * + * Require <b>gs</b> to be non-null pointer. + * Return a number of entries updated. + */ +static size_t +sampled_guards_update_consensus_presence(guard_selection_t *gs) { - tor_assert(gs); - const int REMOVE_UNLISTED_GUARDS_AFTER = - (get_remove_unlisted_guards_after_days() * 86400); - const int unlisted_since_slop = REMOVE_UNLISTED_GUARDS_AFTER / 5; + size_t n_changes = 0; - // It's important to use only a live consensus here; we don't want to - // make changes based on anything expired or old. - if (live_consensus_is_missing(gs)) { - log_info(LD_GUARD, "Not updating the sample guard set; we have " - "no live consensus."); - return; - } - log_info(LD_GUARD, "Updating sampled guard status based on received " - "consensus."); + tor_assert(gs); - int n_changes = 0; + const time_t unlisted_since_slop = + get_remove_unlisted_guards_after_seconds() / 5; - /* First: Update listed/unlisted. */ SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) { /* XXXX #20827 check ed ID too */ const int is_listed = entry_guard_is_listed(gs, guard); @@ -1304,14 +1313,33 @@ sampled_guards_update_from_consensus(guard_selection_t *gs) } } SMARTLIST_FOREACH_END(guard); - const time_t remove_if_unlisted_since = - approx_time() - REMOVE_UNLISTED_GUARDS_AFTER; - const time_t maybe_remove_if_sampled_before = - approx_time() - get_guard_lifetime(); - const time_t remove_if_confirmed_before = - approx_time() - get_guard_confirmed_min_lifetime(); + return n_changes; +} + +/** + * Enumerate <b>sampled_entry_guards</b> smartlist in <b>gs</b>. + * For each <b>entry_guard_t</b> object in smartlist, do the following: + * * If <b>currently_listed</b> is false and <b>unlisted_since_date</b> + * is earlier than <b>remove_if_unlisted_since</b> - remove it. + * * Otherwise, check if <b>sampled_on_date</b> is earlier than + * <b>maybe_remove_if_sampled_before</b>. + * * When above condition is correct, remove the guard if: + * * It was never confirmed. + * * It was confirmed before <b>remove_if_confirmed_before</b>. + * + * Require <b>gs</b> to be non-null pointer. + * Return number of entries deleted. + */ +static size_t +sampled_guards_prune_obsolete_entries(guard_selection_t *gs, + const time_t remove_if_unlisted_since, + const time_t maybe_remove_if_sampled_before, + const time_t remove_if_confirmed_before) +{ + size_t n_changes = 0; + + tor_assert(gs); - /* Then: remove the ones that have been junk for too long */ SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) { int rmv = 0; @@ -1319,7 +1347,7 @@ sampled_guards_update_from_consensus(guard_selection_t *gs) guard->unlisted_since_date < remove_if_unlisted_since) { /* "We have a live consensus, and {IS_LISTED} is false, and - {FIRST_UNLISTED_AT} is over {REMOVE_UNLISTED_GUARDS_AFTER} + {FIRST_UNLISTED_AT} is over get_remove_unlisted_guards_after_days() days in the past." */ log_info(LD_GUARD, "Removing sampled guard %s: it has been unlisted " @@ -1355,6 +1383,45 @@ sampled_guards_update_from_consensus(guard_selection_t *gs) } } SMARTLIST_FOREACH_END(guard); + return n_changes; +} + +/** + * Update the status of all sampled guards based on the arrival of a + * new consensus networkstatus document. This will include marking + * some guards as listed or unlisted, and removing expired guards. */ +STATIC void +sampled_guards_update_from_consensus(guard_selection_t *gs) +{ + tor_assert(gs); + + // It's important to use only a live consensus here; we don't want to + // make changes based on anything expired or old. + if (live_consensus_is_missing(gs)) { + log_info(LD_GUARD, "Not updating the sample guard set; we have " + "no live consensus."); + return; + } + log_info(LD_GUARD, "Updating sampled guard status based on received " + "consensus."); + + /* First: Update listed/unlisted. */ + size_t n_changes = sampled_guards_update_consensus_presence(gs); + + const time_t remove_if_unlisted_since = + approx_time() - get_remove_unlisted_guards_after_seconds(); + const time_t maybe_remove_if_sampled_before = + approx_time() - get_guard_lifetime(); + const time_t remove_if_confirmed_before = + approx_time() - get_guard_confirmed_min_lifetime(); + + /* Then: remove the ones that have been junk for too long */ + n_changes += + sampled_guards_prune_obsolete_entries(gs, + remove_if_unlisted_since, + maybe_remove_if_sampled_before, + remove_if_confirmed_before); + if (n_changes) { gs->primary_guards_up_to_date = 0; entry_guards_update_filtered_sets(gs); @@ -1816,28 +1883,24 @@ entry_guards_update_primary(guard_selection_t *gs) smartlist_add(new_primary_guards, guard); } SMARTLIST_FOREACH_END(guard); - /* Can we keep any older primary guards? First remove all the ones - * that we already kept. */ SMARTLIST_FOREACH_BEGIN(old_primary_guards, entry_guard_t *, guard) { + /* Can we keep any older primary guards? First remove all the ones + * that we already kept. */ if (smartlist_contains(new_primary_guards, guard)) { SMARTLIST_DEL_CURRENT_KEEPORDER(old_primary_guards, guard); - } - } SMARTLIST_FOREACH_END(guard); - - /* Now add any that are still good. */ - SMARTLIST_FOREACH_BEGIN(old_primary_guards, entry_guard_t *, guard) { - if (smartlist_len(new_primary_guards) >= N_PRIMARY_GUARDS) - break; - if (! guard->is_filtered_guard) continue; - guard->is_primary = 1; - smartlist_add(new_primary_guards, guard); - SMARTLIST_DEL_CURRENT_KEEPORDER(old_primary_guards, guard); - } SMARTLIST_FOREACH_END(guard); + } - /* Mark the remaining previous primary guards as non-primary */ - SMARTLIST_FOREACH_BEGIN(old_primary_guards, entry_guard_t *, guard) { - guard->is_primary = 0; + /* Now add any that are still good. */ + if (smartlist_len(new_primary_guards) < N_PRIMARY_GUARDS && + guard->is_filtered_guard) { + guard->is_primary = 1; + smartlist_add(new_primary_guards, guard); + SMARTLIST_DEL_CURRENT_KEEPORDER(old_primary_guards, guard); + } else { + /* Mark the remaining previous primary guards as non-primary */ + guard->is_primary = 0; + } } SMARTLIST_FOREACH_END(guard); /* Finally, fill out the list with sampled guards. */ @@ -1861,18 +1924,8 @@ entry_guards_update_primary(guard_selection_t *gs) }); #endif /* 1 */ - int any_change = 0; - if (smartlist_len(gs->primary_entry_guards) != - smartlist_len(new_primary_guards)) { - any_change = 1; - } else { - SMARTLIST_FOREACH_BEGIN(gs->primary_entry_guards, entry_guard_t *, g) { - if (g != smartlist_get(new_primary_guards, g_sl_idx)) { - any_change = 1; - } - } SMARTLIST_FOREACH_END(g); - } - + const int any_change = !smartlist_ptrs_eq(gs->primary_entry_guards, + new_primary_guards); if (any_change) { log_info(LD_GUARD, "Primary entry guards have changed. " "New primary guard list is: "); @@ -1974,31 +2027,23 @@ entry_guards_note_internet_connectivity(guard_selection_t *gs) } /** - * Get a guard for use with a circuit. Prefer to pick a running primary - * guard; then a non-pending running filtered confirmed guard; then a - * non-pending runnable filtered guard. Update the + * Pick a primary guard for use with a circuit, if available. Update the * <b>last_tried_to_connect</b> time and the <b>is_pending</b> fields of the * guard as appropriate. Set <b>state_out</b> to the new guard-state * of the circuit. */ -STATIC entry_guard_t * -select_entry_guard_for_circuit(guard_selection_t *gs, - guard_usage_t usage, - const entry_guard_restriction_t *rst, - unsigned *state_out) +static entry_guard_t * +select_primary_guard_for_circuit(guard_selection_t *gs, + guard_usage_t usage, + const entry_guard_restriction_t *rst, + unsigned *state_out) { const int need_descriptor = (usage == GUARD_USAGE_TRAFFIC); - tor_assert(gs); - tor_assert(state_out); - - if (!gs->primary_guards_up_to_date) - entry_guards_update_primary(gs); + entry_guard_t *chosen_guard = NULL; int num_entry_guards = get_n_primary_guards_to_use(usage); smartlist_t *usable_primary_guards = smartlist_new(); - /* "If any entry in PRIMARY_GUARDS has {is_reachable} status of - <maybe> or <yes>, return the first such guard." */ SMARTLIST_FOREACH_BEGIN(gs->primary_entry_guards, entry_guard_t *, guard) { entry_guard_consider_retry(guard); if (! entry_guard_obeys_restriction(guard, rst)) @@ -2016,18 +2061,30 @@ select_entry_guard_for_circuit(guard_selection_t *gs, } SMARTLIST_FOREACH_END(guard); if (smartlist_len(usable_primary_guards)) { - entry_guard_t *guard = smartlist_choose(usable_primary_guards); + chosen_guard = smartlist_choose(usable_primary_guards); smartlist_free(usable_primary_guards); log_info(LD_GUARD, "Selected primary guard %s for circuit.", - entry_guard_describe(guard)); - return guard; + entry_guard_describe(chosen_guard)); } + smartlist_free(usable_primary_guards); + return chosen_guard; +} + +/** + * For use with a circuit, pick a non-pending running filtered confirmed guard, + * if one is available. Update the <b>last_tried_to_connect</b> time and the + * <b>is_pending</b> fields of the guard as appropriate. Set <b>state_out</b> + * to the new guard-state of the circuit. + */ +static entry_guard_t * +select_confirmed_guard_for_circuit(guard_selection_t *gs, + guard_usage_t usage, + const entry_guard_restriction_t *rst, + unsigned *state_out) +{ + const int need_descriptor = (usage == GUARD_USAGE_TRAFFIC); - /* "Otherwise, if the ordered intersection of {CONFIRMED_GUARDS} - and {USABLE_FILTERED_GUARDS} is nonempty, return the first - entry in that intersection that has {is_pending} set to - false." */ SMARTLIST_FOREACH_BEGIN(gs->confirmed_entry_guards, entry_guard_t *, guard) { if (guard->is_primary) continue; /* we already considered this one. */ @@ -2048,34 +2105,93 @@ select_entry_guard_for_circuit(guard_selection_t *gs, } } SMARTLIST_FOREACH_END(guard); + return NULL; +} + +/** + * For use with a circuit, pick a confirmed usable filtered guard + * at random. Update the <b>last_tried_to_connect</b> time and the + * <b>is_pending</b> fields of the guard as appropriate. Set <b>state_out</b> + * to the new guard-state of the circuit. + */ +static entry_guard_t * +select_filtered_guard_for_circuit(guard_selection_t *gs, + guard_usage_t usage, + const entry_guard_restriction_t *rst, + unsigned *state_out) +{ + const int need_descriptor = (usage == GUARD_USAGE_TRAFFIC); + entry_guard_t *chosen_guard = NULL; + unsigned flags = 0; + if (need_descriptor) + flags |= SAMPLE_EXCLUDE_NO_DESCRIPTOR; + chosen_guard = sample_reachable_filtered_entry_guards(gs, + rst, + SAMPLE_EXCLUDE_CONFIRMED | + SAMPLE_EXCLUDE_PRIMARY | + SAMPLE_EXCLUDE_PENDING | + flags); + if (!chosen_guard) { + return NULL; + } + + chosen_guard->is_pending = 1; + chosen_guard->last_tried_to_connect = approx_time(); + *state_out = GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD; + log_info(LD_GUARD, "No primary or confirmed guards available. Selected " + "random guard %s for circuit. Will try other guards before " + "using this circuit.", + entry_guard_describe(chosen_guard)); + return chosen_guard; +} + +/** + * Get a guard for use with a circuit. Prefer to pick a running primary + * guard; then a non-pending running filtered confirmed guard; then a + * non-pending runnable filtered guard. Update the + * <b>last_tried_to_connect</b> time and the <b>is_pending</b> fields of the + * guard as appropriate. Set <b>state_out</b> to the new guard-state + * of the circuit. + */ +STATIC entry_guard_t * +select_entry_guard_for_circuit(guard_selection_t *gs, + guard_usage_t usage, + const entry_guard_restriction_t *rst, + unsigned *state_out) +{ + entry_guard_t *chosen_guard = NULL; + tor_assert(gs); + tor_assert(state_out); + + if (!gs->primary_guards_up_to_date) + entry_guards_update_primary(gs); + + /* "If any entry in PRIMARY_GUARDS has {is_reachable} status of + <maybe> or <yes>, return the first such guard." */ + chosen_guard = select_primary_guard_for_circuit(gs, usage, rst, state_out); + if (chosen_guard) + return chosen_guard; + + /* "Otherwise, if the ordered intersection of {CONFIRMED_GUARDS} + and {USABLE_FILTERED_GUARDS} is nonempty, return the first + entry in that intersection that has {is_pending} set to + false." */ + chosen_guard = select_confirmed_guard_for_circuit(gs, usage, rst, state_out); + if (chosen_guard) + return chosen_guard; + /* "Otherwise, if there is no such entry, select a member at random from {USABLE_FILTERED_GUARDS}." */ - { - entry_guard_t *guard; - unsigned flags = 0; - if (need_descriptor) - flags |= SAMPLE_EXCLUDE_NO_DESCRIPTOR; - guard = sample_reachable_filtered_entry_guards(gs, - rst, - SAMPLE_EXCLUDE_CONFIRMED | - SAMPLE_EXCLUDE_PRIMARY | - SAMPLE_EXCLUDE_PENDING | - flags); - if (guard == NULL) { - log_info(LD_GUARD, "Absolutely no sampled guards were available. " - "Marking all guards for retry and starting from top again."); - mark_all_guards_maybe_reachable(gs); - return NULL; - } - guard->is_pending = 1; - guard->last_tried_to_connect = approx_time(); - *state_out = GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD; - log_info(LD_GUARD, "No primary or confirmed guards available. Selected " - "random guard %s for circuit. Will try other guards before " - "using this circuit.", - entry_guard_describe(guard)); - return guard; + chosen_guard = select_filtered_guard_for_circuit(gs, usage, rst, state_out); + + if (chosen_guard == NULL) { + log_info(LD_GUARD, "Absolutely no sampled guards were available. " + "Marking all guards for retry and starting from top again."); + mark_all_guards_maybe_reachable(gs); + return NULL; } + + return chosen_guard; } /** diff --git a/src/feature/control/control.c b/src/feature/control/control.c index 12f10926b7..f22df30e11 100644 --- a/src/feature/control/control.c +++ b/src/feature/control/control.c @@ -2011,6 +2011,8 @@ getinfo_helper_listeners(control_connection_t *control_conn, if (!strcmp(question, "net/listeners/or")) type = CONN_TYPE_OR_LISTENER; + else if (!strcmp(question, "net/listeners/extor")) + type = CONN_TYPE_EXT_OR_LISTENER; else if (!strcmp(question, "net/listeners/dir")) type = CONN_TYPE_DIR_LISTENER; else if (!strcmp(question, "net/listeners/socks")) @@ -2019,6 +2021,8 @@ getinfo_helper_listeners(control_connection_t *control_conn, type = CONN_TYPE_AP_TRANS_LISTENER; else if (!strcmp(question, "net/listeners/natd")) type = CONN_TYPE_AP_NATD_LISTENER; + else if (!strcmp(question, "net/listeners/httptunnel")) + type = CONN_TYPE_AP_HTTP_CONNECT_LISTENER; else if (!strcmp(question, "net/listeners/dns")) type = CONN_TYPE_AP_DNS_LISTENER; else if (!strcmp(question, "net/listeners/control")) diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index ce67c1bb9a..6477f34baf 100644 --- a/src/feature/dirauth/dirvote.c +++ b/src/feature/dirauth/dirvote.c @@ -15,6 +15,7 @@ #include "feature/nodelist/parsecommon.h" #include "core/or/policies.h" #include "core/or/protover.h" +#include "core/or/tor_version_st.h" #include "feature/stats/rephist.h" #include "feature/relay/router.h" #include "feature/relay/routerkeys.h" @@ -254,6 +255,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, /* XXXX Abstraction violation: should be pulling a field out of v3_ns.*/ char *flag_thresholds = dirserv_get_flag_thresholds_line(); char *params; + char *bw_headers_line = NULL; authority_cert_t *cert = v3_ns->cert; char *methods = make_consensus_method_list(MIN_SUPPORTED_CONSENSUS_METHOD, @@ -267,8 +269,32 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, params = smartlist_join_strings(v3_ns->net_params, " ", 0, NULL); else params = tor_strdup(""); - tor_assert(cert); + + /* v3_ns->bw_file_headers is only set when V3BandwidthsFile is + * configured */ + if (v3_ns->bw_file_headers) { + char *bw_file_headers = NULL; + /* If there are too many headers, leave the header string NULL */ + if (! BUG(smartlist_len(v3_ns->bw_file_headers) + > MAX_BW_FILE_HEADER_COUNT_IN_VOTE)) { + bw_file_headers = smartlist_join_strings(v3_ns->bw_file_headers, " ", + 0, NULL); + if (BUG(strlen(bw_file_headers) > MAX_BW_FILE_HEADERS_LINE_LEN)) { + /* Free and set to NULL, because the line was too long */ + tor_free(bw_file_headers); + } + } + if (!bw_file_headers) { + /* If parsing failed, add a bandwidth header line with no entries */ + bw_file_headers = tor_strdup(""); + } + /* At this point, the line will always be present */ + bw_headers_line = format_line_if_present("bandwidth-file-headers", + bw_file_headers); + tor_free(bw_file_headers); + } + smartlist_add_asprintf(chunks, "network-status-version 3\n" "vote-status %s\n" @@ -286,7 +312,9 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, "params %s\n" "dir-source %s %s %s %s %d %d\n" "contact %s\n" - "%s", /* shared randomness information */ + "%s" /* shared randomness information */ + "%s" /* bandwidth file headers */ + , v3_ns->type == NS_TYPE_VOTE ? "vote" : "opinion", methods, published, va, fu, vu, @@ -302,13 +330,16 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, fmt_addr32(addr), voter->dir_port, voter->or_port, voter->contact, shared_random_vote_str ? - shared_random_vote_str : ""); + shared_random_vote_str : "", + bw_headers_line ? + bw_headers_line : ""); tor_free(params); tor_free(flags); tor_free(flag_thresholds); tor_free(methods); tor_free(shared_random_vote_str); + tor_free(bw_headers_line); if (!tor_digest_is_zero(voter->legacy_id_digest)) { char fpbuf[HEX_DIGEST_LEN+1]; @@ -797,6 +828,14 @@ compute_consensus_versions_list(smartlist_t *lst, int n_versioning) int min = n_versioning / 2; smartlist_t *good = smartlist_new(); char *result; + SMARTLIST_FOREACH_BEGIN(lst, const char *, v) { + if (strchr(v, ' ')) { + log_warn(LD_DIR, "At least one authority has voted for a version %s " + "that contains a space. This probably wasn't intentional, and " + "is likely to cause trouble. Please tell them to stop it.", + escaped(v)); + } + } SMARTLIST_FOREACH_END(v); sort_version_list(lst, 0); get_frequent_members(good, lst, min); result = smartlist_join_strings(good, ",", 0, NULL); @@ -4200,8 +4239,8 @@ version_from_platform(const char *platform) * allocate and return a new string containing the version numbers, in order, * separated by commas. Used to generate Recommended(Client|Server)?Versions */ -static char * -format_versions_list(config_line_t *ln) +char * +format_recommended_version_list(const config_line_t *ln, int warn) { smartlist_t *versions; char *result; @@ -4210,6 +4249,37 @@ format_versions_list(config_line_t *ln) smartlist_split_string(versions, ln->value, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); } + + /* Handle the case where a dirauth operator has accidentally made some + * versions space-separated instead of comma-separated. */ + smartlist_t *more_versions = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(versions, char *, v) { + if (strchr(v, ' ')) { + if (warn) + log_warn(LD_DIRSERV, "Unexpected space in versions list member %s. " + "(These are supposed to be comma-separated; I'll pretend you " + "used commas instead.)", escaped(v)); + SMARTLIST_DEL_CURRENT(versions, v); + smartlist_split_string(more_versions, v, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + tor_free(v); + } + } SMARTLIST_FOREACH_END(v); + smartlist_add_all(versions, more_versions); + smartlist_free(more_versions); + + /* Check to make sure everything looks like a version. */ + if (warn) { + SMARTLIST_FOREACH_BEGIN(versions, const char *, v) { + tor_version_t ver; + if (tor_version_parse(v, &ver) < 0) { + log_warn(LD_DIRSERV, "Recommended version %s does not look valid. " + " (I'll include it anyway, since you told me to.)", + escaped(v)); + } + } SMARTLIST_FOREACH_END(v); + } + sort_version_list(versions, 1); result = smartlist_join_strings(versions,",",0,NULL); SMARTLIST_FOREACH(versions,char *,s,tor_free(s)); @@ -4303,6 +4373,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, digestmap_t *omit_as_sybil = NULL; const int vote_on_reachability = running_long_enough_to_decide_unreachable(); smartlist_t *microdescriptors = NULL; + smartlist_t *bw_file_headers = NULL; tor_assert(private_key); tor_assert(cert); @@ -4325,8 +4396,10 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, } if (options->VersioningAuthoritativeDir) { - client_versions = format_versions_list(options->RecommendedClientVersions); - server_versions = format_versions_list(options->RecommendedServerVersions); + client_versions = + format_recommended_version_list(options->RecommendedClientVersions, 0); + server_versions = + format_recommended_version_list(options->RecommendedServerVersions, 0); } contact = get_options()->ContactInfo; @@ -4338,7 +4411,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, * set_routerstatus_from_routerinfo() see up-to-date bandwidth info. */ if (options->V3BandwidthsFile) { - dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL); + dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL, NULL); } else { /* * No bandwidths file; clear the measured bandwidth cache in case we had @@ -4440,8 +4513,10 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, /* This pass through applies the measured bw lines to the routerstatuses */ if (options->V3BandwidthsFile) { + /* Only set bw_file_headers when V3BandwidthsFile is configured */ + bw_file_headers = smartlist_new(); dirserv_read_measured_bandwidths(options->V3BandwidthsFile, - routerstatuses); + routerstatuses, bw_file_headers); } else { /* * No bandwidths file; clear the measured bandwidth cache in case we had @@ -4537,6 +4612,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, options->ConsensusParams, NULL, 0, 0); smartlist_sort_strings(v3_out->net_params); } + v3_out->bw_file_headers = bw_file_headers; voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); voter->nickname = tor_strdup(options->Nickname); diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h index 7ce8e4a699..979a2be8a6 100644 --- a/src/feature/dirauth/dirvote.h +++ b/src/feature/dirauth/dirvote.h @@ -89,6 +89,9 @@ #define DGV_INCLUDE_PENDING 2 #define DGV_INCLUDE_PREVIOUS 4 +/** Maximum size of a line in a vote. */ +#define MAX_BW_FILE_HEADERS_LINE_LEN 1024 + /* * Public API. Used outside of the dirauth subsystem. * diff --git a/src/feature/dircache/dirserv.c b/src/feature/dircache/dirserv.c index 1500467ec0..b85db8324f 100644 --- a/src/feature/dircache/dirserv.c +++ b/src/feature/dircache/dirserv.c @@ -51,6 +51,7 @@ #include "lib/crypt_ops/crypto_format.h" #include "lib/encoding/confline.h" +#include "lib/encoding/keyval.h" /** * \file dirserv.c * \brief Directory server core implementation. Manages directory @@ -2599,12 +2600,14 @@ measured_bw_line_apply(measured_bw_line_t *parsed_line, } /** - * Read the measured bandwidth file and apply it to the list of - * vote_routerstatus_t. Returns -1 on error, 0 otherwise. + * Read the measured bandwidth list file, apply it to the list of + * vote_routerstatus_t and store all the headers in <b>bw_file_headers</b>. + * Returns -1 on error, 0 otherwise. */ int dirserv_read_measured_bandwidths(const char *from_file, - smartlist_t *routerstatuses) + smartlist_t *routerstatuses, + smartlist_t *bw_file_headers) { FILE *fp = tor_fopen_cloexec(from_file, "r"); int applied_lines = 0; @@ -2654,6 +2657,12 @@ dirserv_read_measured_bandwidths(const char *from_file, goto err; } + /* If timestamp was correct and bw_file_headers is not NULL, + * add timestamp to bw_file_headers */ + if (bw_file_headers) + smartlist_add_asprintf(bw_file_headers, "timestamp=%lu", + (unsigned long)file_time); + if (routerstatuses) smartlist_sort(routerstatuses, compare_vote_routerstatus_entries); @@ -2669,7 +2678,24 @@ dirserv_read_measured_bandwidths(const char *from_file, dirserv_cache_measured_bw(&parsed_line, file_time); if (measured_bw_line_apply(&parsed_line, routerstatuses) > 0) applied_lines++; - } + /* if the terminator is found, it is the end of header lines, set the + * flag but do not store anything */ + } else if (strcmp(line, BW_FILE_HEADERS_TERMINATOR) == 0) { + line_is_after_headers = 1; + /* if the line was not a correct relay line nor the terminator and + * the end of the header lines has not been detected yet + * and it is key_value and bw_file_headers did not reach the maximum + * number of headers, + * then assume this line is a header and add it to bw_file_headers */ + } else if (bw_file_headers && + (line_is_after_headers == 0) && + string_is_key_value(LOG_DEBUG, line) && + !strchr(line, ' ') && + (smartlist_len(bw_file_headers) + < MAX_BW_FILE_HEADER_COUNT_IN_VOTE)) { + line[strlen(line)-1] = '\0'; + smartlist_add_strdup(bw_file_headers, line); + }; } } diff --git a/src/feature/dircache/dirserv.h b/src/feature/dircache/dirserv.h index 3b4a646094..9be4bf9db2 100644 --- a/src/feature/dircache/dirserv.h +++ b/src/feature/dircache/dirserv.h @@ -49,6 +49,13 @@ typedef enum { /** Maximum allowable length of a version line in a networkstatus. */ #define MAX_V_LINE_LEN 128 +/** Maximum allowable length of bandwidth headers in a bandwidth file */ +#define MAX_BW_FILE_HEADER_COUNT_IN_VOTE 50 + +/** Terminatore that separates bandwidth file headers from bandwidth file + * relay lines */ +#define BW_FILE_HEADERS_TERMINATOR "=====\n" + /** Ways to convert a spoolable_resource_t to a bunch of bytes. */ typedef enum dir_spool_source_t { DIR_SPOOL_SERVER_BY_DIGEST=1, DIR_SPOOL_SERVER_BY_FP, @@ -180,7 +187,9 @@ char *routerstatus_format_entry( void dirserv_free_all(void); void cached_dir_decref(cached_dir_t *d); cached_dir_t *new_cached_dir(char *s, time_t published); - +struct config_line_t; +char *format_recommended_version_list(const struct config_line_t *line, + int warn); int validate_recommended_package_line(const char *line); int dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_out, @@ -215,7 +224,8 @@ dirserv_read_guardfraction_file_from_str(const char *guardfraction_file_str, #endif /* defined(DIRSERV_PRIVATE) */ int dirserv_read_measured_bandwidths(const char *from_file, - smartlist_t *routerstatuses); + smartlist_t *routerstatuses, + smartlist_t *bw_file_headers); int dirserv_read_guardfraction_file(const char *fname, smartlist_t *vote_routerstatuses); diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c index cd312e98be..541b165dd5 100644 --- a/src/feature/hs/hs_circuit.c +++ b/src/feature/hs/hs_circuit.c @@ -566,10 +566,14 @@ retry_service_rendezvous_point(const origin_circuit_t *circ) return; } -/* Add all possible link specifiers in node to lspecs. - * legacy ID is mandatory thus MUST be present in node. If the primary address - * is not IPv4, log a BUG() warning, and return an empty smartlist. - * Includes ed25519 id and IPv6 link specifiers if present in the node. */ +/* Add all possible link specifiers in node to lspecs: + * - legacy ID is mandatory thus MUST be present in node; + * - include ed25519 link specifier if present in the node, and the node + * supports ed25519 link authentication, even if its link versions are not + * compatible with us; + * - include IPv4 link specifier, if the primary address is not IPv4, log a + * BUG() warning, and return an empty smartlist; + * - include IPv6 link specifier if present in the node. */ static void get_lspecs_from_node(const node_t *node, smartlist_t *lspecs) { @@ -607,8 +611,12 @@ get_lspecs_from_node(const node_t *node, smartlist_t *lspecs) link_specifier_set_ls_len(ls, link_specifier_getlen_un_legacy_id(ls)); smartlist_add(lspecs, ls); - /* ed25519 ID is only included if the node has it. */ - if (!ed25519_public_key_is_zero(&node->ed25519_id)) { + /* ed25519 ID is only included if the node has it, and the node declares a + protocol version that supports ed25519 link authentication, even if that + link version is not compatible with us. (We are sending the ed25519 key + to another tor, which may support different link versions.) */ + if (!ed25519_public_key_is_zero(&node->ed25519_id) && + node_supports_ed25519_link_authentication(node, 0)) { ls = link_specifier_new(); link_specifier_set_ls_type(ls, LS_ED25519_ID); memcpy(link_specifier_getarray_un_ed25519_id(ls), &node->ed25519_id, diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c index 328430be08..12405a79cb 100644 --- a/src/feature/hs/hs_common.c +++ b/src/feature/hs/hs_common.c @@ -254,8 +254,8 @@ get_time_period_length(void) HS_TIME_PERIOD_LENGTH_MIN, HS_TIME_PERIOD_LENGTH_MAX); /* Make sure it's a positive value. */ - tor_assert(time_period_length >= 0); - /* uint64_t will always be able to contain a int32_t */ + tor_assert(time_period_length > 0); + /* uint64_t will always be able to contain a positive int32_t */ return (uint64_t) time_period_length; } @@ -844,7 +844,7 @@ hs_get_subcredential(const ed25519_public_key_t *identity_pk, memwipe(credential, 0, sizeof(credential)); } -/* From the given list of hidden service ports, find the ones that much the +/* From the given list of hidden service ports, find the ones that match the * given edge connection conn, pick one at random and use it to set the * connection address. Return 0 on success or -1 if none. */ int diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index 54204dd070..7775ac6de8 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -410,17 +410,21 @@ service_intro_point_free_void(void *obj) } /* Return a newly allocated service intro point and fully initialized from the - * given extend_info_t ei if non NULL. If is_legacy is true, we also generate - * the legacy key. On error, NULL is returned. + * given extend_info_t ei if non NULL. + * If is_legacy is true, we also generate the legacy key. + * If supports_ed25519_link_handshake_any is true, we add the relay's ed25519 + * key to the link specifiers. * * If ei is NULL, returns a hs_service_intro_point_t with an empty link * specifier list and no onion key. (This is used for testing.) + * On any other error, NULL is returned. * * ei must be an extend_info_t containing an IPv4 address. (We will add supoort * for IPv6 in a later release.) When calling extend_info_from_node(), pass * 0 in for_direct_connection to make sure ei always has an IPv4 address. */ STATIC hs_service_intro_point_t * -service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy) +service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy, + unsigned int supports_ed25519_link_handshake_any) { hs_desc_link_specifier_t *ls; hs_service_intro_point_t *ip; @@ -491,10 +495,13 @@ service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy) } smartlist_add(ip->base.link_specifiers, ls); - /* ed25519 identity key is optional for intro points */ - ls = hs_desc_link_specifier_new(ei, LS_ED25519_ID); - if (ls) { - smartlist_add(ip->base.link_specifiers, ls); + /* ed25519 identity key is optional for intro points. If the node supports + * ed25519 link authentication, we include it. */ + if (supports_ed25519_link_handshake_any) { + ls = hs_desc_link_specifier_new(ei, LS_ED25519_ID); + if (ls) { + smartlist_add(ip->base.link_specifiers, ls); + } } /* IPv6 is not supported in this release. */ @@ -1653,8 +1660,12 @@ pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes) tor_assert_nonfatal(!ed25519_public_key_is_zero(&info->ed_identity)); } - /* Create our objects and populate them with the node information. */ - ip = service_intro_point_new(info, !node_supports_ed25519_hs_intro(node)); + /* Create our objects and populate them with the node information. + * We don't care if the intro's link auth is compatible with us, because + * we are sending the ed25519 key to a remote client via the descriptor. */ + ip = service_intro_point_new(info, !node_supports_ed25519_hs_intro(node), + node_supports_ed25519_link_authentication(node, + 0)); if (ip == NULL) { goto err; } diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h index 4cd05e3897..5c5443a35f 100644 --- a/src/feature/hs/hs_service.h +++ b/src/feature/hs/hs_service.h @@ -315,8 +315,9 @@ STATIC void remove_service(hs_service_ht *map, hs_service_t *service); STATIC int register_service(hs_service_ht *map, hs_service_t *service); /* Service introduction point functions. */ STATIC hs_service_intro_point_t *service_intro_point_new( - const extend_info_t *ei, - unsigned int is_legacy); + const extend_info_t *ei, + unsigned int is_legacy, + unsigned int supports_ed25519_link_handshake_any); STATIC void service_intro_point_free_(hs_service_intro_point_t *ip); #define service_intro_point_free(ip) \ FREE_AND_NULL(hs_service_intro_point_t, \ diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index e9d36cbdcb..6492b828b1 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -385,6 +385,11 @@ networkstatus_vote_free_(networkstatus_t *ns) smartlist_free(ns->routerstatus_list); } + if (ns->bw_file_headers) { + SMARTLIST_FOREACH(ns->bw_file_headers, char *, c, tor_free(c)); + smartlist_free(ns->bw_file_headers); + } + digestmap_free(ns->desc_digest_map, NULL); if (ns->sr_info.commits) { @@ -2417,6 +2422,8 @@ get_net_param_from_list(smartlist_t *net_params, const char *param_name, res = max_val; } + tor_assert(res >= min_val); + tor_assert(res <= max_val); return res; } diff --git a/src/feature/nodelist/networkstatus_st.h b/src/feature/nodelist/networkstatus_st.h index 46b0f53c0b..2bb0e3ae35 100644 --- a/src/feature/nodelist/networkstatus_st.h +++ b/src/feature/nodelist/networkstatus_st.h @@ -96,6 +96,9 @@ struct networkstatus_t { /** Contains the shared random protocol data from a vote or consensus. */ networkstatus_sr_info_t sr_info; + + /** List of key=value strings from the headers of the bandwidth list file */ + smartlist_t *bw_file_headers; }; #endif diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index 973d3e1100..0cc4887232 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -2686,6 +2686,9 @@ log_addr_has_changed(int severity, char addrbuf_prev[TOR_ADDR_BUF_LEN]; char addrbuf_cur[TOR_ADDR_BUF_LEN]; + if (BUG(!server_mode(get_options()))) + return; + if (tor_addr_to_str(addrbuf_prev, prev, sizeof(addrbuf_prev), 1) == NULL) strlcpy(addrbuf_prev, "???", TOR_ADDR_BUF_LEN); if (tor_addr_to_str(addrbuf_cur, cur, sizeof(addrbuf_cur), 1) == NULL) diff --git a/src/lib/cc/torint.h b/src/lib/cc/torint.h index b97fc8d975..5097724726 100644 --- a/src/lib/cc/torint.h +++ b/src/lib/cc/torint.h @@ -100,6 +100,16 @@ typedef int32_t ssize_t; # define TOR_PRIuSZ "zu" #endif +#ifdef _WIN32 +# ifdef _WIN64 +# define TOR_PRIdSZ PRId64 +# else +# define TOR_PRIdSZ PRId32 +# endif +#else +# define TOR_PRIdSZ "zd" +#endif + #ifndef SSIZE_MAX #if (SIZEOF_SIZE_T == 4) #define SSIZE_MAX INT32_MAX diff --git a/src/lib/compress/compress_zstd.c b/src/lib/compress/compress_zstd.c index 0a71fed4b8..fe88d4a544 100644 --- a/src/lib/compress/compress_zstd.c +++ b/src/lib/compress/compress_zstd.c @@ -28,10 +28,14 @@ #endif #ifdef HAVE_ZSTD +#ifdef HAVE_CFLAG_WUNUSED_CONST_VARIABLE DISABLE_GCC_WARNING(unused-const-variable) +#endif #include <zstd.h> +#ifdef HAVE_CFLAG_WUNUSED_CONST_VARIABLE ENABLE_GCC_WARNING(unused-const-variable) #endif +#endif /** Total number of bytes allocated for Zstandard state. */ static atomic_counter_t total_zstd_allocation; diff --git a/src/lib/container/smartlist.c b/src/lib/container/smartlist.c index dc283e5f50..4b29d834d9 100644 --- a/src/lib/container/smartlist.c +++ b/src/lib/container/smartlist.c @@ -189,6 +189,33 @@ smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2) return 1; } +/** + * Return true if there is shallow equality between smartlists - + * i.e. all indices correspond to exactly same object (pointer + * values are matching). Otherwise, return false. + */ +int +smartlist_ptrs_eq(const smartlist_t *s1, const smartlist_t *s2) +{ + if (s1 == s2) + return 1; + + // Note: pointers cannot both be NULL at this point, because + // above check. + if (s1 == NULL || s2 == NULL) + return 0; + + if (smartlist_len(s1) != smartlist_len(s2)) + return 0; + + for (int i = 0; i < smartlist_len(s1); i++) { + if (smartlist_get(s1, i) != smartlist_get(s2, i)) + return 0; + } + + return 1; +} + /** Return true iff <b>sl</b> has some element E such that * tor_memeq(E,<b>element</b>,DIGEST_LEN) */ diff --git a/src/lib/container/smartlist.h b/src/lib/container/smartlist.h index 3b19cbfce4..9705396ac9 100644 --- a/src/lib/container/smartlist.h +++ b/src/lib/container/smartlist.h @@ -37,6 +37,9 @@ 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); +int smartlist_ptrs_eq(const smartlist_t *s1, + const smartlist_t *s2); + void smartlist_sort(smartlist_t *sl, int (*compare)(const void **a, const void **b)); void *smartlist_get_most_frequent_(const smartlist_t *sl, diff --git a/src/lib/crypt_ops/crypto_hkdf.c b/src/lib/crypt_ops/crypto_hkdf.c index 0200d0fe9c..1873632a9d 100644 --- a/src/lib/crypt_ops/crypto_hkdf.c +++ b/src/lib/crypt_ops/crypto_hkdf.c @@ -19,9 +19,9 @@ #include <openssl/opensslv.h> -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) -#define HAVE_OPENSSL_HKDF 1 +#if defined(HAVE_ERR_LOAD_KDF_STRINGS) #include <openssl/kdf.h> +#define HAVE_OPENSSL_HKDF 1 #endif #include <string.h> diff --git a/src/lib/log/util_bug.c b/src/lib/log/util_bug.c index 42b3670a71..b23f4edc97 100644 --- a/src/lib/log/util_bug.c +++ b/src/lib/log/util_bug.c @@ -20,10 +20,6 @@ #include <string.h> -#ifdef __COVERITY__ -int bug_macro_deadcode_dummy__ = 0; -#endif - #ifdef TOR_UNIT_TESTS static void (*failed_assertion_cb)(void) = NULL; static int n_bugs_to_capture = 0; diff --git a/src/lib/log/util_bug.h b/src/lib/log/util_bug.h index 61ee60f729..44a4f8381c 100644 --- a/src/lib/log/util_bug.h +++ b/src/lib/log/util_bug.h @@ -86,13 +86,10 @@ */ #ifdef __COVERITY__ -extern int bug_macro_deadcode_dummy__; #undef BUG // Coverity defines this in global headers; let's override it. This is a // magic coverity-only preprocessor thing. -// We use this "deadcode_dummy__" trick to prevent coverity from -// complaining about unreachable bug cases. -#nodef BUG(x) ((x)?(__coverity_panic__(),1):(0+bug_macro_deadcode_dummy__)) +#nodef BUG(x) (x) #endif /* defined(__COVERITY__) */ #if defined(__COVERITY__) || defined(__clang_analyzer__) diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index c3e44d2a79..4bbadbe535 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -14,3 +14,12 @@ members = [ debug = true panic = "abort" +[features] +default = [] +# If this feature is enabled, test code which calls Tor C code from Rust will +# execute with `cargo test`. Due to numerous linker issues (#25386), this is +# currently disabled by default. Crates listed here are those which, in their +# unittests, doctests, and/or integration tests, call C code. +test-c-from-rust = [ + "crypto/test-c-from-rust", +] diff --git a/src/rust/build.rs b/src/rust/build.rs index 2cf85b404a..2ac24b334b 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -149,14 +149,16 @@ pub fn main() { // tor uses. We must be careful with factoring and dependencies // moving forward! cfg.component("tor-crypt-ops-testing"); - cfg.component("tor-sandbox"); + cfg.component("tor-sandbox-testing"); cfg.component("tor-encoding-testing"); - cfg.component("tor-net"); + cfg.component("tor-fs-testing"); + cfg.component("tor-time-testing"); + cfg.component("tor-net-testing"); 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-log-testing"); + cfg.component("tor-lock-testing"); + cfg.component("tor-fdio-testing"); cfg.component("tor-container-testing"); cfg.component("tor-smartlist-core-testing"); cfg.component("tor-string-testing"); diff --git a/src/rust/crypto/Cargo.toml b/src/rust/crypto/Cargo.toml index 869e0d6256..d68ac48e28 100644 --- a/src/rust/crypto/Cargo.toml +++ b/src/rust/crypto/Cargo.toml @@ -26,3 +26,7 @@ rand = { version = "=0.5.0-pre.2", default-features = false } rand_core = { version = "=0.2.0-pre.0", default-features = false } [features] +# If this feature is enabled, test code which calls Tor C code from Rust will +# execute with `cargo test`. Due to numerous linker issues (#25386), this is +# currently disabled by default. +test-c-from-rust = [] diff --git a/src/rust/crypto/digests/sha2.rs b/src/rust/crypto/digests/sha2.rs index 03e0843dc0..d0246eeb94 100644 --- a/src/rust/crypto/digests/sha2.rs +++ b/src/rust/crypto/digests/sha2.rs @@ -165,15 +165,19 @@ impl FixedOutput for Sha512 { #[cfg(test)] mod test { + #[cfg(feature = "test-c-from-rust")] use digest::Digest; + #[cfg(feature = "test-c-from-rust")] use super::*; + #[cfg(feature = "test-c-from-rust")] #[test] fn sha256_default() { let _: Sha256 = Sha256::default(); } + #[cfg(feature = "test-c-from-rust")] #[test] fn sha256_digest() { let mut h: Sha256 = Sha256::new(); @@ -193,11 +197,13 @@ mod test { assert_eq!(result, expected); } + #[cfg(feature = "test-c-from-rust")] #[test] fn sha512_default() { let _: Sha512 = Sha512::default(); } + #[cfg(feature = "test-c-from-rust")] #[test] fn sha512_digest() { let mut h: Sha512 = Sha512::new(); diff --git a/src/test/test_bt.sh b/src/test/test_bt.sh index 312905a4e2..df8bcb8eda 100755 --- a/src/test/test_bt.sh +++ b/src/test/test_bt.sh @@ -3,6 +3,8 @@ exitcode=0 +ulimit -c 0 + export ASAN_OPTIONS="handle_segv=0:allow_user_segv_handler=1" "${builddir:-.}/src/test/test-bt-cl" backtraces || exit $? "${builddir:-.}/src/test/test-bt-cl" assert 2>&1 | "${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/bt_test.py" || exitcode="$?" diff --git a/src/test/test_config.c b/src/test/test_config.c index f5c759402c..907e3a1fb4 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -5600,6 +5600,12 @@ test_config_include_opened_file_list(void *data) config_line_t *result = NULL; smartlist_t *opened_files = smartlist_new(); + char *torrcd = NULL; + char *subfolder = NULL; + char *path = NULL; + char *empty = NULL; + char *file = NULL; + char *dot = NULL; char *dir = tor_strdup(get_fname("test_include_opened_file_list")); tt_ptr_op(dir, OP_NE, NULL); @@ -5609,8 +5615,7 @@ test_config_include_opened_file_list(void *data) tt_int_op(mkdir(dir, 0700), OP_EQ, 0); #endif - char torrcd[PATH_MAX+1]; - tor_snprintf(torrcd, sizeof(torrcd), "%s"PATH_SEPARATOR"%s", dir, "torrc.d"); + tor_asprintf(&torrcd, "%s"PATH_SEPARATOR"%s", dir, "torrc.d"); #ifdef _WIN32 tt_int_op(mkdir(torrcd), OP_EQ, 0); @@ -5618,9 +5623,7 @@ test_config_include_opened_file_list(void *data) tt_int_op(mkdir(torrcd, 0700), OP_EQ, 0); #endif - char subfolder[PATH_MAX+1]; - tor_snprintf(subfolder, sizeof(subfolder), "%s"PATH_SEPARATOR"%s", torrcd, - "subfolder"); + tor_asprintf(&subfolder, "%s"PATH_SEPARATOR"%s", torrcd, "subfolder"); #ifdef _WIN32 tt_int_op(mkdir(subfolder), OP_EQ, 0); @@ -5628,21 +5631,17 @@ test_config_include_opened_file_list(void *data) tt_int_op(mkdir(subfolder, 0700), OP_EQ, 0); #endif - char path[PATH_MAX+1]; - tor_snprintf(path, sizeof(path), "%s"PATH_SEPARATOR"%s", subfolder, + tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", subfolder, "01_file_in_subfolder"); tt_int_op(write_str_to_file(path, "Test 1\n", 0), OP_EQ, 0); - char empty[PATH_MAX+1]; - tor_snprintf(empty, sizeof(empty), "%s"PATH_SEPARATOR"%s", torrcd, "empty"); + tor_asprintf(&empty, "%s"PATH_SEPARATOR"%s", torrcd, "empty"); tt_int_op(write_str_to_file(empty, "", 0), OP_EQ, 0); - char file[PATH_MAX+1]; - tor_snprintf(file, sizeof(file), "%s"PATH_SEPARATOR"%s", torrcd, "file"); + tor_asprintf(&file, "%s"PATH_SEPARATOR"%s", torrcd, "file"); tt_int_op(write_str_to_file(file, "Test 2\n", 0), OP_EQ, 0); - char dot[PATH_MAX+1]; - tor_snprintf(dot, sizeof(dot), "%s"PATH_SEPARATOR"%s", torrcd, ".dot"); + tor_asprintf(&dot, "%s"PATH_SEPARATOR"%s", torrcd, ".dot"); tt_int_op(write_str_to_file(dot, "Test 3\n", 0), OP_EQ, 0); char torrc_contents[1000]; @@ -5669,6 +5668,12 @@ test_config_include_opened_file_list(void *data) SMARTLIST_FOREACH(opened_files, char *, f, tor_free(f)); smartlist_free(opened_files); config_free_lines(result); + tor_free(torrcd); + tor_free(subfolder); + tor_free(path); + tor_free(empty); + tor_free(file); + tor_free(dot); tor_free(dir); } diff --git a/src/test/test_dir.c b/src/test/test_dir.c index bda56b3a8e..c2f3f5297d 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -23,6 +23,7 @@ #include "app/config/confparse.h" #include "app/config/config.h" #include "feature/control/control.h" +#include "lib/encoding/confline.h" #include "lib/crypt_ops/crypto_ed25519.h" #include "lib/crypt_ops/crypto_format.h" #include "lib/crypt_ops/crypto_rand.h" @@ -1591,25 +1592,6 @@ test_dir_measured_bw_kb(void *arg) return; } -/* Test dirserv_read_measured_bandwidths */ -static void -test_dir_dirserv_read_measured_bandwidths_empty(void *arg) -{ - char *fname=NULL; - (void)arg; - - fname = tor_strdup(get_fname("V3BandwidthsFile")); - /* Test an empty file */ - write_str_to_file(fname, "", 0); - setup_capture_of_logs(LOG_WARN); - tt_int_op(-1, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL)); - expect_log_msg("Empty bandwidth file\n"); - - done: - tor_free(fname); - teardown_capture_of_logs(); -} - /* Unit tests for measured_bw_line_parse using line_is_after_headers flag. * When the end of the header is detected (a first complete bw line is parsed), * incomplete lines fail and give warnings, but do not give warnings if @@ -1653,7 +1635,7 @@ test_dir_measured_bw_kb_line_is_after_headers(void *arg) teardown_capture_of_logs(); } -/* Test dirserv_read_measured_bandwidths with whole files. */ +/* Test dirserv_read_measured_bandwidths with headers and complete files. */ static void test_dir_dirserv_read_measured_bandwidths(void *arg) { @@ -1661,76 +1643,321 @@ test_dir_dirserv_read_measured_bandwidths(void *arg) char *content = NULL; time_t timestamp = time(NULL); char *fname = tor_strdup(get_fname("V3BandwidthsFile")); - - /* Test Torflow file only with timestamp*/ - tor_asprintf(&content, "%ld", (long)timestamp); - write_str_to_file(fname, content, 0); - tor_free(content); - tt_int_op(-1, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL)); - - /* Test Torflow file with timestamp followed by '\n' */ - tor_asprintf(&content, "%ld\n", (long)timestamp); - write_str_to_file(fname, content, 0); - tor_free(content); - tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL)); - - /* Test Torflow complete file*/ - const char *torflow_relay_lines= + smartlist_t *bw_file_headers = smartlist_new(); + /* bw file strings in vote */ + char *bw_file_headers_str = NULL; + char *bw_file_headers_str_v100 = NULL; + char *bw_file_headers_str_v110 = NULL; + char *bw_file_headers_str_bad = NULL; + char *bw_file_headers_str_extra = NULL; + char bw_file_headers_str_long[MAX_BW_FILE_HEADER_COUNT_IN_VOTE * 8 + 1] = ""; + /* string header lines in bw file */ + char *header_lines_v100 = NULL; + char *header_lines_v110_no_terminator = NULL; + char *header_lines_v110 = NULL; + char header_lines_long[MAX_BW_FILE_HEADER_COUNT_IN_VOTE * 8 + 1] = ""; + int i; + const char *header_lines_v110_no_terminator_no_timestamp = + "version=1.1.0\n" + "software=sbws\n" + "software_version=0.1.0\n" + "earliest_bandwidth=2018-05-08T16:13:26\n" + "file_created=2018-04-16T21:49:18\n" + "generator_started=2018-05-08T16:13:25\n" + "latest_bandwidth=2018-04-16T20:49:18\n"; + const char *bw_file_headers_str_v110_no_timestamp = + "version=1.1.0 software=sbws " + "software_version=0.1.0 " + "earliest_bandwidth=2018-05-08T16:13:26 " + "file_created=2018-04-16T21:49:18 " + "generator_started=2018-05-08T16:13:25 " + "latest_bandwidth=2018-04-16T20:49:18"; + const char *relay_lines_v100 = "node_id=$557365204145532d32353620696e73746561642e bw=1024 " "nick=Test measured_at=1523911725 updated_at=1523911725 " "pid_error=4.11374090719 pid_error_sum=4.11374090719 " "pid_bw=57136645 pid_delta=2.12168374577 circ_fail=0.2 " "scanner=/filepath\n"; - - tor_asprintf(&content, "%ld\n%s", (long)timestamp, torflow_relay_lines); + const char *relay_lines_v110 = + "node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A27F80 " + "master_key_ed25519=YaqV4vbvPYKucElk297eVdNArDz9HtIwUoIeo0+cVIpQ " + "bw=760 nick=Test rtt=380 time=2018-05-08T16:13:26\n"; + const char *relay_lines_bad = + "node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A\n"; + + tor_asprintf(&header_lines_v100, "%ld\n", (long)timestamp); + tor_asprintf(&header_lines_v110_no_terminator, "%ld\n%s", (long)timestamp, + header_lines_v110_no_terminator_no_timestamp); + tor_asprintf(&header_lines_v110, "%s%s", + header_lines_v110_no_terminator, BW_FILE_HEADERS_TERMINATOR); + + tor_asprintf(&bw_file_headers_str_v100, "timestamp=%ld",(long)timestamp); + tor_asprintf(&bw_file_headers_str_v110, "timestamp=%ld %s", + (long)timestamp, bw_file_headers_str_v110_no_timestamp); + tor_asprintf(&bw_file_headers_str_bad, "%s " + "node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A", + bw_file_headers_str_v110); + + for (i=0; i<MAX_BW_FILE_HEADER_COUNT_IN_VOTE; i++) { + strlcat(header_lines_long, "foo=bar\n", + sizeof(header_lines_long)); + } + /* 8 is the number of v110 lines in header_lines_v110 */ + for (i=0; i<MAX_BW_FILE_HEADER_COUNT_IN_VOTE - 8 - 1; i++) { + strlcat(bw_file_headers_str_long, "foo=bar ", + sizeof(bw_file_headers_str_long)); + } + strlcat(bw_file_headers_str_long, "foo=bar", + sizeof(bw_file_headers_str_long)); + tor_asprintf(&bw_file_headers_str_extra, + "%s %s", + bw_file_headers_str_v110, + bw_file_headers_str_long); + + /* Test an empty bandwidth file. bw_file_headers will be empty string */ + write_str_to_file(fname, "", 0); + setup_capture_of_logs(LOG_WARN); + tt_int_op(-1, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + expect_log_msg("Empty bandwidth file\n"); + teardown_capture_of_logs(); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op("", OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test bandwidth file with only timestamp. + * bw_file_headers will be empty string */ + bw_file_headers = smartlist_new(); + tor_asprintf(&content, "%ld", (long)timestamp); write_str_to_file(fname, content, 0); tor_free(content); - tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL)); - - /* Test Torflow complete file including v1.1.0 headers */ - const char *v110_header_lines= - "version=1.1.0\n" - "software=sbws\n" - "software_version=0.1.0\n" - "generator_started=2018-05-08T16:13:25\n" - "earliest_bandwidth=2018-05-08T16:13:26\n" - "====\n"; - - tor_asprintf(&content, "%ld\n%s%s", (long)timestamp, v110_header_lines, - torflow_relay_lines); + tt_int_op(-1, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op("", OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test v1.0.0 bandwidth file headers */ + write_str_to_file(fname, header_lines_v100, 0); + bw_file_headers = smartlist_new(); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op(bw_file_headers_str_v100, OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test v1.0.0 complete bandwidth file */ + bw_file_headers = smartlist_new(); + tor_asprintf(&content, "%s%s", header_lines_v100, relay_lines_v100); write_str_to_file(fname, content, 0); tor_free(content); - tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL)); - - /* Test Torflow with additional headers afer a correct bw line */ - tor_asprintf(&content, "%ld\n%s%s", (long)timestamp, torflow_relay_lines, - v110_header_lines); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op(bw_file_headers_str_v100, OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test v1.0.0 complete bandwidth file with NULL bw_file_headers. */ + tor_asprintf(&content, "%s%s", header_lines_v100, relay_lines_v100); write_str_to_file(fname, content, 0); tor_free(content); - tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL)); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, NULL)); - /* Test Torflow with additional headers afer a correct bw line and more - * bw lines after the headers. */ - tor_asprintf(&content, "%ld\n%s%s%s", (long)timestamp, torflow_relay_lines, - v110_header_lines, torflow_relay_lines); + /* Test bandwidth file including v1.1.0 bandwidth headers and + * v1.0.0 relay lines. bw_file_headers will contain the v1.1.0 headers. */ + bw_file_headers = smartlist_new(); + tor_asprintf(&content, "%s%s%s", header_lines_v100, header_lines_v110, + relay_lines_v100); write_str_to_file(fname, content, 0); tor_free(content); - tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL)); - - /* Test sbws file */ - const char *sbws_relay_lines= - "node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A27F80 " - "master_key_ed25519=YaqV4vbvPYKucElk297eVdNArDz9HtIwUoIeo0+cVIpQ " - "bw=760 nick=Test rtt=380 time=2018-05-08T16:13:26\n"; - - tor_asprintf(&content, "%ld\n%s%s", (long)timestamp, v110_header_lines, - sbws_relay_lines); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op(bw_file_headers_str_v110, OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test v1.0.0 complete bandwidth file with v1.1.0 headers at the end. + * bw_file_headers will contain only v1.0.0 headers and the additional + * headers will be interpreted as malformed relay lines. */ + bw_file_headers = smartlist_new(); + tor_asprintf(&content, "%s%s%s", header_lines_v100, relay_lines_v100, + header_lines_v110); + write_str_to_file(fname, content, 0); + tor_free(content); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op(bw_file_headers_str_v100, OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test v1.0.0 complete bandwidth file, the v1.1.0 headers and more relay + * lines. bw_file_headers will contain only v1.0.0 headers, the additional + * headers will be interpreted as malformed relay lines and the last relay + * lines will be correctly interpreted as relay lines. */ + bw_file_headers = smartlist_new(); + tor_asprintf(&content, "%s%s%s%s", header_lines_v100, relay_lines_v100, + header_lines_v110, relay_lines_v100); + write_str_to_file(fname, content, 0); + tor_free(content); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op(bw_file_headers_str_v100, OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test v1.1.0 bandwidth headers without terminator */ + bw_file_headers = smartlist_new(); + write_str_to_file(fname, header_lines_v110_no_terminator, 0); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op(bw_file_headers_str_v110, OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test v1.1.0 bandwidth headers with terminator */ + bw_file_headers = smartlist_new(); + write_str_to_file(fname, header_lines_v110, 0); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op(bw_file_headers_str_v110, OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test v1.1.0 bandwidth file without terminator, then relay lines. + * bw_file_headers will contain the v1.1.0 headers. */ + bw_file_headers = smartlist_new(); + tor_asprintf(&content, "%s%s", + header_lines_v110_no_terminator, relay_lines_v110); + write_str_to_file(fname, content, 0); + tor_free(content); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op(bw_file_headers_str_v110, OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test v1.1.0 bandwidth headers with terminator, then relay lines + * bw_file_headers will contain the v1.1.0 headers. */ + bw_file_headers = smartlist_new(); + tor_asprintf(&content, "%s%s", + header_lines_v110, relay_lines_v110); + write_str_to_file(fname, content, 0); + tor_free(content); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op(bw_file_headers_str_v110, OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test v1.1.0 bandwidth headers with terminator, then bad relay lines, + * then terminator, then relay_lines_bad. + * bw_file_headers will contain the v1.1.0 headers. */ + bw_file_headers = smartlist_new(); + tor_asprintf(&content, "%s%s%s%s", header_lines_v110, relay_lines_bad, + BW_FILE_HEADERS_TERMINATOR, relay_lines_bad); write_str_to_file(fname, content, 0); tor_free(content); - tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL)); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op(bw_file_headers_str_v110, OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test v1.1.0 bandwidth headers without terminator, then bad relay lines, + * then relay lines. bw_file_headers will contain the v1.1.0 headers and + * the bad relay lines. */ + bw_file_headers = smartlist_new(); + tor_asprintf(&content, "%s%s%s", + header_lines_v110_no_terminator, relay_lines_bad, + relay_lines_v110); + write_str_to_file(fname, content, 0); + tor_free(content); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op(bw_file_headers_str_bad, OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test v1.1.0 bandwidth headers without terminator, + * then many bad relay lines, then relay lines. + * bw_file_headers will contain the v1.1.0 headers and the bad relay lines + * to a maximum of MAX_BW_FILE_HEADER_COUNT_IN_VOTE header lines. */ + bw_file_headers = smartlist_new(); + tor_asprintf(&content, "%s%s%s", + header_lines_v110_no_terminator, header_lines_long, + relay_lines_v110); + write_str_to_file(fname, content, 0); + tor_free(content); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + tt_int_op(MAX_BW_FILE_HEADER_COUNT_IN_VOTE, OP_EQ, + smartlist_len(bw_file_headers)); + bw_file_headers_str = smartlist_join_strings(bw_file_headers, " ", 0, NULL); + tt_str_op(bw_file_headers_str_extra, OP_EQ, bw_file_headers_str); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); + + /* Test v1.1.0 bandwidth headers without terminator, + * then many bad relay lines, then relay lines. + * bw_file_headers will contain the v1.1.0 headers and the bad relay lines. + * Force bw_file_headers to have more than MAX_BW_FILE_HEADER_COUNT_IN_VOTE + * This test is needed while there is not dirvote test. */ + bw_file_headers = smartlist_new(); + tor_asprintf(&content, "%s%s%s", + header_lines_v110_no_terminator, header_lines_long, + relay_lines_v110); + write_str_to_file(fname, content, 0); + tor_free(content); + tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, + bw_file_headers)); + tt_int_op(MAX_BW_FILE_HEADER_COUNT_IN_VOTE, OP_EQ, + smartlist_len(bw_file_headers)); + /* force bw_file_headers to be bigger than + * MAX_BW_FILE_HEADER_COUNT_IN_VOTE */ + char line[8] = "foo=bar\0"; + smartlist_add_strdup(bw_file_headers, line); + tt_int_op(MAX_BW_FILE_HEADER_COUNT_IN_VOTE, OP_LT, + smartlist_len(bw_file_headers)); + SMARTLIST_FOREACH(bw_file_headers, char *, c, tor_free(c)); + smartlist_free(bw_file_headers); + tor_free(bw_file_headers_str); done: tor_free(fname); + tor_free(header_lines_v100); + tor_free(header_lines_v110_no_terminator); + tor_free(header_lines_v110); + tor_free(bw_file_headers_str_v100); + tor_free(bw_file_headers_str_v110); + tor_free(bw_file_headers_str_bad); + tor_free(bw_file_headers_str_extra); } #define MBWC_INIT_TIME 1000 @@ -5979,6 +6206,57 @@ test_dir_networkstatus_consensus_has_ipv6(void *arg) UNMOCK(networkstatus_get_latest_consensus_by_flavor); } +static void +test_dir_format_versions_list(void *arg) +{ + (void)arg; + char *s = NULL; + config_line_t *lines = NULL; + + setup_capture_of_logs(LOG_WARN); + s = format_recommended_version_list(lines, 1); + tt_str_op(s, OP_EQ, ""); + + tor_free(s); + config_line_append(&lines, "ignored", "0.3.4.1, 0.2.9.111-alpha, 4.4.4-rc"); + s = format_recommended_version_list(lines, 1); + tt_str_op(s, OP_EQ, "0.2.9.111-alpha,0.3.4.1,4.4.4-rc"); + + tor_free(s); + config_line_append(&lines, "ignored", "0.1.2.3,0.2.9.10 "); + s = format_recommended_version_list(lines, 1); + tt_str_op(s, OP_EQ, "0.1.2.3,0.2.9.10,0.2.9.111-alpha,0.3.4.1,4.4.4-rc"); + + /* There should be no warnings so far. */ + expect_no_log_entry(); + + /* Now try a line with a space in it. */ + tor_free(s); + config_line_append(&lines, "ignored", "1.3.3.8 1.3.3.7"); + s = format_recommended_version_list(lines, 1); + tt_str_op(s, OP_EQ, "0.1.2.3,0.2.9.10,0.2.9.111-alpha,0.3.4.1," + "1.3.3.7,1.3.3.8,4.4.4-rc"); + + expect_single_log_msg_containing( + "Unexpected space in versions list member \"1.3.3.8 1.3.3.7\"." ); + + /* Start over, with a line containing a bogus version */ + config_free_lines(lines); + lines = NULL; + tor_free(s); + mock_clean_saved_logs(); + config_line_append(&lines, "ignored", "0.1.2.3, alpha-complex, 0.1.1.8-rc"); + s = format_recommended_version_list(lines,1); + tt_str_op(s, OP_EQ, "0.1.1.8-rc,0.1.2.3,alpha-complex"); + expect_single_log_msg_containing( + "Recommended version \"alpha-complex\" does not look valid."); + + done: + tor_free(s); + config_free_lines(lines); + teardown_capture_of_logs(); +} + #define DIR_LEGACY(name) \ { #name, test_dir_ ## name , TT_FORK, NULL, NULL } @@ -6001,7 +6279,6 @@ struct testcase_t dir_tests[] = { DIR_LEGACY(versions), DIR_LEGACY(fp_pairs), DIR(split_fps, 0), - DIR_LEGACY(dirserv_read_measured_bandwidths_empty), DIR_LEGACY(measured_bw_kb), DIR_LEGACY(measured_bw_kb_line_is_after_headers), DIR_LEGACY(measured_bw_kb_cache), @@ -6049,5 +6326,6 @@ struct testcase_t dir_tests[] = { DIR(networkstatus_compute_bw_weights_v10, 0), DIR(platform_str, 0), DIR(networkstatus_consensus_has_ipv6, TT_FORK), + DIR(format_versions_list, TT_FORK), END_OF_TESTCASES }; diff --git a/src/test/test_hs_cell.c b/src/test/test_hs_cell.c index b47929e8eb..5b48dd3785 100644 --- a/src/test/test_hs_cell.c +++ b/src/test/test_hs_cell.c @@ -39,7 +39,7 @@ test_gen_establish_intro_cell(void *arg) attempt to parse it. */ { /* We only need the auth key pair here. */ - hs_service_intro_point_t *ip = service_intro_point_new(NULL, 0); + hs_service_intro_point_t *ip = service_intro_point_new(NULL, 0, 0); /* Auth key pair is generated in the constructor so we are all set for * using this IP object. */ ret = hs_cell_build_establish_intro(circ_nonce, ip, buf); @@ -107,7 +107,7 @@ test_gen_establish_intro_cell_bad(void *arg) ed25519_sign_prefixed() function and make it fail. */ cell = trn_cell_establish_intro_new(); tt_assert(cell); - ip = service_intro_point_new(NULL, 0); + ip = service_intro_point_new(NULL, 0, 0); cell_len = hs_cell_build_establish_intro(circ_nonce, ip, NULL); service_intro_point_free(ip); expect_log_msg_containing("Unable to make signature for " diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c index 7da376471b..628d99bfde 100644 --- a/src/test/test_hs_intropoint.c +++ b/src/test/test_hs_intropoint.c @@ -50,7 +50,7 @@ new_establish_intro_cell(const char *circ_nonce, /* Auth key pair is generated in the constructor so we are all set for * using this IP object. */ - ip = service_intro_point_new(NULL, 0); + ip = service_intro_point_new(NULL, 0, 0); tt_assert(ip); cell_len = hs_cell_build_establish_intro(circ_nonce, ip, buf); tt_i64_op(cell_len, OP_GT, 0); @@ -76,7 +76,7 @@ new_establish_intro_encoded_cell(const char *circ_nonce, uint8_t *cell_out) /* Auth key pair is generated in the constructor so we are all set for * using this IP object. */ - ip = service_intro_point_new(NULL, 0); + ip = service_intro_point_new(NULL, 0, 0); tt_assert(ip); cell_len = hs_cell_build_establish_intro(circ_nonce, ip, cell_out); tt_i64_op(cell_len, OP_GT, 0); diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c index ee6cbc2ac1..ad0b3ab342 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -250,7 +250,7 @@ static hs_service_intro_point_t * helper_create_service_ip(void) { hs_desc_link_specifier_t *ls; - hs_service_intro_point_t *ip = service_intro_point_new(NULL, 0); + hs_service_intro_point_t *ip = service_intro_point_new(NULL, 0, 0); tor_assert(ip); /* Add a first unused link specifier. */ ls = tor_malloc_zero(sizeof(*ls)); diff --git a/src/test/test_key_expiration.sh b/src/test/test_key_expiration.sh index 5511dbf18c..cf6608634d 100755 --- a/src/test/test_key_expiration.sh +++ b/src/test/test_key_expiration.sh @@ -13,6 +13,14 @@ if [ $# -eq 0 ] || [ ! -f ${1} ] || [ ! -x ${1} ]; then fi fi +UNAME_OS=`uname -s | cut -d_ -f1` +if test "$UNAME_OS" = 'CYGWIN' || \ + test "$UNAME_OS" = 'MSYS' || \ + test "$UNAME_OS" = 'MINGW'; then + echo "This test is unreliable on Windows. See trac #26076. Skipping." >&2 + exit 77 +fi + if [ $# -ge 1 ]; then TOR_BINARY="${1}" shift diff --git a/src/tools/Makefile.nmake b/src/tools/Makefile.nmake index fda1990e0b..e223d9b135 100644 --- a/src/tools/Makefile.nmake +++ b/src/tools/Makefile.nmake @@ -1,4 +1,4 @@ -all: tor-resolve.exe tor-gencert.exe +all: tor-resolve.exe tor-gencert.exe tor-print-ed-signing-cert.exe CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common /I ..\or @@ -15,5 +15,8 @@ tor-gencert.exe: tor-gencert.obj tor-resolve.exe: tor-resolve.obj $(CC) $(CFLAGS) $(LIBS) ..\common\*.lib tor-resolve.obj +tor-print-ed-signing-cert.exe: tor-print-ed-signing-cert.obj + $(CC) $(CFLAGS) $(LIBS) ..\common\*.lib tor-print-ed-signing-cert.obj + clean: del *.obj *.lib *.exe diff --git a/src/tools/include.am b/src/tools/include.am index 8a2ecb23c9..d5924dda5f 100644 --- a/src/tools/include.am +++ b/src/tools/include.am @@ -1,4 +1,4 @@ -bin_PROGRAMS+= src/tools/tor-resolve src/tools/tor-gencert +bin_PROGRAMS+= src/tools/tor-resolve src/tools/tor-gencert src/tools/tor-print-ed-signing-cert if COVERAGE_ENABLED noinst_PROGRAMS+= src/tools/tor-cov-resolve src/tools/tor-cov-gencert @@ -29,6 +29,15 @@ src_tools_tor_gencert_LDADD = \ @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ +src_tools_tor_print_ed_signing_cert_SOURCES = src/tools/tor-print-ed-signing-cert.c +src_tools_tor_print_ed_signing_cert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ +src_tools_tor_print_ed_signing_cert_LDADD = \ + src/trunnel/libor-trunnel.a \ + $(TOR_CRYPTO_LIBS) \ + $(TOR_UTIL_LIBS) \ + @TOR_LIB_MATH@ @TOR_OPENSSL_LIBS@ \ + @TOR_LIB_WS32@ @TOR_LIB_USERENV@ + if COVERAGE_ENABLED src_tools_tor_cov_gencert_SOURCES = src/tools/tor-gencert.c src_tools_tor_cov_gencert_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) diff --git a/src/tools/tor-print-ed-signing-cert.c b/src/tools/tor-print-ed-signing-cert.c new file mode 100644 index 0000000000..0f64059d84 --- /dev/null +++ b/src/tools/tor-print-ed-signing-cert.c @@ -0,0 +1,65 @@ +/* Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "ed25519_cert.h" +#include "lib/cc/torint.h" /* TOR_PRIdSZ */ +#include "lib/crypt_ops/crypto_format.h" +#include "lib/malloc/malloc.h" + +int +main(int argc, char **argv) +{ + ed25519_cert_t *cert = NULL; + + if (argc != 2) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "%s <path to ed25519_signing_cert file>\n", argv[0]); + return -1; + } + + const char *filepath = argv[1]; + char *got_tag = NULL; + + uint8_t certbuf[256]; + ssize_t cert_body_len = crypto_read_tagged_contents_from_file( + filepath, "ed25519v1-cert", + &got_tag, certbuf, sizeof(certbuf)); + + if (cert_body_len <= 0) { + fprintf(stderr, "crypto_read_tagged_contents_from_file failed with " + "error: %s\n", strerror(errno)); + return -2; + } + + if (!got_tag) { + fprintf(stderr, "Found no tag\n"); + return -3; + } + + if (strcmp(got_tag, "type4") != 0) { + fprintf(stderr, "Wrong tag: %s\n", got_tag); + return -4; + } + + tor_free(got_tag); + + ssize_t parsed = ed25519_cert_parse(&cert, certbuf, cert_body_len); + if (parsed <= 0) { + fprintf(stderr, "ed25519_cert_parse failed with return value %" TOR_PRIdSZ + "\n", parsed); + return -5; + } + + time_t expires_at = (time_t)cert->exp_field * 60 * 60; + + printf("Expires at: %s", ctime(&expires_at)); + + ed25519_cert_free(cert); + + return 0; +} |