summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml9
-rw-r--r--Doxyfile.in3
-rw-r--r--Makefile.am4
-rw-r--r--changes/ticket309844
-rw-r--r--changes/ticket320217
-rw-r--r--changes/ticket326094
-rw-r--r--changes/ticket326294
-rwxr-xr-xcontrib/client-tools/tor-resolve.py5
-rwxr-xr-xscripts/codegen/fuzzing_include_am.py5
-rwxr-xr-xscripts/codegen/gen_server_ciphers.py5
-rwxr-xr-xscripts/codegen/get_mozilla_ciphers.py5
-rw-r--r--scripts/codegen/makedesc.py5
-rwxr-xr-xscripts/maint/add_c_file.py5
-rwxr-xr-xscripts/maint/annotate_ifdef_directives.py5
-rwxr-xr-xscripts/maint/checkIncludes.py5
-rwxr-xr-xscripts/maint/format_changelog.py4
-rwxr-xr-xscripts/maint/lintChanges.py5
-rwxr-xr-xscripts/maint/locatemissingdoxygen.py5
-rwxr-xr-xscripts/maint/practracker/includes.py4
-rw-r--r--scripts/maint/practracker/metrics.py5
-rwxr-xr-xscripts/maint/practracker/practracker.py3
-rwxr-xr-xscripts/maint/practracker/practracker_tests.py5
-rw-r--r--scripts/maint/practracker/problem.py3
-rw-r--r--scripts/maint/practracker/util.py5
-rwxr-xr-xscripts/maint/rectify_include_paths.py5
-rwxr-xr-xscripts/maint/redox.py11
-rwxr-xr-xscripts/maint/rename_c_identifier.py5
-rwxr-xr-xscripts/maint/sortChanges.py4
-rwxr-xr-xscripts/maint/update_versions.py3
-rw-r--r--scripts/test/appveyor-irc-notify.py4
-rw-r--r--src/config/mmdb-convert.py5
-rw-r--r--src/core/or/circuituse.c13
-rw-r--r--src/ext/ed25519/ref10/base.py5
-rw-r--r--src/ext/ed25519/ref10/base2.py5
-rw-r--r--src/ext/ed25519/ref10/d.py5
-rw-r--r--src/ext/ed25519/ref10/d2.py5
-rw-r--r--src/ext/ed25519/ref10/sqrtm1.py5
-rw-r--r--src/feature/control/control_cmd.c142
-rw-r--r--src/feature/control/control_getinfo.c45
-rw-r--r--src/feature/control/control_proto.c157
-rw-r--r--src/feature/control/control_proto.h72
-rw-r--r--src/feature/hs/hs_circuit.c48
-rw-r--r--src/feature/hs/hs_circuit.h2
-rw-r--r--src/lib/encoding/kvline.c52
-rw-r--r--src/lib/encoding/kvline.h1
-rwxr-xr-xsrc/test/bt_test.py4
-rw-r--r--src/test/ed25519_exts_ref.py5
-rw-r--r--src/test/hs_build_address.py5
-rw-r--r--src/test/hs_indexes.py5
-rw-r--r--src/test/hs_ntor_ref.py5
-rwxr-xr-xsrc/test/ntor_ref.py5
-rw-r--r--src/test/ope_ref.py5
-rw-r--r--src/test/slow_ed25519.py5
-rw-r--r--src/test/slownacl_curve25519.py7
-rw-r--r--src/test/sr_commit_calc_ref.py5
-rw-r--r--src/test/sr_srv_calc_ref.py5
-rw-r--r--src/test/test_config.c30
-rw-r--r--src/test/test_controller.c71
-rw-r--r--src/test/test_hs_control.c4
-rw-r--r--src/test/test_rebind.py3
60 files changed, 731 insertions, 141 deletions
diff --git a/.travis.yml b/.travis.yml
index eabc495aa4..1fee931e24 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -70,15 +70,16 @@ matrix:
- env: MODULES_OPTIONS="--disable-module-relay"
## We check disable module dirauth
- env: MODULES_OPTIONS="--disable-module-dirauth"
+ ## macOS builds are very slow, and we have a limited number of
+ ## concurrent macOS jobs. We're not actively developing Rust, so it is
+ ## the lowest priority.
## We run rust on macOS, because we have seen macOS rust failures before
- # Disabled due to slow Travis macOS builds, see #32177
#- env: RUST_VERSION="nightly" RUST_OPTIONS="--enable-rust --enable-cargo-online-mode"
# compiler: clang
# os: osx
## We run chutney on macOS, because macOS Travis has IPv6
- # Disabled due to slow Travis macOS builds, see #32177
- #- env: CHUTNEY="yes" CHUTNEY_ALLOW_FAILURES="2" SKIP_MAKE_CHECK="yes"
- # os: osx
+ - env: CHUTNEY="yes" CHUTNEY_ALLOW_FAILURES="2" SKIP_MAKE_CHECK="yes"
+ os: osx
## We clone our stem repo and run `make test-stem`
- env: TEST_STEM="yes" SKIP_MAKE_CHECK="yes"
diff --git a/Doxyfile.in b/Doxyfile.in
index c99f536e60..503c1302db 100644
--- a/Doxyfile.in
+++ b/Doxyfile.in
@@ -2117,7 +2117,8 @@ PREDEFINED = "MOCK_IMPL(a,b,c)=a b c" \
__attribute__(x)= \
"BEGIN_CONF_STRUCT(x)=struct x {" \
"END_CONF_STRUCT(x)=};" \
- "CONF_VAR(a,b,c,d)=b a;"
+ "CONF_VAR(a,b,c,d)=b a;" \
+ "CHECK_PRINTF(a, b)="
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
diff --git a/Makefile.am b/Makefile.am
index 58b791a619..2dd3a7aa3f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -265,14 +265,10 @@ test: all
shellcheck:
$(top_srcdir)/scripts/maint/checkShellScripts.sh
-check-practracker-unit-test:
- $(top_srcdir)/scripts/maint/practracker/test_practracker.sh
-
check-local: \
check-spaces \
check-changes \
check-includes \
- check-practracker-unit-test \
check-best-practices \
shellcheck \
check-cocci
diff --git a/changes/ticket30984 b/changes/ticket30984
new file mode 100644
index 0000000000..de7d055415
--- /dev/null
+++ b/changes/ticket30984
@@ -0,0 +1,4 @@
+ o Code simplification and refactoring:
+ - Create a new abstraction for formatting control protocol reply
+ lines based on key-value pairs. Refactor some existing control
+ protocol code to take advantage of this. Closes ticket 30984.
diff --git a/changes/ticket32021 b/changes/ticket32021
new file mode 100644
index 0000000000..24a6d9d981
--- /dev/null
+++ b/changes/ticket32021
@@ -0,0 +1,7 @@
+ o Minor bugfixes (onion services v3, client):
+ - Properly handle the client rendezvous circuit timeout. This results in
+ better reachability because tor doesn't timeout a rendezvous circuit
+ awaiting the introduction ACK and thus preventing tor to re-establish all
+ circuits because the rendezvous circuit timed out too early. Fixes bug
+ 32021; bugfix on 0.3.2.1-alpha.
+
diff --git a/changes/ticket32609 b/changes/ticket32609
index 2fc3f733f5..d37b3d66b8 100644
--- a/changes/ticket32609
+++ b/changes/ticket32609
@@ -1,3 +1,3 @@
o Testing:
- - Run the practracker unit tests as part of "make check", and in the
- pre-commit git hook. Closes ticket 32609.
+ - Run the practracker unit tests in the pre-commit git hook.
+ Closes ticket 32609.
diff --git a/changes/ticket32629 b/changes/ticket32629
new file mode 100644
index 0000000000..740746c572
--- /dev/null
+++ b/changes/ticket32629
@@ -0,0 +1,4 @@
+ o Testing:
+ - Re-enable the Travis CI macOS Chutney build, but allow the job to finish
+ before it finishes, because the Travis macOS jobs are slow.
+ Closes ticket 32629.
diff --git a/contrib/client-tools/tor-resolve.py b/contrib/client-tools/tor-resolve.py
index 47ae1a0c38..593efc97d4 100755
--- a/contrib/client-tools/tor-resolve.py
+++ b/contrib/client-tools/tor-resolve.py
@@ -1,5 +1,10 @@
#!/usr/bin/python
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import socket
import struct
import sys
diff --git a/scripts/codegen/fuzzing_include_am.py b/scripts/codegen/fuzzing_include_am.py
index a944584453..aa3ba49a73 100755
--- a/scripts/codegen/fuzzing_include_am.py
+++ b/scripts/codegen/fuzzing_include_am.py
@@ -1,5 +1,10 @@
#!/usr/bin/python
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
FUZZERS = """
consensus
descriptor
diff --git a/scripts/codegen/gen_server_ciphers.py b/scripts/codegen/gen_server_ciphers.py
index 5d326f8b9e..dd295b7f7d 100755
--- a/scripts/codegen/gen_server_ciphers.py
+++ b/scripts/codegen/gen_server_ciphers.py
@@ -8,6 +8,11 @@
#
# Run it on all the files in your openssl include directory.
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import re
import sys
diff --git a/scripts/codegen/get_mozilla_ciphers.py b/scripts/codegen/get_mozilla_ciphers.py
index f23f2f1e6f..d149c71c27 100755
--- a/scripts/codegen/get_mozilla_ciphers.py
+++ b/scripts/codegen/get_mozilla_ciphers.py
@@ -10,6 +10,11 @@
# It takes two arguments: the location of a firefox source directory, and the
# location of an openssl source directory.
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import os
import re
import sys
diff --git a/scripts/codegen/makedesc.py b/scripts/codegen/makedesc.py
index efca4dda9a..7d8177f469 100644
--- a/scripts/codegen/makedesc.py
+++ b/scripts/codegen/makedesc.py
@@ -9,6 +9,11 @@
# I've used this to make inputs for unit tests. I wouldn't suggest
# using it for anything else.
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import base64
import binascii
import ctypes
diff --git a/scripts/maint/add_c_file.py b/scripts/maint/add_c_file.py
index a773fd0fff..a9a6eb25bd 100755
--- a/scripts/maint/add_c_file.py
+++ b/scripts/maint/add_c_file.py
@@ -9,6 +9,11 @@
% add_c_file.py ./src/feature/dirauth/ocelot.c
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import os
import re
import time
diff --git a/scripts/maint/annotate_ifdef_directives.py b/scripts/maint/annotate_ifdef_directives.py
index 102128bfa0..cd70b55c8c 100755
--- a/scripts/maint/annotate_ifdef_directives.py
+++ b/scripts/maint/annotate_ifdef_directives.py
@@ -57,6 +57,11 @@ Note that only #else and #endif lines are annotated. Existing comments
on those lines are removed.
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import re
# Any block with fewer than this many lines does not need annotations.
diff --git a/scripts/maint/checkIncludes.py b/scripts/maint/checkIncludes.py
index 926b201b35..2ca46347f0 100755
--- a/scripts/maint/checkIncludes.py
+++ b/scripts/maint/checkIncludes.py
@@ -5,6 +5,11 @@
# functionality. This is a stub file that exists so that older git
# hooks will know where to look.
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys, os
dirname = os.path.split(sys.argv[0])[0]
diff --git a/scripts/maint/format_changelog.py b/scripts/maint/format_changelog.py
index 97a6ce938b..5f04a44ef6 100755
--- a/scripts/maint/format_changelog.py
+++ b/scripts/maint/format_changelog.py
@@ -9,7 +9,11 @@
# To run it, pipe a section of the changelog (starting with "Changes
# in Tor 0.x.y.z-alpha" through the script.)
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
+from __future__ import unicode_literals
+
import os
import re
import sys
diff --git a/scripts/maint/lintChanges.py b/scripts/maint/lintChanges.py
index 82c118f07e..88a865a572 100755
--- a/scripts/maint/lintChanges.py
+++ b/scripts/maint/lintChanges.py
@@ -1,7 +1,10 @@
#!/usr/bin/python
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
-from __future__ import with_statement
+from __future__ import unicode_literals
+
import sys
import re
import os
diff --git a/scripts/maint/locatemissingdoxygen.py b/scripts/maint/locatemissingdoxygen.py
index 797bf8176f..9e58bd3477 100755
--- a/scripts/maint/locatemissingdoxygen.py
+++ b/scripts/maint/locatemissingdoxygen.py
@@ -7,6 +7,11 @@
to highlight the undocumented stuff.
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import os
import re
import shutil
diff --git a/scripts/maint/practracker/includes.py b/scripts/maint/practracker/includes.py
index ed0e11ef28..fe0f32e253 100755
--- a/scripts/maint/practracker/includes.py
+++ b/scripts/maint/practracker/includes.py
@@ -19,8 +19,10 @@
Advisory .may_include files only result in warnings, rather than errors.
"""
-
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
+from __future__ import unicode_literals
import fnmatch
import os
diff --git a/scripts/maint/practracker/metrics.py b/scripts/maint/practracker/metrics.py
index 4c62bc2425..ae88b84f31 100644
--- a/scripts/maint/practracker/metrics.py
+++ b/scripts/maint/practracker/metrics.py
@@ -4,6 +4,11 @@
# These are currently ad-hoc string operations and regexps.
# We might want to use a proper static analysis library in the future, if we want to get more advanced metrics.
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import re
def get_file_len(f):
diff --git a/scripts/maint/practracker/practracker.py b/scripts/maint/practracker/practracker.py
index 5f26d28cea..e1845c43e3 100755
--- a/scripts/maint/practracker/practracker.py
+++ b/scripts/maint/practracker/practracker.py
@@ -19,7 +19,10 @@ problems in the Tor source, use the --regen flag:
$ python3 --regen ./scripts/maint/practracker/practracker.py .
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
+from __future__ import unicode_literals
import os, sys
diff --git a/scripts/maint/practracker/practracker_tests.py b/scripts/maint/practracker/practracker_tests.py
index 45719d6cb7..8d0418880c 100755
--- a/scripts/maint/practracker/practracker_tests.py
+++ b/scripts/maint/practracker/practracker_tests.py
@@ -2,6 +2,11 @@
"""Some simple tests for practracker metrics"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import unittest
try:
diff --git a/scripts/maint/practracker/problem.py b/scripts/maint/practracker/problem.py
index d21840a213..bee5eeb903 100644
--- a/scripts/maint/practracker/problem.py
+++ b/scripts/maint/practracker/problem.py
@@ -7,7 +7,10 @@ problem is worse than a registered exception so that it only warns when things
get worse.
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
+from __future__ import unicode_literals
import os.path
import re
diff --git a/scripts/maint/practracker/util.py b/scripts/maint/practracker/util.py
index db02a983f8..c52ca2fbbf 100644
--- a/scripts/maint/practracker/util.py
+++ b/scripts/maint/practracker/util.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import os
# We don't want to run metrics for unittests, automatically-generated C files,
diff --git a/scripts/maint/rectify_include_paths.py b/scripts/maint/rectify_include_paths.py
index 1140e8cd22..111cf816ce 100755
--- a/scripts/maint/rectify_include_paths.py
+++ b/scripts/maint/rectify_include_paths.py
@@ -1,5 +1,10 @@
#!/usr/bin/python
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import os
import os.path
import re
diff --git a/scripts/maint/redox.py b/scripts/maint/redox.py
index 203cce0107..171c6d9699 100755
--- a/scripts/maint/redox.py
+++ b/scripts/maint/redox.py
@@ -29,6 +29,14 @@
# "mv fname.c.newdoc fname.c". Otherwise, you'll need to merge
# the parts you like by hand.
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+import re
+import sys
+
# Which files should we ignore warning from? Mostly, these are external
# files that we've snarfed in from somebody else, whose C we do no intend
# to document for them.
@@ -52,9 +60,6 @@ ADD_DOCDOCS_TO_TYPES += [ 'variable', ]
# ====================
# The rest of this should not need hacking.
-import re
-import sys
-
KINDS = [ "type", "field", "typedef", "define", "function", "variable",
"enumeration" ]
diff --git a/scripts/maint/rename_c_identifier.py b/scripts/maint/rename_c_identifier.py
index 213172d913..6e0c1d8cf1 100755
--- a/scripts/maint/rename_c_identifier.py
+++ b/scripts/maint/rename_c_identifier.py
@@ -11,6 +11,11 @@ Helpful script to replace one or more C identifiers, and optionally
generate a commit message explaining what happened.
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import argparse
import fileinput
import os
diff --git a/scripts/maint/sortChanges.py b/scripts/maint/sortChanges.py
index 44dd0dc41f..2e049b1e53 100755
--- a/scripts/maint/sortChanges.py
+++ b/scripts/maint/sortChanges.py
@@ -7,7 +7,11 @@
changelog.
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
+from __future__ import unicode_literals
+
import re
import sys
diff --git a/scripts/maint/update_versions.py b/scripts/maint/update_versions.py
index 706a93b6a2..07de1c343a 100755
--- a/scripts/maint/update_versions.py
+++ b/scripts/maint/update_versions.py
@@ -1,6 +1,9 @@
#!/usr/bin/env python
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
+from __future__ import unicode_literals
import io
import os
diff --git a/scripts/test/appveyor-irc-notify.py b/scripts/test/appveyor-irc-notify.py
index cfe0afe7ae..598a68f47d 100644
--- a/scripts/test/appveyor-irc-notify.py
+++ b/scripts/test/appveyor-irc-notify.py
@@ -75,8 +75,10 @@ in Appveyor's YAML:
- "python scripts/test/appveyor-irc-notify.py irc.oftc.net:6697 tor-ci failure
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
-from __future__ import absolute_import
+from __future__ import unicode_literals
import os
import random
diff --git a/src/config/mmdb-convert.py b/src/config/mmdb-convert.py
index b861e9433e..a58f5d43e1 100644
--- a/src/config/mmdb-convert.py
+++ b/src/config/mmdb-convert.py
@@ -28,6 +28,11 @@
pieces.
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import struct
import bisect
import socket
diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
index ad9841cc36..e5013fe968 100644
--- a/src/core/or/circuituse.c
+++ b/src/core/or/circuituse.c
@@ -775,16 +775,11 @@ circuit_expire_building(void)
if (!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)) {
switch (victim->purpose) {
case CIRCUIT_PURPOSE_C_REND_READY:
- /* We only want to spare a rend circ if it has been specified in
- * an INTRODUCE1 cell sent to a hidden service. A circ's
- * pending_final_cpath field is non-NULL iff it is a rend circ
- * and we have tried to send an INTRODUCE1 cell specifying it.
- * Thus, if the pending_final_cpath field *is* NULL, then we
- * want to not spare it. */
- if (TO_ORIGIN_CIRCUIT(victim)->build_state &&
- TO_ORIGIN_CIRCUIT(victim)->build_state->pending_final_cpath ==
- NULL)
+ /* We only want to spare a rend circ iff it has been specified in an
+ * INTRODUCE1 cell sent to a hidden service. */
+ if (!hs_circ_is_rend_sent_in_intro1(CONST_TO_ORIGIN_CIRCUIT(victim))) {
break;
+ }
/* fallthrough! */
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
diff --git a/src/ext/ed25519/ref10/base.py b/src/ext/ed25519/ref10/base.py
index 84accc8580..8bfaab0568 100644
--- a/src/ext/ed25519/ref10/base.py
+++ b/src/ext/ed25519/ref10/base.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
b = 256
q = 2**255 - 19
l = 2**252 + 27742317777372353535851937790883648493
diff --git a/src/ext/ed25519/ref10/base2.py b/src/ext/ed25519/ref10/base2.py
index 5e4e8739d0..5923e43a7b 100644
--- a/src/ext/ed25519/ref10/base2.py
+++ b/src/ext/ed25519/ref10/base2.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
b = 256
q = 2**255 - 19
l = 2**252 + 27742317777372353535851937790883648493
diff --git a/src/ext/ed25519/ref10/d.py b/src/ext/ed25519/ref10/d.py
index 8995bb86a3..3fbb175077 100644
--- a/src/ext/ed25519/ref10/d.py
+++ b/src/ext/ed25519/ref10/d.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
q = 2**255 - 19
def expmod(b,e,m):
diff --git a/src/ext/ed25519/ref10/d2.py b/src/ext/ed25519/ref10/d2.py
index 79841758be..3e533730b7 100644
--- a/src/ext/ed25519/ref10/d2.py
+++ b/src/ext/ed25519/ref10/d2.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
q = 2**255 - 19
def expmod(b,e,m):
diff --git a/src/ext/ed25519/ref10/sqrtm1.py b/src/ext/ed25519/ref10/sqrtm1.py
index 9a47fbc12a..a276d4e673 100644
--- a/src/ext/ed25519/ref10/sqrtm1.py
+++ b/src/ext/ed25519/ref10/sqrtm1.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
q = 2**255 - 19
def expmod(b,e,m):
diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c
index 656ddf5ca1..cc4375112f 100644
--- a/src/feature/control/control_cmd.c
+++ b/src/feature/control/control_cmd.c
@@ -289,26 +289,23 @@ handle_control_getconf(control_connection_t *conn,
const smartlist_t *questions = args->args;
smartlist_t *answers = smartlist_new();
smartlist_t *unrecognized = smartlist_new();
- char *msg = NULL;
- size_t msg_len;
const or_options_t *options = get_options();
- int i, len;
SMARTLIST_FOREACH_BEGIN(questions, const char *, q) {
if (!option_is_recognized(q)) {
- smartlist_add(unrecognized, (char*) q);
+ control_reply_add_printf(unrecognized, 552,
+ "Unrecognized configuration key \"%s\"", q);
} else {
config_line_t *answer = option_get_assignment(options,q);
if (!answer) {
const char *name = option_get_canonical_name(q);
- smartlist_add_asprintf(answers, "250-%s\r\n", name);
+ control_reply_add_one_kv(answers, 250, KV_OMIT_VALS, name, "");
}
while (answer) {
config_line_t *next;
- smartlist_add_asprintf(answers, "250-%s=%s\r\n",
- answer->key, answer->value);
-
+ control_reply_add_one_kv(answers, 250, KV_RAW, answer->key,
+ answer->value);
next = answer->next;
tor_free(answer->key);
tor_free(answer->value);
@@ -318,20 +315,10 @@ handle_control_getconf(control_connection_t *conn,
}
} SMARTLIST_FOREACH_END(q);
- if ((len = smartlist_len(unrecognized))) {
- for (i=0; i < len-1; ++i)
- control_printf_midreply(conn, 552,
- "Unrecognized configuration key \"%s\"",
- (char*)smartlist_get(unrecognized, i));
- control_printf_endreply(conn, 552,
- "Unrecognized configuration key \"%s\"",
- (char*)smartlist_get(unrecognized, len-1));
- } else if ((len = smartlist_len(answers))) {
- char *tmp = smartlist_get(answers, len-1);
- tor_assert(strlen(tmp)>4);
- tmp[3] = ' ';
- msg = smartlist_join_strings(answers, "", 0, &msg_len);
- connection_buf_add(msg, msg_len, TO_CONN(conn));
+ if (smartlist_len(unrecognized)) {
+ control_write_reply_lines(conn, unrecognized);
+ } else if (smartlist_len(answers)) {
+ control_write_reply_lines(conn, answers);
} else {
send_control_done(conn);
}
@@ -340,8 +327,6 @@ handle_control_getconf(control_connection_t *conn,
smartlist_free(answers);
smartlist_free(unrecognized);
- tor_free(msg);
-
return 0;
}
@@ -1257,6 +1242,66 @@ static const control_cmd_syntax_t protocolinfo_syntax = {
.max_args = UINT_MAX
};
+/** Return a comma-separated list of authentication methods for
+ handle_control_protocolinfo(). Caller must free this string. */
+static char *
+get_authmethods(const or_options_t *options)
+{
+ int cookies = options->CookieAuthentication;
+ char *methods;
+ int passwd = (options->HashedControlPassword != NULL ||
+ options->HashedControlSessionPassword != NULL);
+ smartlist_t *mlist = smartlist_new();
+
+ if (cookies) {
+ smartlist_add(mlist, (char*)"COOKIE");
+ smartlist_add(mlist, (char*)"SAFECOOKIE");
+ }
+ if (passwd)
+ smartlist_add(mlist, (char*)"HASHEDPASSWORD");
+ if (!cookies && !passwd)
+ smartlist_add(mlist, (char*)"NULL");
+ methods = smartlist_join_strings(mlist, ",", 0, NULL);
+ smartlist_free(mlist);
+
+ return methods;
+}
+
+/** Return escaped cookie filename. Caller must free this string.
+ Return NULL if cookie authentication is disabled. */
+static char *
+get_esc_cfile(const or_options_t *options)
+{
+ char *cfile = NULL, *abs_cfile = NULL, *esc_cfile = NULL;
+
+ if (!options->CookieAuthentication)
+ return NULL;
+
+ cfile = get_controller_cookie_file_name();
+ abs_cfile = make_path_absolute(cfile);
+ esc_cfile = esc_for_log(abs_cfile);
+ tor_free(cfile);
+ tor_free(abs_cfile);
+ return esc_cfile;
+}
+
+/** Compose the auth methods line of a PROTOCOLINFO reply. */
+static void
+add_authmethods(smartlist_t *reply)
+{
+ const or_options_t *options = get_options();
+ char *methods = get_authmethods(options);
+ char *esc_cfile = get_esc_cfile(options);
+
+ control_reply_add_str(reply, 250, "AUTH");
+ control_reply_append_kv(reply, "METHODS", methods);
+ if (esc_cfile)
+ control_reply_append_kv(reply, "COOKIEFILE", esc_cfile);
+
+ tor_free(methods);
+ tor_free(esc_cfile);
+}
+
/** Called when we get a PROTOCOLINFO command: send back a reply. */
static int
handle_control_protocolinfo(control_connection_t *conn,
@@ -1264,6 +1309,7 @@ handle_control_protocolinfo(control_connection_t *conn,
{
const char *bad_arg = NULL;
const smartlist_t *args = cmd_args->args;
+ smartlist_t *reply = NULL;
conn->have_sent_protocolinfo = 1;
@@ -1281,45 +1327,17 @@ handle_control_protocolinfo(control_connection_t *conn,
/* Don't tolerate bad arguments when not authenticated. */
if (!STATE_IS_OPEN(TO_CONN(conn)->state))
connection_mark_for_close(TO_CONN(conn));
- goto done;
- } else {
- const or_options_t *options = get_options();
- int cookies = options->CookieAuthentication;
- char *cfile = get_controller_cookie_file_name();
- char *abs_cfile;
- char *esc_cfile;
- char *methods;
- abs_cfile = make_path_absolute(cfile);
- esc_cfile = esc_for_log(abs_cfile);
- {
- int passwd = (options->HashedControlPassword != NULL ||
- options->HashedControlSessionPassword != NULL);
- smartlist_t *mlist = smartlist_new();
- if (cookies) {
- smartlist_add(mlist, (char*)"COOKIE");
- smartlist_add(mlist, (char*)"SAFECOOKIE");
- }
- if (passwd)
- smartlist_add(mlist, (char*)"HASHEDPASSWORD");
- if (!cookies && !passwd)
- smartlist_add(mlist, (char*)"NULL");
- methods = smartlist_join_strings(mlist, ",", 0, NULL);
- smartlist_free(mlist);
- }
-
- control_write_midreply(conn, 250, "PROTOCOLINFO 1");
- control_printf_midreply(conn, 250, "AUTH METHODS=%s%s%s", methods,
- cookies?" COOKIEFILE=":"",
- cookies?esc_cfile:"");
- control_printf_midreply(conn, 250, "VERSION Tor=%s", escaped(VERSION));
- send_control_done(conn);
-
- tor_free(methods);
- tor_free(cfile);
- tor_free(abs_cfile);
- tor_free(esc_cfile);
+ return 0;
}
- done:
+ reply = smartlist_new();
+ control_reply_add_str(reply, 250, "PROTOCOLINFO 1");
+ add_authmethods(reply);
+ control_reply_add_str(reply, 250, "VERSION");
+ control_reply_append_kv(reply, "Tor", escaped(VERSION));
+ control_reply_add_done(reply);
+
+ control_write_reply_lines(conn, reply);
+ control_reply_free(reply);
return 0;
}
diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c
index 979fa4480d..cff4a08793 100644
--- a/src/feature/control/control_getinfo.c
+++ b/src/feature/control/control_getinfo.c
@@ -50,6 +50,7 @@
#include "feature/stats/geoip_stats.h"
#include "feature/stats/predict_ports.h"
#include "lib/version/torversion.h"
+#include "lib/encoding/kvline.h"
#include "core/or/entry_connection_st.h"
#include "core/or/or_connection_st.h"
@@ -1632,7 +1633,6 @@ handle_control_getinfo(control_connection_t *conn,
smartlist_t *answers = smartlist_new();
smartlist_t *unrecognized = smartlist_new();
char *ans = NULL;
- int i;
SMARTLIST_FOREACH_BEGIN(questions, const char *, q) {
const char *errmsg = NULL;
@@ -1644,43 +1644,32 @@ handle_control_getinfo(control_connection_t *conn,
goto done;
}
if (!ans) {
- if (errmsg) /* use provided error message */
- smartlist_add_strdup(unrecognized, errmsg);
- else /* use default error message */
- smartlist_add_asprintf(unrecognized, "Unrecognized key \"%s\"", q);
+ if (errmsg) {
+ /* use provided error message */
+ control_reply_add_str(unrecognized, 552, errmsg);
+ } else {
+ /* use default error message */
+ control_reply_add_printf(unrecognized, 552,
+ "Unrecognized key \"%s\"", q);
+ }
} else {
- smartlist_add_strdup(answers, q);
- smartlist_add(answers, ans);
+ control_reply_add_one_kv(answers, 250, KV_RAW, q, ans);
}
} SMARTLIST_FOREACH_END(q);
- if (smartlist_len(unrecognized)) {
- /* control-spec section 2.3, mid-reply '-' or end of reply ' ' */
- for (i=0; i < smartlist_len(unrecognized)-1; ++i)
- control_write_midreply(conn, 552,
- (char *)smartlist_get(unrecognized, i));
+ control_reply_add_done(answers);
- control_write_endreply(conn, 552, (char *)smartlist_get(unrecognized, i));
+ if (smartlist_len(unrecognized)) {
+ control_write_reply_lines(conn, unrecognized);
+ /* If there were any unrecognized queries, don't write real answers */
goto done;
}
- for (i = 0; i < smartlist_len(answers); i += 2) {
- char *k = smartlist_get(answers, i);
- char *v = smartlist_get(answers, i+1);
- if (!strchr(v, '\n') && !strchr(v, '\r')) {
- control_printf_midreply(conn, 250, "%s=%s", k, v);
- } else {
- control_printf_datareply(conn, 250, "%s=", k);
- control_write_data(conn, v);
- }
- }
- send_control_done(conn);
+ control_write_reply_lines(conn, answers);
done:
- SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp));
- smartlist_free(answers);
- SMARTLIST_FOREACH(unrecognized, char *, cp, tor_free(cp));
- smartlist_free(unrecognized);
+ control_reply_free(answers);
+ control_reply_free(unrecognized);
return 0;
}
diff --git a/src/feature/control/control_proto.c b/src/feature/control/control_proto.c
index 5dec87491d..7d04fea6a7 100644
--- a/src/feature/control/control_proto.c
+++ b/src/feature/control/control_proto.c
@@ -22,6 +22,8 @@
#include "core/or/origin_circuit_st.h"
#include "core/or/socks_request_st.h"
#include "feature/control/control_connection_st.h"
+#include "lib/container/smartlist.h"
+#include "lib/encoding/kvline.h"
/** Append a NUL-terminated string <b>s</b> to the end of
* <b>conn</b>-\>outbuf.
@@ -275,3 +277,158 @@ control_write_data(control_connection_t *conn, const char *data)
connection_buf_add(esc, esc_len, TO_CONN(conn));
tor_free(esc);
}
+
+/** Write a single reply line to @a conn.
+ *
+ * @param conn control connection
+ * @param line control reply line to write
+ * @param lastone true if this is the last reply line of a multi-line reply
+ */
+void
+control_write_reply_line(control_connection_t *conn,
+ const control_reply_line_t *line, bool lastone)
+{
+ const config_line_t *kvline = line->kvline;
+ char *s = NULL;
+
+ if (strpbrk(kvline->value, "\r\n") != NULL) {
+ /* If a key-value pair needs to be encoded as CmdData, it can be
+ the only key-value pair in that reply line */
+ tor_assert(kvline->next == NULL);
+ control_printf_datareply(conn, line->code, "%s=", kvline->key);
+ control_write_data(conn, kvline->value);
+ return;
+ }
+ s = kvline_encode(kvline, line->flags);
+ if (lastone) {
+ control_write_endreply(conn, line->code, s);
+ } else {
+ control_write_midreply(conn, line->code, s);
+ }
+ tor_free(s);
+}
+
+/** Write a set of reply lines to @a conn.
+ *
+ * @param conn control connection
+ * @param lines smartlist of pointers to control_reply_line_t to write
+ */
+void
+control_write_reply_lines(control_connection_t *conn, smartlist_t *lines)
+{
+ bool lastone = false;
+
+ SMARTLIST_FOREACH_BEGIN(lines, control_reply_line_t *, line) {
+ if (line_sl_idx >= line_sl_len - 1)
+ lastone = true;
+ control_write_reply_line(conn, line, lastone);
+ } SMARTLIST_FOREACH_END(line);
+}
+
+/** Add a single key-value pair as a new reply line to a control reply
+ * line list.
+ *
+ * @param reply smartlist of pointers to control_reply_line_t
+ * @param code numeric control reply code
+ * @param flags kvline encoding flags
+ * @param key key
+ * @param val value
+ */
+void
+control_reply_add_one_kv(smartlist_t *reply, int code, int flags,
+ const char *key, const char *val)
+{
+ control_reply_line_t *line = tor_malloc_zero(sizeof(*line));
+
+ line->code = code;
+ line->flags = flags;
+ config_line_append(&line->kvline, key, val);
+ smartlist_add(reply, line);
+}
+
+/** Append a single key-value pair to last reply line in a control
+ * reply line list.
+ *
+ * @param reply smartlist of pointers to control_reply_line_t
+ * @param key key
+ * @param val value
+ */
+void
+control_reply_append_kv(smartlist_t *reply, const char *key, const char *val)
+{
+ int len = smartlist_len(reply);
+ control_reply_line_t *line;
+
+ tor_assert(len > 0);
+
+ line = smartlist_get(reply, len - 1);
+ config_line_append(&line->kvline, key, val);
+}
+
+/** Add new reply line consisting of the string @a s
+ *
+ * @param reply smartlist of pointers to control_reply_line_t
+ * @param code numeric control reply code
+ * @param s string containing the rest of the reply line
+ */
+void
+control_reply_add_str(smartlist_t *reply, int code, const char *s)
+{
+ control_reply_add_one_kv(reply, code, KV_OMIT_KEYS|KV_RAW, "", s);
+}
+
+/** Format a new reply line
+ *
+ * @param reply smartlist of pointers to control_reply_line_t
+ * @param code numeric control reply code
+ * @param fmt format string
+ */
+void
+control_reply_add_printf(smartlist_t *reply, int code, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf = NULL;
+
+ va_start(ap, fmt);
+ (void)tor_vasprintf(&buf, fmt, ap);
+ va_end(ap);
+ control_reply_add_str(reply, code, buf);
+ tor_free(buf);
+}
+
+/** Add a "250 OK" line to a set of control reply lines */
+void
+control_reply_add_done(smartlist_t *reply)
+{
+ control_reply_add_str(reply, 250, "OK");
+}
+
+/** Free a control_reply_line_t. Don't call this directly; use the
+ * control_reply_line_free() macro instead. */
+void
+control_reply_line_free_(control_reply_line_t *line)
+{
+ if (!line)
+ return;
+ config_free_lines(line->kvline);
+ tor_free_(line);
+}
+
+/** Clear a smartlist of control_reply_line_t. Doesn't free the
+ * smartlist, but does free each individual line. */
+void
+control_reply_clear(smartlist_t *reply)
+{
+ SMARTLIST_FOREACH(reply, control_reply_line_t *, line,
+ control_reply_line_free(line));
+ smartlist_clear(reply);
+}
+
+/** Free a smartlist of control_reply_line_t. Don't call this
+ * directly; use the control_reply_free() macro instead. */
+void
+control_reply_free_(smartlist_t *reply)
+{
+ control_reply_clear(reply);
+ smartlist_free_(reply);
+}
diff --git a/src/feature/control/control_proto.h b/src/feature/control/control_proto.h
index 3182f3d415..cf7c000439 100644
--- a/src/feature/control/control_proto.h
+++ b/src/feature/control/control_proto.h
@@ -7,11 +7,56 @@
/**
* \file control_proto.h
* \brief Header file for control_proto.c.
+ *
+ * See @ref replylines for details about the key-value abstraction for
+ * generating reply lines.
**/
#ifndef TOR_CONTROL_PROTO_H
#define TOR_CONTROL_PROTO_H
+#include "lib/encoding/confline.h"
+
+/**
+ * @defgroup replylines Control reply lines
+ * @brief Key-value structures for control reply lines
+ *
+ * Control reply lines are config_line_t key-value structures with
+ * some additional information to help formatting, such as the numeric
+ * result code specified in the control protocol and flags affecting
+ * the way kvline_encode() formats the @a kvline.
+ *
+ * Generally, modules implementing control commands will work with
+ * smartlists of these structures, using functions like
+ * control_reply_add_str() for adding a reply line consisting of a
+ * single string, or control_reply_add_one_kv() and
+ * control_reply_append_kv() for composing a line containing one or
+ * more key-value pairs.
+ *
+ * @{
+ */
+/** @brief A reply line for the control protocol.
+ *
+ * This wraps config_line_t with some additional information that's
+ * useful when generating control reply lines.
+ */
+typedef struct control_reply_line_t {
+ int code; /**< numeric code */
+ int flags; /**< kvline encoding flags */
+ config_line_t *kvline; /**< kvline */
+} control_reply_line_t;
+
+void control_reply_line_free_(control_reply_line_t *line);
+/**
+ * @brief Free and null a control_reply_line_t
+ *
+ * @param line pointer to control_reply_line_t to free
+ */
+#define control_reply_line_free(line) \
+ FREE_AND_NULL(control_reply_line_t, \
+ control_reply_line_free_, (line))
+/** @} */
+
void connection_write_str_to_buf(const char *s, control_connection_t *conn);
void connection_printf_to_buf(control_connection_t *conn,
const char *format, ...)
@@ -45,4 +90,31 @@ void control_printf_datareply(control_connection_t *conn, int code,
CHECK_PRINTF(3, 4);
void control_write_data(control_connection_t *conn, const char *data);
+/** @addtogroup replylines
+ * @{
+ */
+void control_write_reply_line(control_connection_t *conn,
+ const control_reply_line_t *line, bool lastone);
+void control_write_reply_lines(control_connection_t *conn, smartlist_t *lines);
+
+void control_reply_add_one_kv(smartlist_t *reply, int code, int flags,
+ const char *key, const char *val);
+void control_reply_append_kv(smartlist_t *reply, const char *key,
+ const char *val);
+void control_reply_add_str(smartlist_t *reply, int code, const char *s);
+void control_reply_add_printf(smartlist_t *reply, int code,
+ const char *fmt, ...)
+ CHECK_PRINTF(3, 4);
+void control_reply_add_done(smartlist_t *reply);
+
+void control_reply_clear(smartlist_t *reply);
+void control_reply_free_(smartlist_t *reply);
+
+/** @brief Free and null a smartlist of control_reply_line_t.
+ *
+ * @param r pointer to smartlist_t of control_reply_line_t to free */
+#define control_reply_free(r) \
+ FREE_AND_NULL(smartlist_t, control_reply_free_, (r))
+/** @} */
+
#endif /* !defined(TOR_CONTROL_PROTO_H) */
diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c
index a09e319729..2d3bd35a3b 100644
--- a/src/feature/hs/hs_circuit.c
+++ b/src/feature/hs/hs_circuit.c
@@ -1297,3 +1297,51 @@ hs_circ_cleanup_on_repurpose(circuit_t *circ)
hs_circuitmap_remove_circuit(circ);
}
}
+
+/** Return true iff the given established client rendezvous circuit was sent
+ * into the INTRODUCE1 cell. This is called so we can take a decision on
+ * expiring or not the circuit.
+ *
+ * The caller MUST make sure the circuit is an established client rendezvous
+ * circuit (purpose: CIRCUIT_PURPOSE_C_REND_READY).
+ *
+ * This function supports all onion service versions. */
+bool
+hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ)
+{
+ tor_assert(circ);
+ /* This can only be called for a rendezvous circuit that is an established
+ * confirmed rendezsvous circuit but without an introduction ACK. */
+ tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_REND_READY);
+
+ /* The v2 and v3 circuit are handled differently:
+ *
+ * v2: A circ's pending_final_cpath field is non-NULL iff it is a rend circ
+ * and we have tried to send an INTRODUCE1 cell specifying it. Thus, if the
+ * pending_final_cpath field *is* NULL, then we want to not spare it.
+ *
+ * v3: When the INTRODUCE1 cell is sent, the introduction encryption public
+ * key is copied in the rendezvous circuit hs identifier. If it is a valid
+ * key, we know that this circuit is waiting the ACK on the introduction
+ * circuit. We want to _not_ spare the circuit if the key was never set. */
+
+ if (circ->rend_data) {
+ /* v2. */
+ if (circ->build_state && circ->build_state->pending_final_cpath != NULL) {
+ return true;
+ }
+ } else if (circ->hs_ident) {
+ /* v3. */
+ if (curve25519_public_key_is_ok(&circ->hs_ident->intro_enc_pk)) {
+ return true;
+ }
+ } else {
+ /* A circuit with an HS purpose without an hs_ident or rend_data in theory
+ * can not happen. In case, scream loudly and return false to the caller
+ * that the rendezvous was not sent in the INTRO1 cell. */
+ tor_assert_nonfatal_unreached();
+ }
+
+ /* The rendezvous has not been specified in the INTRODUCE1 cell. */
+ return false;
+}
diff --git a/src/feature/hs/hs_circuit.h b/src/feature/hs/hs_circuit.h
index 42e5ca1348..c044ad89c4 100644
--- a/src/feature/hs/hs_circuit.h
+++ b/src/feature/hs/hs_circuit.h
@@ -66,6 +66,8 @@ int hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
int hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ,
const uint8_t *rend_cell_body);
+bool hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ);
+
#ifdef HS_CIRCUIT_PRIVATE
STATIC hs_ident_circuit_t *
diff --git a/src/lib/encoding/kvline.c b/src/lib/encoding/kvline.c
index d4a8f510ba..f55e3d966f 100644
--- a/src/lib/encoding/kvline.c
+++ b/src/lib/encoding/kvline.c
@@ -29,12 +29,20 @@
#include <string.h>
/** Return true iff we need to quote and escape the string <b>s</b> to encode
- * it. */
+ * it.
+ *
+ * kvline_can_encode_lines() also uses this (with
+ * <b>as_keyless_val</b> true) to check whether a key would require
+ * quoting.
+ */
static bool
needs_escape(const char *s, bool as_keyless_val)
{
if (as_keyless_val && *s == 0)
return true;
+ /* Keyless values containing '=' need to be escaped. */
+ if (as_keyless_val && strchr(s, '='))
+ return true;
for (; *s; ++s) {
if (*s >= 127 || TOR_ISSPACE(*s) || ! TOR_ISPRINT(*s) ||
@@ -72,23 +80,17 @@ kvline_can_encode_lines(const config_line_t *line, unsigned flags)
{
for ( ; line; line = line->next) {
const bool keyless = line_has_no_key(line);
- if (keyless) {
- if (! (flags & KV_OMIT_KEYS)) {
- /* If KV_OMIT_KEYS is not set, we can't encode a line with no key. */
- return false;
- }
- if (strchr(line->value, '=') && !( flags & KV_QUOTED)) {
- /* We can't have a keyless value with = without quoting it. */
- return false;
- }
+ if (keyless && ! (flags & KV_OMIT_KEYS)) {
+ /* If KV_OMIT_KEYS is not set, we can't encode a line with no key. */
+ return false;
}
- if (needs_escape(line->value, keyless) && ! (flags & KV_QUOTED)) {
- /* If KV_QUOTED is false, we can't encode a value that needs quotes. */
+ if (needs_escape(line->value, keyless) && ! (flags & (KV_QUOTED|KV_RAW))) {
+ /* If both KV_QUOTED and KV_RAW are false, we can't encode a
+ value that needs quotes. */
return false;
}
- if (line->key && strlen(line->key) &&
- (needs_escape(line->key, false) || strchr(line->key, '='))) {
+ if (!keyless && needs_escape(line->key, true)) {
/* We can't handle keys that need quoting. */
return false;
}
@@ -103,7 +105,7 @@ kvline_can_encode_lines(const config_line_t *line, unsigned flags)
*
* If KV_QUOTED is set in <b>flags</b>, then all values that contain
* spaces or unusual characters are escaped and quoted. Otherwise, such
- * values are not allowed.
+ * values are not allowed. Mutually exclusive with KV_RAW.
*
* If KV_OMIT_KEYS is set in <b>flags</b>, then pairs with empty keys are
* allowed, and are encoded as 'Value'. Otherwise, such pairs are not
@@ -113,6 +115,11 @@ kvline_can_encode_lines(const config_line_t *line, unsigned flags)
* encoded as 'Key', not as 'Key=' or 'Key=""'. Mutually exclusive with
* KV_OMIT_KEYS.
*
+ * If KV_RAW is set in <b>flags</b>, then don't apply any quoting to
+ * the value, and assume that the caller has adequately quoted it.
+ * (The control protocol has some quirks that make this necessary.)
+ * Mutually exclusive with KV_QUOTED.
+ *
* KV_QUOTED_QSTRING is not supported.
*/
char *
@@ -121,11 +128,12 @@ kvline_encode(const config_line_t *line,
{
tor_assert(! (flags & KV_QUOTED_QSTRING));
- if (!kvline_can_encode_lines(line, flags))
- return NULL;
-
tor_assert((flags & (KV_OMIT_KEYS|KV_OMIT_VALS)) !=
(KV_OMIT_KEYS|KV_OMIT_VALS));
+ tor_assert((flags & (KV_QUOTED|KV_RAW)) != (KV_QUOTED|KV_RAW));
+
+ if (!kvline_can_encode_lines(line, flags))
+ return NULL;
smartlist_t *elements = smartlist_new();
@@ -142,15 +150,12 @@ kvline_encode(const config_line_t *line,
k = line->key;
} else {
eq = "";
- if (strchr(line->value, '=')) {
- esc = true;
- }
}
if ((flags & KV_OMIT_VALS) && line_has_no_val(line)) {
eq = "";
v = "";
- } else if (esc) {
+ } else if (!(flags & KV_RAW) && esc) {
tmp = esc_for_log(line->value);
v = tmp;
} else {
@@ -187,12 +192,15 @@ kvline_encode(const config_line_t *line,
* If KV_QUOTED_QSTRING is set in <b>flags</b>, then double-quoted values
* are allowed and handled as QuotedStrings per qstring.c. Do not add
* new users of this flag.
+ *
+ * KV_RAW is not supported.
*/
config_line_t *
kvline_parse(const char *line, unsigned flags)
{
tor_assert((flags & (KV_OMIT_KEYS|KV_OMIT_VALS)) !=
(KV_OMIT_KEYS|KV_OMIT_VALS));
+ tor_assert(!(flags & KV_RAW));
const char *cp = line, *cplast = NULL;
const bool omit_keys = (flags & KV_OMIT_KEYS) != 0;
diff --git a/src/lib/encoding/kvline.h b/src/lib/encoding/kvline.h
index dea2ce1809..9d36902ad1 100644
--- a/src/lib/encoding/kvline.h
+++ b/src/lib/encoding/kvline.h
@@ -19,6 +19,7 @@ struct config_line_t;
#define KV_OMIT_KEYS (1u<<1)
#define KV_OMIT_VALS (1u<<2)
#define KV_QUOTED_QSTRING (1u<<3)
+#define KV_RAW (1u<<4)
struct config_line_t *kvline_parse(const char *line, unsigned flags);
char *kvline_encode(const struct config_line_t *line, unsigned flags);
diff --git a/src/test/bt_test.py b/src/test/bt_test.py
index f9ca79efde..d728f13596 100755
--- a/src/test/bt_test.py
+++ b/src/test/bt_test.py
@@ -15,7 +15,11 @@ OK
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
diff --git a/src/test/ed25519_exts_ref.py b/src/test/ed25519_exts_ref.py
index 75562184b5..658f7cde12 100644
--- a/src/test/ed25519_exts_ref.py
+++ b/src/test/ed25519_exts_ref.py
@@ -8,6 +8,11 @@
Includes self-tester and test vector generator.
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import slow_ed25519
from slow_ed25519 import *
diff --git a/src/test/hs_build_address.py b/src/test/hs_build_address.py
index 7ff22c3a9a..91864eabcb 100644
--- a/src/test/hs_build_address.py
+++ b/src/test/hs_build_address.py
@@ -1,3 +1,8 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
import hashlib
import struct
diff --git a/src/test/hs_indexes.py b/src/test/hs_indexes.py
index af0b81f8de..5c6d893a66 100644
--- a/src/test/hs_indexes.py
+++ b/src/test/hs_indexes.py
@@ -7,6 +7,11 @@
# store/fetch the descriptor on the hashring. (hs_build_hs_index()).
#
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
import hashlib
import struct
diff --git a/src/test/hs_ntor_ref.py b/src/test/hs_ntor_ref.py
index 1b9772a5d6..f107cc36ca 100644
--- a/src/test/hs_ntor_ref.py
+++ b/src/test/hs_ntor_ref.py
@@ -41,6 +41,11 @@ The whole logic and concept for this test suite was taken from ntor_ref.py.
*** DO NOT USE THIS IN PRODUCTION. ***
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import struct
import os, sys
import binascii
diff --git a/src/test/ntor_ref.py b/src/test/ntor_ref.py
index 3e642eb257..e3307430e1 100755
--- a/src/test/ntor_ref.py
+++ b/src/test/ntor_ref.py
@@ -27,6 +27,11 @@ commands:
"""
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import binascii
try:
import curve25519
diff --git a/src/test/ope_ref.py b/src/test/ope_ref.py
index b2f7012563..61a86b57bb 100644
--- a/src/test/ope_ref.py
+++ b/src/test/ope_ref.py
@@ -4,6 +4,11 @@
# Reference implementation for our rudimentary OPE code, used to
# generate test vectors. See crypto_ope.c for more details.
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.backends import default_backend
diff --git a/src/test/slow_ed25519.py b/src/test/slow_ed25519.py
index f44708b200..afad678000 100644
--- a/src/test/slow_ed25519.py
+++ b/src/test/slow_ed25519.py
@@ -8,6 +8,11 @@
#
# Don't edit this file. Mess with ed25519_ref.py
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import hashlib
b = 256
diff --git a/src/test/slownacl_curve25519.py b/src/test/slownacl_curve25519.py
index 4dabab61b6..0cafe0e71f 100644
--- a/src/test/slownacl_curve25519.py
+++ b/src/test/slownacl_curve25519.py
@@ -6,10 +6,15 @@
# Nick got the slownacl source from:
# https://github.com/mdempsky/dnscurve/tree/master/slownacl
-__all__ = ['smult_curve25519_base', 'smult_curve25519']
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
import sys
+__all__ = ['smult_curve25519_base', 'smult_curve25519']
+
P = 2 ** 255 - 19
A = 486662
diff --git a/src/test/sr_commit_calc_ref.py b/src/test/sr_commit_calc_ref.py
index 45e629cfb0..c4cb72d87f 100644
--- a/src/test/sr_commit_calc_ref.py
+++ b/src/test/sr_commit_calc_ref.py
@@ -12,6 +12,11 @@
# COMMIT = base64-encode( TIMESTAMP || H(REVEAL) )
#
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
import hashlib
import struct
diff --git a/src/test/sr_srv_calc_ref.py b/src/test/sr_srv_calc_ref.py
index 492ca62b15..a3752b15cc 100644
--- a/src/test/sr_srv_calc_ref.py
+++ b/src/test/sr_srv_calc_ref.py
@@ -10,6 +10,11 @@
# HASHED_REVEALS | previous_SRV)
#
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
import sys
import hashlib
import struct
diff --git a/src/test/test_config.c b/src/test/test_config.c
index a75a862739..8f705da7e0 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -6050,6 +6050,36 @@ test_config_kvline_parse(void *arg)
tt_str_op(lines->next->next->value, OP_EQ, "I");
enc = kvline_encode(lines, KV_OMIT_VALS|KV_QUOTED);
tt_str_op(enc, OP_EQ, "AB=\"CD E\" DE FGH=I");
+ tor_free(enc);
+ config_free_lines(lines);
+
+ lines = kvline_parse("AB=CD \"EF=GH\"", KV_OMIT_KEYS|KV_QUOTED);
+ tt_assert(lines);
+ tt_str_op(lines->key, OP_EQ, "AB");
+ tt_str_op(lines->value, OP_EQ, "CD");
+ tt_str_op(lines->next->key, OP_EQ, "");
+ tt_str_op(lines->next->value, OP_EQ, "EF=GH");
+ enc = kvline_encode(lines, KV_OMIT_KEYS);
+ tt_assert(!enc);
+ enc = kvline_encode(lines, KV_OMIT_KEYS|KV_QUOTED);
+ tt_assert(enc);
+ tt_str_op(enc, OP_EQ, "AB=CD \"EF=GH\"");
+ tor_free(enc);
+ config_free_lines(lines);
+
+ lines = tor_malloc_zero(sizeof(*lines));
+ lines->key = tor_strdup("A=B");
+ lines->value = tor_strdup("CD");
+ enc = kvline_encode(lines, 0);
+ tt_assert(!enc);
+ config_free_lines(lines);
+
+ config_line_append(&lines, "A", "B C");
+ enc = kvline_encode(lines, 0);
+ tt_assert(!enc);
+ enc = kvline_encode(lines, KV_RAW);
+ tt_assert(enc);
+ tt_str_op(enc, OP_EQ, "A=B C");
done:
config_free_lines(lines);
diff --git a/src/test/test_controller.c b/src/test/test_controller.c
index d07ec5d0f0..b3023130ae 100644
--- a/src/test/test_controller.c
+++ b/src/test/test_controller.c
@@ -1957,6 +1957,76 @@ test_getinfo_md_all(void *arg)
return;
}
+static smartlist_t *reply_strs;
+
+static void
+mock_control_write_reply_list(control_connection_t *conn, int code, int c,
+ const char *s)
+{
+ (void)conn;
+ /* To make matching easier, don't append "\r\n" */
+ smartlist_add_asprintf(reply_strs, "%03d%c%s", code, c, s);
+}
+
+static void
+test_control_reply(void *arg)
+{
+ (void)arg;
+ smartlist_t *lines = smartlist_new();
+
+ MOCK(control_write_reply, mock_control_write_reply);
+
+ tor_free(reply_str);
+ control_reply_clear(lines);
+ control_reply_add_str(lines, 250, "FOO");
+ control_write_reply_lines(NULL, lines);
+ tt_str_op(reply_str, OP_EQ, "FOO");
+
+ tor_free(reply_str);
+ control_reply_clear(lines);
+ control_reply_add_done(lines);
+ control_write_reply_lines(NULL, lines);
+ tt_str_op(reply_str, OP_EQ, "OK");
+
+ tor_free(reply_str);
+ control_reply_clear(lines);
+ UNMOCK(control_write_reply);
+ MOCK(control_write_reply, mock_control_write_reply_list);
+ reply_strs = smartlist_new();
+ control_reply_add_one_kv(lines, 250, 0, "A", "B");
+ control_reply_add_one_kv(lines, 250, 0, "C", "D");
+ control_write_reply_lines(NULL, lines);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 2);
+ tt_str_op((char *)smartlist_get(reply_strs, 0), OP_EQ, "250-A=B");
+ tt_str_op((char *)smartlist_get(reply_strs, 1), OP_EQ, "250 C=D");
+
+ control_reply_clear(lines);
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_clear(reply_strs);
+ control_reply_add_printf(lines, 250, "PROTOCOLINFO %d", 1);
+ control_reply_add_one_kv(lines, 250, KV_OMIT_VALS|KV_RAW, "AUTH", "");
+ control_reply_append_kv(lines, "METHODS", "COOKIE");
+ control_reply_append_kv(lines, "COOKIEFILE", escaped("/tmp/cookie"));
+ control_reply_add_done(lines);
+ control_write_reply_lines(NULL, lines);
+ tt_int_op(smartlist_len(reply_strs), OP_EQ, 3);
+ tt_str_op((char *)smartlist_get(reply_strs, 0),
+ OP_EQ, "250-PROTOCOLINFO 1");
+ tt_str_op((char *)smartlist_get(reply_strs, 1),
+ OP_EQ, "250-AUTH METHODS=COOKIE COOKIEFILE=\"/tmp/cookie\"");
+ tt_str_op((char *)smartlist_get(reply_strs, 2),
+ OP_EQ, "250 OK");
+
+ done:
+ UNMOCK(control_write_reply);
+ tor_free(reply_str);
+ control_reply_free(lines);
+ if (reply_strs)
+ SMARTLIST_FOREACH(reply_strs, char *, p, tor_free(p));
+ smartlist_free(reply_strs);
+ return;
+}
+
#ifndef COCCI
#define PARSER_TEST(type) \
{ "parse/" #type, test_controller_parse_cmd, 0, &passthrough_setup, \
@@ -1989,5 +2059,6 @@ struct testcase_t controller_tests[] = {
{ "download_status_bridge", test_download_status_bridge, 0, NULL, NULL },
{ "current_time", test_current_time, 0, NULL, NULL },
{ "getinfo_md_all", test_getinfo_md_all, 0, NULL, NULL },
+ { "control_reply", test_control_reply, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c
index 97a6f259e3..dab0a8c609 100644
--- a/src/test/test_hs_control.c
+++ b/src/test/test_hs_control.c
@@ -528,6 +528,7 @@ test_hs_control_store_permanent_creds(void *arg)
{ /* Setup ClientOnionAuthDir */
int ret;
char *perm_creds_dir = tor_strdup(get_fname("permanent_credentials"));
+ get_options_mutable()->ClientOnionAuthDir = perm_creds_dir;
#ifdef _WIN32
ret = mkdir(perm_creds_dir);
@@ -535,8 +536,6 @@ test_hs_control_store_permanent_creds(void *arg)
ret = mkdir(perm_creds_dir, 0700);
#endif
tt_int_op(ret, OP_EQ, 0);
-
- get_options_mutable()->ClientOnionAuthDir = perm_creds_dir;
}
tor_free(args);
@@ -625,6 +624,7 @@ test_hs_control_store_permanent_creds(void *arg)
tt_uint_op(digest256map_size(client_auths), OP_EQ, 0);
done:
+ tor_free(get_options_mutable()->ClientOnionAuthDir);
tor_free(args);
tor_free(cp1);
buf_free(TO_CONN(&conn)->outbuf);
diff --git a/src/test/test_rebind.py b/src/test/test_rebind.py
index c9b9200b2d..3fc3deb68e 100644
--- a/src/test/test_rebind.py
+++ b/src/test/test_rebind.py
@@ -1,4 +1,7 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
from __future__ import print_function
+from __future__ import unicode_literals
import errno
import logging