From 1baa2703c36cf964d5fc1f07433196e8ccc0e55a Mon Sep 17 00:00:00 2001 From: rl1987 Date: Fri, 31 Aug 2018 20:05:54 +0300 Subject: Add changes file --- changes/bug23082 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/bug23082 (limited to 'changes') diff --git a/changes/bug23082 b/changes/bug23082 new file mode 100644 index 0000000000..fc4b52c364 --- /dev/null +++ b/changes/bug23082 @@ -0,0 +1,4 @@ + o Minor bugfixes (networking): + - Introduce additional checks into tor_addr_parse() to + reject certain incorrect inputs that previously were + not detected. Fixes bug 23082; bugfix on 0.2.0.10-alpha. -- cgit v1.2.3-54-g00ecf From 81a5448c187458ea3edcc0a72044a4cfdf0273bf Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 11 Sep 2018 11:54:37 -0400 Subject: Changes file for feature27244 --- changes/feature27244 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/feature27244 (limited to 'changes') diff --git a/changes/feature27244 b/changes/feature27244 new file mode 100644 index 0000000000..a4debbbe53 --- /dev/null +++ b/changes/feature27244 @@ -0,0 +1,5 @@ + o Minor features (memory usage): + - Tor clients no longer need to keep the full text of a consensus in + memory in order to parse it, or apply a diff to it. Instead, they + use mmap() to read the consensus files from disk. Closes ticket + 27244. -- cgit v1.2.3-54-g00ecf From 7e862c3ec029d3cdfdd07483e31843c8f3b48a68 Mon Sep 17 00:00:00 2001 From: teor Date: Sat, 15 Sep 2018 01:23:02 +1000 Subject: check-changes: Check bugfix version formatting Check that bugfix versions in changes files look like Tor versions from the versions spec. Part of ticket 27761. --- changes/ticket27761 | 3 +++ scripts/maint/lintChanges.py | 6 ++++++ 2 files changed, 9 insertions(+) create mode 100644 changes/ticket27761 (limited to 'changes') diff --git a/changes/ticket27761 b/changes/ticket27761 new file mode 100644 index 0000000000..ef4686bdca --- /dev/null +++ b/changes/ticket27761 @@ -0,0 +1,3 @@ + o Minor features (changelogs): + - Check that bugfix versions in changes files look like Tor versions + from the versions spec. Closes ticket 27761. diff --git a/scripts/maint/lintChanges.py b/scripts/maint/lintChanges.py index d5b8fcae5c..5c5d45da1d 100755 --- a/scripts/maint/lintChanges.py +++ b/scripts/maint/lintChanges.py @@ -87,6 +87,12 @@ def lintfile(fname): warn("Bugfix does not say 'Fixes bug X; bugfix on Y'") elif re.search('tor-([0-9]+)', contents): warn("Do not prefix versions with 'tor-'. ('0.1.2', not 'tor-0.1.2'.)") + else: + bugfix_match = re.search('bugfix on ([0-9]+\.[0-9]+\.[0-9]+)', contents) + if bugfix_match is None: + warn("Versions must have at least 3 digits. ('0.1.2', '0.3.4.8', or '0.3.5.1-alpha'.)") + elif bugfix_match.group(0) is None: + warn("Versions must have at least 3 digits. ('0.1.2', '0.3.4.8', or '0.3.5.1-alpha'.)") return have_warned != [] -- cgit v1.2.3-54-g00ecf From 3eafa61f6324c91b4bb8c02a6e54db0f12ef42c2 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 18 Sep 2018 20:39:03 +1000 Subject: check-changes: Warn about bugfixes on future releases Warn when bugfix changes files say that the bug is in a future release. Closes ticket 27761. --- Makefile.am | 2 +- changes/ticket27761 | 3 ++- scripts/maint/lintChanges.py | 50 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) (limited to 'changes') diff --git a/Makefile.am b/Makefile.am index 36a5dd2e9e..9a65e083a5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -408,7 +408,7 @@ endif check-changes: if USEPYTHON @if test -d "$(top_srcdir)/changes"; then \ - $(PYTHON) $(top_srcdir)/scripts/maint/lintChanges.py $(top_srcdir)/changes; \ + PACKAGE_VERSION=$(PACKAGE_VERSION) $(PYTHON) $(top_srcdir)/scripts/maint/lintChanges.py $(top_srcdir)/changes; \ fi endif diff --git a/changes/ticket27761 b/changes/ticket27761 index ef4686bdca..35106ee9c6 100644 --- a/changes/ticket27761 +++ b/changes/ticket27761 @@ -1,3 +1,4 @@ o Minor features (changelogs): - Check that bugfix versions in changes files look like Tor versions - from the versions spec. Closes ticket 27761. + from the versions spec. Warn when bugfixes claim to be on a future + release. Closes ticket 27761. diff --git a/scripts/maint/lintChanges.py b/scripts/maint/lintChanges.py index 5c5d45da1d..39fa08bb4a 100755 --- a/scripts/maint/lintChanges.py +++ b/scripts/maint/lintChanges.py @@ -35,6 +35,36 @@ NEEDS_SUBCATEGORIES = set([ "Major features", ]) +def split_tor_version(version): + ''' + Return the initial numeric components of the Tor version as a list of ints. + For versions earlier than 0.1.0, returns MAJOR, MINOR, and MICRO. + For versions 0.1.0 and later, returns MAJOR, MINOR, MICRO, and PATCHLEVEL if present. + + If the version is malformed, returns None. + ''' + version_match = re.search('([0-9]+)\.([0-9]+)\.([0-9]+)(\.([0-9]+))?', version) + if version_match is None: + return None + + version_groups = version_match.groups() + if version_groups is None: + return None + if len(version_groups) < 3: + return None + + if len(version_groups) != 5: + return None + version_components = version_groups[0:3] + version_components += version_groups[4:5] + + try: + version_list = [int(v) for v in version_components if v is not None] + except ValueError: + return None + + return version_list + def lintfile(fname): have_warned = [] @@ -93,6 +123,26 @@ def lintfile(fname): warn("Versions must have at least 3 digits. ('0.1.2', '0.3.4.8', or '0.3.5.1-alpha'.)") elif bugfix_match.group(0) is None: warn("Versions must have at least 3 digits. ('0.1.2', '0.3.4.8', or '0.3.5.1-alpha'.)") + else: + bugfix_match = re.search('bugfix on ([0-9a-z][-.0-9a-z]+[0-9a-z])', contents) + bugfix_group = bugfix_match.groups(0) if bugfix_match is not None else None + bugfix_version = bugfix_group[0] if bugfix_group is not None else None + package_version = os.environ.get('PACKAGE_VERSION', None) + if bugfix_version is None: + # This should be unreachable, unless the patterns are out of sync + warn("Malformed bugfix version.") + elif package_version is not None: + # If $PACKAGE_VERSION isn't set, skip this check + bugfix_split = split_tor_version(bugfix_version) + package_split = split_tor_version(package_version) + if bugfix_split is None: + # This should be unreachable, unless the patterns are out of sync + warn("Malformed bugfix version: '{}'.".format(bugfix_version)) + elif package_split is None: + # This should be unreachable, unless the patterns are out of sync, or the package versioning scheme has changed + warn("Malformed $PACKAGE_VERSION: '{}'.".format(package_version)) + elif bugfix_split > package_split: + warn("Bugfixes must be made on earlier versions (or this version). (Bugfix on version: '{}', current tor package version: '{}'.)".format(bugfix_version, package_version)) return have_warned != [] -- cgit v1.2.3-54-g00ecf From 8b5ad246e81a8346b79d37052320753f87e22a04 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Thu, 11 Oct 2018 20:28:11 +0300 Subject: Fix issues that shellcheck found in chutney-git-bisect.sh --- changes/ticket28006 | 3 +++ scripts/test/chutney-git-bisect.sh | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 changes/ticket28006 (limited to 'changes') diff --git a/changes/ticket28006 b/changes/ticket28006 new file mode 100644 index 0000000000..95a4b2cae4 --- /dev/null +++ b/changes/ticket28006 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Fix issues that shellcheck found in chutney-git-bisect.sh. + Resolves ticket 28006. diff --git a/scripts/test/chutney-git-bisect.sh b/scripts/test/chutney-git-bisect.sh index 8a3f2c70c8..dc1319a27a 100755 --- a/scripts/test/chutney-git-bisect.sh +++ b/scripts/test/chutney-git-bisect.sh @@ -20,7 +20,7 @@ if [ ! -z "$1" ]; then fi if [ ! -z "$2" ]; then - cd "$2" + cd "$2" || exit fi CHUTNEY_TEST_CMD="make test-network-all" @@ -54,9 +54,9 @@ while [ "$i" -le "$CHUTNEY_TRIES" ]; do echo "test '$CHUTNEY_TEST_CMD' succeeded after $i/$CHUTNEY_TRIES attempts, good" exit 0 fi - i=$[$i+1] + i=$((i+1)) done -i=$[$i-1] +i=$((i-1)) echo "test '$CHUTNEY_TEST_CMD' failed $i/$CHUTNEY_TRIES attempts, bad" exit 1 -- cgit v1.2.3-54-g00ecf From 65864be9bc59fb3743d2cebf497d0a4268596f95 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Tue, 16 Oct 2018 17:53:17 +0300 Subject: Add changes file --- changes/ticket27625 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket27625 (limited to 'changes') diff --git a/changes/ticket27625 b/changes/ticket27625 new file mode 100644 index 0000000000..33d40adf34 --- /dev/null +++ b/changes/ticket27625 @@ -0,0 +1,4 @@ + o Testing: + - Write some unit tests for tokenize_string() and + get_next_token() functions. Resolves ticket 27625. + -- cgit v1.2.3-54-g00ecf From 2f0744b3e6f579f25db1ed6e048d0418ac2ab570 Mon Sep 17 00:00:00 2001 From: cypherpunks Date: Wed, 17 Oct 2018 00:16:21 +0000 Subject: rust/tor_util: drop unsafe block in cstr! This is unnecessary just to get an empty string, there's Default::default(). Fix on 8fff331bb095dc6f5e2fe2ecfc9ab08ea9e2fe97. --- changes/ticket28077 | 3 +++ src/rust/tor_util/strings.rs | 6 +----- 2 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 changes/ticket28077 (limited to 'changes') diff --git a/changes/ticket28077 b/changes/ticket28077 new file mode 100644 index 0000000000..2b5afb1678 --- /dev/null +++ b/changes/ticket28077 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Remove unnecessarily unsafe code from the rust macro cstr!. Closes + ticket 28077. diff --git a/src/rust/tor_util/strings.rs b/src/rust/tor_util/strings.rs index d64275e06b..71a908a58c 100644 --- a/src/rust/tor_util/strings.rs +++ b/src/rust/tor_util/strings.rs @@ -105,11 +105,7 @@ macro_rules! cstr { ($($bytes:expr),*) => ( ::std::ffi::CStr::from_bytes_with_nul( concat!($($bytes),*, "\0").as_bytes() - ).unwrap_or( - unsafe{ - ::std::ffi::CStr::from_bytes_with_nul_unchecked(b"\0") - } - ) + ).unwrap_or_default() ) } -- cgit v1.2.3-54-g00ecf From 3a8f32067d1cb4d5aee320fbd3d1c02541f4e112 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 18 Sep 2018 13:50:12 -0400 Subject: hs-v3: Consolidate descriptor cookie computation code Both client and service had their own code for this. Consolidate into one place so we avoid duplication. Closes #27549 Signed-off-by: David Goulet --- changes/ticket27549 | 3 ++ src/feature/hs/hs_descriptor.c | 89 +++++++++++++++++++++++++++--------------- 2 files changed, 61 insertions(+), 31 deletions(-) create mode 100644 changes/ticket27549 (limited to 'changes') diff --git a/changes/ticket27549 b/changes/ticket27549 new file mode 100644 index 0000000000..51d0f24757 --- /dev/null +++ b/changes/ticket27549 @@ -0,0 +1,3 @@ + o Code simplification and refactoring (hidden service v3): + - Consolidate the authorized client descriptor cookie computation code + from client and service into one function. Closes ticket 27549. diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c index d0cdffdf10..1232182ea5 100644 --- a/src/feature/hs/hs_descriptor.c +++ b/src/feature/hs/hs_descriptor.c @@ -1400,6 +1400,49 @@ encrypted_data_length_is_valid(size_t len) return 0; } +/* Build the KEYS component for the authorized client computation. The format + * of the construction is: + * + * SECRET_SEED = x25519(sk, pk) + * KEYS = KDF(subcredential | SECRET_SEED, 40) + * + * The keys_out parameter will points to the buffer containing the KEYS. The + * caller should wipe and free its content once done with it. This function + * can't fail. */ +static void +build_descriptor_cookie_keys(const uint8_t *subcredential, + size_t subcredential_len, + const curve25519_secret_key_t *sk, + const curve25519_public_key_t *pk, + uint8_t **keys_out) +{ + uint8_t secret_seed[CURVE25519_OUTPUT_LEN]; + uint8_t *keystream; + size_t keystream_len = HS_DESC_CLIENT_ID_LEN + HS_DESC_COOKIE_KEY_LEN; + crypto_xof_t *xof; + + tor_assert(subcredential); + tor_assert(sk); + tor_assert(pk); + tor_assert(keys_out); + + keystream = tor_malloc_zero(keystream_len); + + /* Calculate x25519(sk, pk) to get the secret seed. */ + curve25519_handshake(secret_seed, sk, pk); + + /* Calculate KEYS = KDF(subcredential | SECRET_SEED, 40) */ + xof = crypto_xof_new(); + crypto_xof_add_bytes(xof, subcredential, subcredential_len); + crypto_xof_add_bytes(xof, secret_seed, sizeof(secret_seed)); + crypto_xof_squeeze_bytes(xof, keystream, keystream_len); + crypto_xof_free(xof); + + memwipe(secret_seed, 0, sizeof(secret_seed)); + + *keys_out = keystream; +} + /* Decrypt the descriptor cookie given the descriptor, the auth client, * and the client secret key. On sucess, return 0 and a newly allocated * descriptor cookie descriptor_cookie_out. On error or if the client id @@ -1412,12 +1455,10 @@ decrypt_descriptor_cookie(const hs_descriptor_t *desc, uint8_t **descriptor_cookie_out) { int ret = -1; - uint8_t secret_seed[CURVE25519_OUTPUT_LEN]; - uint8_t keystream[HS_DESC_CLIENT_ID_LEN + HS_DESC_COOKIE_KEY_LEN]; - uint8_t *cookie_key = NULL; + uint8_t *keystream = NULL; uint8_t *descriptor_cookie = NULL; + const uint8_t *cookie_key = NULL; crypto_cipher_t *cipher = NULL; - crypto_xof_t *xof = NULL; tor_assert(desc); tor_assert(client); @@ -1429,16 +1470,11 @@ decrypt_descriptor_cookie(const hs_descriptor_t *desc, sizeof(*client_auth_sk))); tor_assert(!tor_mem_is_zero((char *) desc->subcredential, DIGEST256_LEN)); - /* Calculate x25519(client_x, hs_Y) */ - curve25519_handshake(secret_seed, client_auth_sk, - &desc->superencrypted_data.auth_ephemeral_pubkey); - - /* Calculate KEYS = KDF(subcredential | SECRET_SEED, 40) */ - xof = crypto_xof_new(); - crypto_xof_add_bytes(xof, desc->subcredential, DIGEST256_LEN); - crypto_xof_add_bytes(xof, secret_seed, sizeof(secret_seed)); - crypto_xof_squeeze_bytes(xof, keystream, sizeof(keystream)); - crypto_xof_free(xof); + /* Get the KEYS component to derive the CLIENT-ID and COOKIE-KEY. */ + build_descriptor_cookie_keys(desc->subcredential, DIGEST256_LEN, + client_auth_sk, + &desc->superencrypted_data.auth_ephemeral_pubkey, + &keystream); /* If the client id of auth client is not the same as the calculcated * client id, it means that this auth client is invaild according to the @@ -1464,8 +1500,8 @@ decrypt_descriptor_cookie(const hs_descriptor_t *desc, if (cipher) { crypto_cipher_free(cipher); } - memwipe(secret_seed, 0, sizeof(secret_seed)); memwipe(keystream, 0, sizeof(keystream)); + tor_free(keystream); return ret; } @@ -2864,11 +2900,9 @@ hs_desc_build_authorized_client(const uint8_t *subcredential, const uint8_t *descriptor_cookie, hs_desc_authorized_client_t *client_out) { - uint8_t secret_seed[CURVE25519_OUTPUT_LEN]; - uint8_t keystream[HS_DESC_CLIENT_ID_LEN + HS_DESC_COOKIE_KEY_LEN]; - uint8_t *cookie_key; + uint8_t *keystream = NULL; + const uint8_t *cookie_key; crypto_cipher_t *cipher; - crypto_xof_t *xof; tor_assert(client_auth_pk); tor_assert(auth_ephemeral_sk); @@ -2884,18 +2918,11 @@ hs_desc_build_authorized_client(const uint8_t *subcredential, tor_assert(!tor_mem_is_zero((char *) subcredential, DIGEST256_LEN)); - /* Calculate x25519(hs_y, client_X) */ - curve25519_handshake(secret_seed, - auth_ephemeral_sk, - client_auth_pk); - - /* Calculate KEYS = KDF(subcredential | SECRET_SEED, 40) */ - xof = crypto_xof_new(); - crypto_xof_add_bytes(xof, subcredential, DIGEST256_LEN); - crypto_xof_add_bytes(xof, secret_seed, sizeof(secret_seed)); - crypto_xof_squeeze_bytes(xof, keystream, sizeof(keystream)); - crypto_xof_free(xof); + /* Get the KEYS part so we can derive the CLIENT-ID and COOKIE-KEY. */ + build_descriptor_cookie_keys(subcredential, DIGEST256_LEN, + auth_ephemeral_sk, client_auth_pk, &keystream); + /* Extract the CLIENT-ID and COOKIE-KEY from the KEYS. */ memcpy(client_out->client_id, keystream, HS_DESC_CLIENT_ID_LEN); cookie_key = keystream + HS_DESC_CLIENT_ID_LEN; @@ -2910,8 +2937,8 @@ hs_desc_build_authorized_client(const uint8_t *subcredential, (const char *) descriptor_cookie, HS_DESC_DESCRIPTOR_COOKIE_LEN); - memwipe(secret_seed, 0, sizeof(secret_seed)); memwipe(keystream, 0, sizeof(keystream)); + tor_free(keystream); crypto_cipher_free(cipher); } -- cgit v1.2.3-54-g00ecf From 1a1b088f8cab73ca258c35e83d21df900f8e2e32 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Mon, 13 Aug 2018 19:05:40 +0300 Subject: Add changes file --- changes/bug21900 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/bug21900 (limited to 'changes') diff --git a/changes/bug21900 b/changes/bug21900 new file mode 100644 index 0000000000..686cb6c584 --- /dev/null +++ b/changes/bug21900 @@ -0,0 +1,4 @@ + o Minor bugfixes (DNS): + - Gracefully handle empty or absent resolve.conf file by falling + back to using localhost DNS service and hoping it works. Fixes + bug 21900; bugfix on 0.2.1.10-alpha. -- cgit v1.2.3-54-g00ecf From f874ab26401ca269074963697ddcad879b3b4e3a Mon Sep 17 00:00:00 2001 From: cypherpunks Date: Wed, 29 Aug 2018 08:49:10 +0000 Subject: dircache: make dirauths reject non UTF-8 descriptors and extrainfo Ticket #27367. --- changes/feature27367 | 4 ++++ src/feature/dirauth/process_descs.c | 12 +++++++++--- src/feature/dirauth/process_descs.h | 3 ++- src/feature/dircache/dircache.c | 4 ++-- 4 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 changes/feature27367 (limited to 'changes') diff --git a/changes/feature27367 b/changes/feature27367 new file mode 100644 index 0000000000..99c0839621 --- /dev/null +++ b/changes/feature27367 @@ -0,0 +1,4 @@ + o Minor features (parsing): + - Directory authorities now validate that router descriptors and ExtraInfo + documents are in a valid subset of UTF-8, and reject them if not. + Closes ticket 27367. diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c index c379f25bdd..dca87b3eaf 100644 --- a/src/feature/dirauth/process_descs.c +++ b/src/feature/dirauth/process_descs.c @@ -519,7 +519,8 @@ WRA_MORE_SEVERE(was_router_added_t a, was_router_added_t b) /** As for dirserv_add_descriptor(), but accepts multiple documents, and * returns the most severe error that occurred for any one of them. */ was_router_added_t -dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose, +dirserv_add_multiple_descriptors(const char *desc, size_t desclen, + uint8_t purpose, const char *source, const char **msg) { @@ -536,6 +537,11 @@ dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose, r=ROUTER_ADDED_SUCCESSFULLY; /*Least severe return value. */ + if (!string_is_utf8_no_bom(desc, desclen)) { + *msg = "descriptor(s) or extrainfo(s) not valid UTF-8 or had BOM."; + return ROUTER_AUTHDIR_REJECTS; + } + format_iso_time(time_buf, now); if (tor_snprintf(annotation_buf, sizeof(annotation_buf), "@uploaded-at %s\n" @@ -552,7 +558,7 @@ dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose, s = desc; list = smartlist_new(); - if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 0, 0, + if (!router_parse_list_from_string(&s, s+desclen, list, SAVED_NOWHERE, 0, 0, annotation_buf, NULL)) { SMARTLIST_FOREACH(list, routerinfo_t *, ri, { msg_out = NULL; @@ -568,7 +574,7 @@ dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose, smartlist_clear(list); s = desc; - if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 1, 0, + if (!router_parse_list_from_string(&s, s+desclen, list, SAVED_NOWHERE, 1, 0, NULL, NULL)) { SMARTLIST_FOREACH(list, extrainfo_t *, ei, { msg_out = NULL; diff --git a/src/feature/dirauth/process_descs.h b/src/feature/dirauth/process_descs.h index ad9d5c3d4c..5a0914acd8 100644 --- a/src/feature/dirauth/process_descs.h +++ b/src/feature/dirauth/process_descs.h @@ -17,7 +17,8 @@ void dirserv_free_fingerprint_list(void); int dirserv_add_own_fingerprint(crypto_pk_t *pk); enum was_router_added_t dirserv_add_multiple_descriptors( - const char *desc, uint8_t purpose, + const char *desc, size_t desclen, + uint8_t purpose, const char *source, const char **msg); enum was_router_added_t dirserv_add_descriptor(routerinfo_t *ri, diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c index 872a88018f..930a8b87ef 100644 --- a/src/feature/dircache/dircache.c +++ b/src/feature/dircache/dircache.c @@ -1608,8 +1608,8 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers, const char *msg = "[None]"; uint8_t purpose = authdir_mode_bridge(options) ? ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL; - was_router_added_t r = dirserv_add_multiple_descriptors(body, purpose, - conn->base_.address, &msg); + was_router_added_t r = dirserv_add_multiple_descriptors(body, body_len, + purpose, conn->base_.address, &msg); tor_assert(msg); if (r == ROUTER_ADDED_SUCCESSFULLY) { -- cgit v1.2.3-54-g00ecf From b64e1e602bac5e108e40a284616e3fe7f7597b17 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sat, 22 Sep 2018 20:01:15 +0300 Subject: Add changes file --- changes/ticket27325 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket27325 (limited to 'changes') diff --git a/changes/ticket27325 b/changes/ticket27325 new file mode 100644 index 0000000000..2cf2bb7d69 --- /dev/null +++ b/changes/ticket27325 @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Reimplement NETINFO cell parsing and generation to rely on + trunnel-generated wire format handling code. Closes ticket + 27325. -- cgit v1.2.3-54-g00ecf From 4af27e016814f4817174ed87e7b660d65c6eaf9c Mon Sep 17 00:00:00 2001 From: rl1987 Date: Mon, 29 Oct 2018 11:05:55 +0200 Subject: Add changes file --- changes/ticket28010 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket28010 (limited to 'changes') diff --git a/changes/ticket28010 b/changes/ticket28010 new file mode 100644 index 0000000000..4fca17d022 --- /dev/null +++ b/changes/ticket28010 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Fix shellcheck warnings in run_trunnel.sh. Resolves issue + 28010. -- cgit v1.2.3-54-g00ecf From 5a3cb495ce5bf010440fc0288c1ca00fff6ec8e5 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Mon, 29 Oct 2018 11:41:36 +0200 Subject: Add changes file --- changes/ticket28011 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket28011 (limited to 'changes') diff --git a/changes/ticket28011 b/changes/ticket28011 new file mode 100644 index 0000000000..5efc3c917b --- /dev/null +++ b/changes/ticket28011 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Fix shellcheck warnings in run_calltool.sh. Resolves + ticket 28011. -- cgit v1.2.3-54-g00ecf From 067b16eae2b7d37c7ec1595226bc7bf26aac1ff5 Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Wed, 5 Sep 2018 10:12:35 -0400 Subject: Check IPv6 subnets as well as IPv4 subnets where possible when choosing client paths --- changes/bug24393 | 6 ++++++ src/feature/nodelist/nodelist.c | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 changes/bug24393 (limited to 'changes') diff --git a/changes/bug24393 b/changes/bug24393 new file mode 100644 index 0000000000..e190192319 --- /dev/null +++ b/changes/bug24393 @@ -0,0 +1,6 @@ + o Minor features (ipv6): + - When using addrs_in_same_network_family(), check IPv6 subnets as well as + IPv4 ones where possible when a client chooses circuit paths. Previously, + we used this function only for IPv4 subnets. Closes ticket 24393. Patch + by Neel Chauhan. + diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c index a98a5c8655..a1a1b0ea37 100644 --- a/src/feature/nodelist/nodelist.c +++ b/src/feature/nodelist/nodelist.c @@ -1867,6 +1867,9 @@ int addrs_in_same_network_family(const tor_addr_t *a1, const tor_addr_t *a2) { + if (tor_addr_is_null(a1) || tor_addr_is_null(a2)) + return 0; + switch (tor_addr_family(a1)) { case AF_INET: return 0 == tor_addr_compare_masked(a1, a2, 16, CMP_SEMANTIC); @@ -1917,7 +1920,13 @@ nodes_in_same_family(const node_t *node1, const node_t *node2) tor_addr_t a1, a2; node_get_addr(node1, &a1); node_get_addr(node2, &a2); - if (addrs_in_same_network_family(&a1, &a2)) + + tor_addr_port_t ap6_1, ap6_2; + node_get_pref_ipv6_orport(node1, &ap6_1); + node_get_pref_ipv6_orport(node2, &ap6_2); + + if (addrs_in_same_network_family(&a1, &a2) || + addrs_in_same_network_family(&ap6_1.addr, &ap6_2.addr)) return 1; } @@ -1974,12 +1983,17 @@ nodelist_add_node_and_family(smartlist_t *sl, const node_t *node) /* First, add any nodes with similar network addresses. */ if (options->EnforceDistinctSubnets) { tor_addr_t node_addr; + tor_addr_port_t node_ap6; node_get_addr(node, &node_addr); + node_get_pref_ipv6_orport(node, &node_ap6); SMARTLIST_FOREACH_BEGIN(all_nodes, const node_t *, node2) { tor_addr_t a; + tor_addr_port_t ap6; node_get_addr(node2, &a); - if (addrs_in_same_network_family(&a, &node_addr)) + node_get_pref_ipv6_orport(node2, &ap6); + if (addrs_in_same_network_family(&a, &node_addr) || + addrs_in_same_network_family(&ap6.addr, &node_ap6.addr)) smartlist_add(sl, (void*)node2); } SMARTLIST_FOREACH_END(node2); } -- cgit v1.2.3-54-g00ecf From a0402c6f33206468f57c381c0022e547520d14c2 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 1 Nov 2018 12:37:17 +0200 Subject: Add changes file for #27707. --- changes/bug27707 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/bug27707 (limited to 'changes') diff --git a/changes/bug27707 b/changes/bug27707 new file mode 100644 index 0000000000..e114222741 --- /dev/null +++ b/changes/bug27707 @@ -0,0 +1,3 @@ + o Minor features (log messages): + - Improve log message in HSv3 service that could print out negative + revision counters. Closes ticket 27707. Patch by "ffmancera". \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 1b75de85b3cbc7706078a9899e483d18579a6fd1 Mon Sep 17 00:00:00 2001 From: "Alex Xu (Hello71)" Date: Fri, 19 Oct 2018 09:53:23 -0400 Subject: Don't overwrite the Content-Type when compressing --- changes/ticket28100 | 3 +++ src/feature/dircache/dircache.c | 14 ++++---------- 2 files changed, 7 insertions(+), 10 deletions(-) create mode 100644 changes/ticket28100 (limited to 'changes') diff --git a/changes/ticket28100 b/changes/ticket28100 new file mode 100644 index 0000000000..b8e3271013 --- /dev/null +++ b/changes/ticket28100 @@ -0,0 +1,3 @@ + o Minor features (HTTP standards compliance): + - Don't send Content-Type: application/octet-stream for transparently + compressed documents, which confused browsers. Closes ticket 28100. diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c index 872a88018f..dff4b85caa 100644 --- a/src/feature/dircache/dircache.c +++ b/src/feature/dircache/dircache.c @@ -166,22 +166,16 @@ write_http_response_header_impl(dir_connection_t *conn, ssize_t length, buf_free(buf); } -/** As write_http_response_header_impl, but sets encoding and content-typed - * based on whether the response will be compressed or not. */ +/** As write_http_response_header_impl, but translates method into + * encoding */ static void write_http_response_headers(dir_connection_t *conn, ssize_t length, compress_method_t method, const char *extra_headers, long cache_lifetime) { - const char *methodname = compression_method_get_name(method); - const char *doctype; - if (method == NO_METHOD) - doctype = "text/plain"; - else - doctype = "application/octet-stream"; write_http_response_header_impl(conn, length, - doctype, - methodname, + "text/plain", + compression_method_get_name(method), extra_headers, cache_lifetime); } -- cgit v1.2.3-54-g00ecf From 45b28167d7e2b1d5afb26db6f76ca2329a9bbc04 Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Wed, 17 Oct 2018 21:43:59 -0400 Subject: In count_acceptable_nodes(), count direct and indirect nodes with node_has_preferred_descriptor() --- changes/bug25885 | 7 +++++++ src/core/or/circuitbuild.c | 21 ++++++++++++--------- src/core/or/circuitbuild.h | 3 ++- src/test/test_circuitbuild.c | 4 ++-- 4 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 changes/bug25885 (limited to 'changes') diff --git a/changes/bug25885 b/changes/bug25885 new file mode 100644 index 0000000000..1b89acfe06 --- /dev/null +++ b/changes/bug25885 @@ -0,0 +1,7 @@ + o Minor bugfixes (guards): + - In count_acceptable_nodes(), check if we have at least one bridge + or guard node, and two non-guard nodes for a circuit. Previously, + we have added up the sum of all nodes with a descriptor, but that + could cause us to build circuits that fail if we had either too + many bridges, or not enough guard nodes. Fixes bug 25885; bugfix + on 0.3.6.1-alpha. Patch by Neel Chauhan. diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c index a69457571e..4f9f09bc8f 100644 --- a/src/core/or/circuitbuild.c +++ b/src/core/or/circuitbuild.c @@ -1658,22 +1658,25 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei) STATIC int new_route_len(uint8_t purpose, extend_info_t *exit_ei, smartlist_t *nodes) { - int num_acceptable_routers; int routelen; tor_assert(nodes); routelen = route_len_for_purpose(purpose, exit_ei); - num_acceptable_routers = count_acceptable_nodes(nodes); + int num_acceptable_direct = count_acceptable_nodes(nodes, 1); + int num_acceptable_indirect = count_acceptable_nodes(nodes, 0); - log_debug(LD_CIRC,"Chosen route length %d (%d/%d routers suitable).", - routelen, num_acceptable_routers, smartlist_len(nodes)); + log_debug(LD_CIRC,"Chosen route length %d (%d direct and %d indirect " + "routers suitable).", routelen, num_acceptable_direct, + num_acceptable_indirect); - if (num_acceptable_routers < routelen) { + if (num_acceptable_direct < 1 || num_acceptable_indirect < routelen - 1) { log_info(LD_CIRC, - "Not enough acceptable routers (%d/%d). Discarding this circuit.", - num_acceptable_routers, routelen); + "Not enough acceptable routers (%d/%d direct and %d/%d " + "indirect routers suitable). Discarding this circuit.", + num_acceptable_direct, routelen, + num_acceptable_indirect, routelen); return -1; } @@ -2315,7 +2318,7 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit_ei) * particular router. See bug #25885.) */ MOCK_IMPL(STATIC int, -count_acceptable_nodes, (smartlist_t *nodes)) +count_acceptable_nodes, (smartlist_t *nodes, int direct)) { int num=0; @@ -2329,7 +2332,7 @@ count_acceptable_nodes, (smartlist_t *nodes)) if (! node->is_valid) // log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i); continue; - if (! node_has_any_descriptor(node)) + if (! node_has_preferred_descriptor(node, direct)) continue; /* The node has a descriptor, so we can just check the ntor key directly */ if (!node_has_curve25519_onion_key(node)) diff --git a/src/core/or/circuitbuild.h b/src/core/or/circuitbuild.h index cee71b297b..93f903f060 100644 --- a/src/core/or/circuitbuild.h +++ b/src/core/or/circuitbuild.h @@ -84,7 +84,8 @@ void circuit_upgrade_circuits_from_guard_wait(void); STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan); STATIC int new_route_len(uint8_t purpose, extend_info_t *exit_ei, smartlist_t *nodes); -MOCK_DECL(STATIC int, count_acceptable_nodes, (smartlist_t *nodes)); +MOCK_DECL(STATIC int, count_acceptable_nodes, (smartlist_t *nodes, + int direct)); STATIC int onion_extend_cpath(origin_circuit_t *circ); diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c index 02eadecd98..dd47ad7689 100644 --- a/src/test/test_circuitbuild.c +++ b/src/test/test_circuitbuild.c @@ -21,11 +21,11 @@ static smartlist_t dummy_nodes; static extend_info_t dummy_ei; static int -mock_count_acceptable_nodes(smartlist_t *nodes) +mock_count_acceptable_nodes(smartlist_t *nodes, int direct) { (void)nodes; - return DEFAULT_ROUTE_LEN + 1; + return direct ? 1 : DEFAULT_ROUTE_LEN + 1; } /* Test route lengths when the caller of new_route_len() doesn't -- cgit v1.2.3-54-g00ecf From adecda753996611e9a5b82c5fa87ea78ec683806 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 5 Nov 2018 09:42:16 -0500 Subject: changes file for subsystems api (28330) --- changes/subsystems | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/subsystems (limited to 'changes') diff --git a/changes/subsystems b/changes/subsystems new file mode 100644 index 0000000000..a51fb8e2b1 --- /dev/null +++ b/changes/subsystems @@ -0,0 +1,6 @@ + o Major features (refactoring): + - Tor now uses an explicit list of its own subsystems when initializing + and shutting down. Previously, these systems were managed implicitly + though various places throughout the codebase. (There still some + subsystems using the old system.) + Closes ticket 28330. -- cgit v1.2.3-54-g00ecf From 6d93820499a8bfb19128759893b18c1437f99c6b Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 19 Oct 2018 15:04:45 -0400 Subject: Memoize summarize_protover_flags() Our tests showed that this function is responsible for a huge number of our malloc/free() calls. It's a prime candidate for being memoized. Closes ticket 27225. --- changes/ticket27225 | 5 +++ src/app/main/main.c | 2 ++ src/core/or/versions.c | 82 +++++++++++++++++++++++++++++++++++++++++--------- src/core/or/versions.h | 2 ++ 4 files changed, 76 insertions(+), 15 deletions(-) create mode 100644 changes/ticket27225 (limited to 'changes') diff --git a/changes/ticket27225 b/changes/ticket27225 new file mode 100644 index 0000000000..4c05a269d6 --- /dev/null +++ b/changes/ticket27225 @@ -0,0 +1,5 @@ + o Minor features (performance): + - Avoid parsing the same protocol-versions string over and over + in summarize_protover_flags(). This should save us a huge number + of malloc calls on startup, and may reduce memory fragmentation with + some allocators. Closes ticket 27225. diff --git a/src/app/main/main.c b/src/app/main/main.c index ae87add67d..04bbfadcb7 100644 --- a/src/app/main/main.c +++ b/src/app/main/main.c @@ -33,6 +33,7 @@ #include "core/or/relay.h" #include "core/or/scheduler.h" #include "core/or/status.h" +#include "core/or/versions.h" #include "feature/api/tor_api.h" #include "feature/api/tor_api_internal.h" #include "feature/client/addressmap.h" @@ -791,6 +792,7 @@ tor_free_all(int postfork) dos_free_all(); circuitmux_ewma_free_all(); accounting_free_all(); + protover_summary_cache_free_all(); if (!postfork) { config_free_all(); diff --git a/src/core/or/versions.c b/src/core/or/versions.c index 06274996a7..6f8eea7a67 100644 --- a/src/core/or/versions.c +++ b/src/core/or/versions.c @@ -377,6 +377,62 @@ sort_version_list(smartlist_t *versions, int remove_duplicates) smartlist_uniq(versions, compare_tor_version_str_ptr_, tor_free_); } +/** If there are more than this many entries, we're probably under + * some kind of weird DoS. */ +static const int MAX_PROTOVER_SUMMARY_MAP_LEN = 1024; + +/** + * Map from protover string to protover_summary_flags_t. + */ +static strmap_t *protover_summary_map = NULL; + +/** + * Helper. Given a non-NULL protover string protocols, set out + * to its summary, and memoize the result in protover_summary_map. + */ +static void +memoize_protover_summary(protover_summary_flags_t *out, + const char *protocols) +{ + if (!protover_summary_map) + protover_summary_map = strmap_new(); + + if (strmap_size(protover_summary_map) >= MAX_PROTOVER_SUMMARY_MAP_LEN) { + protover_summary_cache_free_all(); + } + + const protover_summary_flags_t *cached = + strmap_get(protover_summary_map, protocols); + + if (cached != NULL) { + /* We found a cached entry; no need to parse this one. */ + memcpy(out, cached, sizeof(protover_summary_flags_t)); + tor_assert(out->protocols_known); + return; + } + + memset(out, 0, sizeof(*out)); + out->protocols_known = 1; + out->supports_extend2_cells = + protocol_list_supports_protocol(protocols, PRT_RELAY, 2); + out->supports_ed25519_link_handshake_compat = + protocol_list_supports_protocol(protocols, PRT_LINKAUTH, 3); + out->supports_ed25519_link_handshake_any = + protocol_list_supports_protocol_or_later(protocols, PRT_LINKAUTH, 3); + out->supports_ed25519_hs_intro = + protocol_list_supports_protocol(protocols, PRT_HSINTRO, 4); + out->supports_v3_hsdir = + protocol_list_supports_protocol(protocols, PRT_HSDIR, + PROTOVER_HSDIR_V3); + out->supports_v3_rendezvous_point = + protocol_list_supports_protocol(protocols, PRT_HSREND, + PROTOVER_HS_RENDEZVOUS_POINT_V3); + + protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out)); + cached = strmap_set(protover_summary_map, protocols, new_cached); + tor_assert(!cached); +} + /** Summarize the protocols listed in protocols into out, * falling back or correcting them based on version as appropriate. */ @@ -388,21 +444,7 @@ summarize_protover_flags(protover_summary_flags_t *out, tor_assert(out); memset(out, 0, sizeof(*out)); if (protocols) { - out->protocols_known = 1; - out->supports_extend2_cells = - protocol_list_supports_protocol(protocols, PRT_RELAY, 2); - out->supports_ed25519_link_handshake_compat = - protocol_list_supports_protocol(protocols, PRT_LINKAUTH, 3); - out->supports_ed25519_link_handshake_any = - protocol_list_supports_protocol_or_later(protocols, PRT_LINKAUTH, 3); - out->supports_ed25519_hs_intro = - protocol_list_supports_protocol(protocols, PRT_HSINTRO, 4); - out->supports_v3_hsdir = - protocol_list_supports_protocol(protocols, PRT_HSDIR, - PROTOVER_HSDIR_V3); - out->supports_v3_rendezvous_point = - protocol_list_supports_protocol(protocols, PRT_HSREND, - PROTOVER_HS_RENDEZVOUS_POINT_V3); + memoize_protover_summary(out, protocols); } if (version && !strcmpstart(version, "Tor ")) { if (!out->protocols_known) { @@ -420,3 +462,13 @@ summarize_protover_flags(protover_summary_flags_t *out, } } } + +/** + * Free all space held in the protover_summary_map. + */ +void +protover_summary_cache_free_all(void) +{ + strmap_free(protover_summary_map, tor_free_); + protover_summary_map = NULL; +} diff --git a/src/core/or/versions.h b/src/core/or/versions.h index 0c773f3f4c..4fc50a0018 100644 --- a/src/core/or/versions.h +++ b/src/core/or/versions.h @@ -41,4 +41,6 @@ void summarize_protover_flags(protover_summary_flags_t *out, const char *protocols, const char *version); +void protover_summary_cache_free_all(void); + #endif /* !defined(TOR_VERSIONS_H) */ -- cgit v1.2.3-54-g00ecf From 100136ca8624151605601d80b63746cfaeb6df47 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sun, 11 Nov 2018 20:24:07 +0200 Subject: Create new periodic event for pruning old info about Tor routers --- changes/bug27929 | 5 +++++ src/core/mainloop/mainloop.c | 32 ++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 changes/bug27929 (limited to 'changes') diff --git a/changes/bug27929 b/changes/bug27929 new file mode 100644 index 0000000000..a97d18f202 --- /dev/null +++ b/changes/bug27929 @@ -0,0 +1,5 @@ + o Minor bugfixes (periodic events): + - Refrain from calling routerlist_remove_old_routers() from + check_descriptor_callback(). Instead, create a new periodic + event that will run every minute even if Tor is not configured + as onion router. Fixes bug 27929; bugfix on 0.2.8.1-alpha. diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c index a9f1429787..be19136130 100644 --- a/src/core/mainloop/mainloop.c +++ b/src/core/mainloop/mainloop.c @@ -1359,6 +1359,7 @@ CALLBACK(heartbeat); CALLBACK(hs_service); CALLBACK(launch_descriptor_fetches); CALLBACK(launch_reachability_tests); +CALLBACK(prune_old_routers); CALLBACK(reachability_warnings); CALLBACK(record_bridge_stats); CALLBACK(rend_cache_failure_clean); @@ -1391,6 +1392,8 @@ STATIC periodic_event_item_t periodic_events[] = { CALLBACK(retry_listeners, PERIODIC_EVENT_ROLE_ALL, PERIODIC_EVENT_FLAG_NEED_NET), CALLBACK(save_state, PERIODIC_EVENT_ROLE_ALL, 0), + CALLBACK(prune_old_routers, PERIODIC_EVENT_ROLE_ALL, + PERIODIC_EVENT_FLAG_NEED_NET), CALLBACK(rotate_x509_certificate, PERIODIC_EVENT_ROLE_ALL, 0), CALLBACK(write_stats_file, PERIODIC_EVENT_ROLE_ALL, 0), @@ -1454,6 +1457,7 @@ static periodic_event_item_t *fetch_networkstatus_event=NULL; static periodic_event_item_t *launch_descriptor_fetches_event=NULL; static periodic_event_item_t *check_dns_honesty_event=NULL; static periodic_event_item_t *save_state_event=NULL; +static periodic_event_item_t *prune_old_routers_event=NULL; /** Reset all the periodic events so we'll do all our actions again as if we * just started up. @@ -1556,6 +1560,7 @@ initialize_periodic_events(void) STMT_BEGIN name ## _event = find_periodic_event( #name ); STMT_END NAMED_CALLBACK(check_descriptor); + NAMED_CALLBACK(prune_old_routers); NAMED_CALLBACK(dirvote); NAMED_CALLBACK(fetch_networkstatus); NAMED_CALLBACK(launch_descriptor_fetches); @@ -2220,6 +2225,27 @@ retry_dns_callback(time_t now, const or_options_t *options) return RETRY_DNS_INTERVAL; } +/** + * Periodic callback: prune routerlist of old information about Tor network. + */ +static int +prune_old_routers_callback(time_t now, const or_options_t *options) +{ +#define ROUTERLIST_PRUNING_INTERVAL (60) // 1 minute. + (void)now; + (void)options; + + if (!net_is_disabled()) { + /* If any networkstatus documents are no longer recent, we need to + * update all the descriptors' running status. */ + /* Remove dead routers. */ + log_debug(LD_GENERAL, "Pruning routerlist..."); + routerlist_remove_old_routers(); + } + + return ROUTERLIST_PRUNING_INTERVAL; +} + /** Periodic callback: consider rebuilding or and re-uploading our descriptor * (if we've passed our internal checks). */ static int @@ -2239,12 +2265,6 @@ check_descriptor_callback(time_t now, const or_options_t *options) check_descriptor_ipaddress_changed(now); mark_my_descriptor_dirty_if_too_old(now); consider_publishable_server(0); - /* If any networkstatus documents are no longer recent, we need to - * update all the descriptors' running status. */ - /* Remove dead routers. */ - /* XXXX This doesn't belong here, but it was here in the pre- - * XXXX refactoring code. */ - routerlist_remove_old_routers(); } return CHECK_DESCRIPTOR_INTERVAL; -- cgit v1.2.3-54-g00ecf From 5090fecaca61c87d52559342d6488ee8bb8fd20b Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 7 Nov 2018 11:02:03 -0500 Subject: changes file for no-circular-dependencies stuff (28362) --- changes/ticket28362 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/ticket28362 (limited to 'changes') diff --git a/changes/ticket28362 b/changes/ticket28362 new file mode 100644 index 0000000000..4ac22d50f2 --- /dev/null +++ b/changes/ticket28362 @@ -0,0 +1,6 @@ + o Code simplification and refactoring: + - The .may_include files that we use to describe our + directory-by-directory dependency structure now describe a noncircular + dependency graph over the directories that they cover. + Our checkIncludes.py tool now enforces this. + Closes ticket 28362. -- cgit v1.2.3-54-g00ecf From 8cb817cc5e0cc36cc0218da53bc4c1f277ccd8cc Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sun, 11 Nov 2018 18:56:20 +0200 Subject: Add changes file --- changes/ticket28008 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket28008 (limited to 'changes') diff --git a/changes/ticket28008 b/changes/ticket28008 new file mode 100644 index 0000000000..1f0de1a14d --- /dev/null +++ b/changes/ticket28008 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Fix shellcheck warnings in scripts/test/coverage. Resolves issue + 28008. -- cgit v1.2.3-54-g00ecf From d9f7cb3f6202291d38d611165f70e0c1c33b3e92 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sun, 11 Nov 2018 19:18:49 +0200 Subject: Fix shellcheck issues in cov-diff - SC2231, SC2006 and SC2086 --- changes/ticket28009 | 3 +++ scripts/test/cov-diff | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 changes/ticket28009 (limited to 'changes') diff --git a/changes/ticket28009 b/changes/ticket28009 new file mode 100644 index 0000000000..1d986d4211 --- /dev/null +++ b/changes/ticket28009 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Fix shellcheck warnings in cov-diff script. Resolves issue + 28009. diff --git a/scripts/test/cov-diff b/scripts/test/cov-diff index 6179dff63e..f3ca856888 100755 --- a/scripts/test/cov-diff +++ b/scripts/test/cov-diff @@ -7,9 +7,9 @@ DIRA="$1" DIRB="$2" -for B in $DIRB/*; do - A=$DIRA/`basename $B` - if [ -f $A ]; then +for B in "$DIRB"/*; do + A=$DIRA/$(basename "$B") + if [ -f "$A" ]; then perl -pe 's/^\s*\!*\d+(\*?):/ 1$1:/; s/^([^:]+:)[\d\s]+:/$1/; s/^ *-:(Runs|Programs):.*//;' "$A" > "$A.tmp" else cat /dev/null > "$A.tmp" -- cgit v1.2.3-54-g00ecf From c8c4c3dffa71b4bbc9e7cabfee2124fb5e19ad39 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sat, 17 Nov 2018 10:27:10 +0200 Subject: fixup! Make ROUTERLIST_PRUNING_INTERVAL 1 hr. --- changes/bug27929 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'changes') diff --git a/changes/bug27929 b/changes/bug27929 index a97d18f202..dab57a2eca 100644 --- a/changes/bug27929 +++ b/changes/bug27929 @@ -1,5 +1,5 @@ o Minor bugfixes (periodic events): - Refrain from calling routerlist_remove_old_routers() from check_descriptor_callback(). Instead, create a new periodic - event that will run every minute even if Tor is not configured + event that will run once every hour even if Tor is not configured as onion router. Fixes bug 27929; bugfix on 0.2.8.1-alpha. -- cgit v1.2.3-54-g00ecf From 426c9561c5f5bc5f38a42f3e46437db59fcdc7c0 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 23 Oct 2018 19:55:12 -0400 Subject: Use nodefamily_t in microdescriptors. Closes ticket 27359. --- changes/ticket27359 | 3 + src/feature/dirparse/microdesc_parse.c | 16 ++--- src/feature/nodelist/microdesc.c | 6 +- src/feature/nodelist/microdesc_st.h | 5 +- src/feature/nodelist/nodelist.c | 110 +++++++++++++++++++++------------ src/feature/nodelist/nodelist.h | 1 - src/test/test_microdesc.c | 8 ++- 7 files changed, 89 insertions(+), 60 deletions(-) create mode 100644 changes/ticket27359 (limited to 'changes') diff --git a/changes/ticket27359 b/changes/ticket27359 new file mode 100644 index 0000000000..bddc90634d --- /dev/null +++ b/changes/ticket27359 @@ -0,0 +1,3 @@ + o Minor features (memory usage): + - Store microdescriptor family lists with a more compact representation + to save memory. Closes ticket 27359. diff --git a/src/feature/dirparse/microdesc_parse.c b/src/feature/dirparse/microdesc_parse.c index aebff5a35f..8ad9626377 100644 --- a/src/feature/dirparse/microdesc_parse.c +++ b/src/feature/dirparse/microdesc_parse.c @@ -18,6 +18,7 @@ #include "feature/dirparse/routerparse.h" #include "feature/nodelist/microdesc.h" #include "feature/nodelist/nickname.h" +#include "feature/nodelist/nodefamily.h" #include "feature/relay/router.h" #include "lib/crypt_ops/crypto_curve25519.h" #include "lib/crypt_ops/crypto_ed25519.h" @@ -32,7 +33,7 @@ static token_rule_t microdesc_token_table[] = { T01("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ), T0N("id", K_ID, GE(2), NO_OBJ ), T0N("a", K_A, GE(1), NO_OBJ ), - T01("family", K_FAMILY, ARGS, NO_OBJ ), + T01("family", K_FAMILY, CONCAT_ARGS, NO_OBJ ), T01("p", K_P, CONCAT_ARGS, NO_OBJ ), T01("p6", K_P6, CONCAT_ARGS, NO_OBJ ), A01("@last-listed", A_LAST_LISTED, CONCAT_ARGS, NO_OBJ ), @@ -222,16 +223,9 @@ microdescs_parse_from_string(const char *s, const char *eos, } if ((tok = find_opt_by_keyword(tokens, K_FAMILY))) { - int i; - md->family = smartlist_new(); - for (i=0;in_args;++i) { - if (!is_legal_nickname_or_hexdigest(tok->args[i])) { - log_warn(LD_DIR, "Illegal nickname %s in family line", - escaped(tok->args[i])); - goto next; - } - smartlist_add_strdup(md->family, tok->args[i]); - } + md->family = nodefamily_parse(tok->args[0], + NULL, + NF_WARN_MALFORMED); } if ((tok = find_opt_by_keyword(tokens, K_P))) { diff --git a/src/feature/nodelist/microdesc.c b/src/feature/nodelist/microdesc.c index 146c772daf..f331d5e109 100644 --- a/src/feature/nodelist/microdesc.c +++ b/src/feature/nodelist/microdesc.c @@ -23,6 +23,7 @@ #include "feature/nodelist/dirlist.h" #include "feature/nodelist/microdesc.h" #include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodefamily.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerlist.h" #include "feature/relay/router.h" @@ -882,10 +883,7 @@ microdesc_free_(microdesc_t *md, const char *fname, int lineno) if (md->body && md->saved_location != SAVED_IN_CACHE) tor_free(md->body); - if (md->family) { - SMARTLIST_FOREACH(md->family, char *, cp, tor_free(cp)); - smartlist_free(md->family); - } + nodefamily_free(md->family); short_policy_free(md->exit_policy); short_policy_free(md->ipv6_exit_policy); diff --git a/src/feature/nodelist/microdesc_st.h b/src/feature/nodelist/microdesc_st.h index d23da13137..30c896181d 100644 --- a/src/feature/nodelist/microdesc_st.h +++ b/src/feature/nodelist/microdesc_st.h @@ -9,6 +9,7 @@ struct curve25519_public_key_t; struct ed25519_public_key_t; +struct nodefamily_t; struct short_policy_t; /** A microdescriptor is the smallest amount of information needed to build a @@ -69,8 +70,8 @@ struct microdesc_t { tor_addr_t ipv6_addr; /** As routerinfo_t.ipv6_orport */ uint16_t ipv6_orport; - /** As routerinfo_t.family */ - smartlist_t *family; + /** As routerinfo_t.family, with readable members parsed. */ + struct nodefamily_t *family; /** IPv4 exit policy summary */ struct short_policy_t *exit_policy; /** IPv6 exit policy summary */ diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c index a98a5c8655..3994c8d072 100644 --- a/src/feature/nodelist/nodelist.c +++ b/src/feature/nodelist/nodelist.c @@ -59,6 +59,7 @@ #include "feature/nodelist/microdesc.h" #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/node_select.h" +#include "feature/nodelist/nodefamily.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerlist.h" #include "feature/nodelist/routerset.h" @@ -1504,19 +1505,6 @@ node_is_me(const node_t *node) return router_digest_is_me(node->identity); } -/** Return node declared family (as a list of names), or NULL if - * the node didn't declare a family. */ -const smartlist_t * -node_get_declared_family(const node_t *node) -{ - if (node->ri && node->ri->declared_family) - return node->ri->declared_family; - else if (node->md && node->md->family) - return node->md->family; - else - return NULL; -} - /* Does this node have a valid IPv6 address? * Prefer node_has_ipv6_orport() or node_has_ipv6_dirport() for * checking specific ports. */ @@ -1905,6 +1893,61 @@ node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node) return 0; } +/** Return true iff n1's declared family contains n2. */ +static int +node_family_contains(const node_t *n1, const node_t *n2) +{ + if (n1->ri && n1->ri->declared_family) { + return node_in_nickname_smartlist(n1->ri->declared_family, n2); + } else if (n1->md) { + return nodefamily_contains_node(n1->md->family, n2); + } else { + return 0; + } +} + +/** + * Return true iff node has declared a nonempty family. + **/ +static bool +node_has_declared_family(const node_t *node) +{ + if (node->ri && node->ri->declared_family && + smartlist_len(node->ri->declared_family)) { + return true; + } + + if (node->md && node->md->family) { + return true; + } + + return false; +} + +/** + * Add to out every node_t that is listed by node as being in + * its family. (Note that these nodes are not in node's family unless they + * also agree that node is in their family.) + **/ +static void +node_lookup_declared_family(smartlist_t *out, const node_t *node) +{ + if (node->ri && node->ri->declared_family && + smartlist_len(node->ri->declared_family)) { + SMARTLIST_FOREACH_BEGIN(node->ri->declared_family, const char *, name) { + const node_t *n2 = node_get_by_nickname(name, NNF_NO_WARN_UNNAMED); + if (n2) { + smartlist_add(out, (node_t *)n2); + } + } SMARTLIST_FOREACH_END(name); + return; + } + + if (node->md && node->md->family) { + nodefamily_add_nodes_to_smartlist(node->md->family, out); + } +} + /** Return true iff r1 and r2 are in the same family, but not the same * router. */ int @@ -1922,14 +1965,9 @@ nodes_in_same_family(const node_t *node1, const node_t *node2) } /* Are they in the same family because the agree they are? */ - { - const smartlist_t *f1, *f2; - f1 = node_get_declared_family(node1); - f2 = node_get_declared_family(node2); - if (f1 && f2 && - node_in_nickname_smartlist(f1, node2) && - node_in_nickname_smartlist(f2, node1)) - return 1; + if (node_family_contains(node1, node2) && + node_family_contains(node2, node1)) { + return 1; } /* Are they in the same option because the user says they are? */ @@ -1957,13 +1995,10 @@ void nodelist_add_node_and_family(smartlist_t *sl, const node_t *node) { const smartlist_t *all_nodes = nodelist_get_list(); - const smartlist_t *declared_family; const or_options_t *options = get_options(); tor_assert(node); - declared_family = node_get_declared_family(node); - /* Let's make sure that we have the node itself, if it's a real node. */ { const node_t *real_node = node_get_by_id(node->identity); @@ -1984,25 +2019,20 @@ nodelist_add_node_and_family(smartlist_t *sl, const node_t *node) } SMARTLIST_FOREACH_END(node2); } - /* Now, add all nodes in the declared_family of this node, if they + /* Now, add all nodes in the declared family of this node, if they * also declare this node to be in their family. */ - if (declared_family) { + if (node_has_declared_family(node)) { + smartlist_t *declared_family = smartlist_new(); + node_lookup_declared_family(declared_family, node); + /* Add every r such that router declares familyness with node, and node * declares familyhood with router. */ - SMARTLIST_FOREACH_BEGIN(declared_family, const char *, name) { - const node_t *node2; - const smartlist_t *family2; - if (!(node2 = node_get_by_nickname(name, NNF_NO_WARN_UNNAMED))) - continue; - if (!(family2 = node_get_declared_family(node2))) - continue; - SMARTLIST_FOREACH_BEGIN(family2, const char *, name2) { - if (node_nickname_matches(node, name2)) { - smartlist_add(sl, (void*)node2); - break; - } - } SMARTLIST_FOREACH_END(name2); - } SMARTLIST_FOREACH_END(name); + SMARTLIST_FOREACH_BEGIN(declared_family, const node_t *, node2) { + if (node_family_contains(node2, node)) { + smartlist_add(sl, (void*)node2); + } + } SMARTLIST_FOREACH_END(node2); + smartlist_free(declared_family); } /* If the user declared any families locally, honor those too. */ diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h index cf7658cf9d..87ea544db2 100644 --- a/src/feature/nodelist/nodelist.h +++ b/src/feature/nodelist/nodelist.h @@ -68,7 +68,6 @@ const char *node_get_platform(const node_t *node); uint32_t node_get_prim_addr_ipv4h(const node_t *node); void node_get_address_string(const node_t *node, char *cp, size_t len); long node_get_declared_uptime(const node_t *node); -const smartlist_t *node_get_declared_family(const node_t *node); const struct ed25519_public_key_t *node_get_ed25519_id(const node_t *node); int node_ed25519_id_matches(const node_t *node, const struct ed25519_public_key_t *id); diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c index 8ede2690ec..3318408d53 100644 --- a/src/test/test_microdesc.c +++ b/src/test/test_microdesc.c @@ -11,6 +11,7 @@ #include "feature/dirparse/routerparse.h" #include "feature/nodelist/microdesc.h" #include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodefamily.h" #include "feature/nodelist/routerlist.h" #include "feature/nodelist/torcert.h" @@ -70,6 +71,7 @@ test_md_cache(void *data) const char *test_md3_noannotation = strchr(test_md3, '\n')+1; time_t time1, time2, time3; char *fn = NULL, *s = NULL; + char *encoded_family = NULL; (void)data; options = get_options_mutable(); @@ -172,8 +174,9 @@ test_md_cache(void *data) tt_ptr_op(md1->family, OP_EQ, NULL); tt_ptr_op(md3->family, OP_NE, NULL); - tt_int_op(smartlist_len(md3->family), OP_EQ, 3); - tt_str_op(smartlist_get(md3->family, 0), OP_EQ, "nodeX"); + + encoded_family = nodefamily_format(md3->family); + tt_str_op(encoded_family, OP_EQ, "nodeX nodeY nodeZ"); /* Now rebuild the cache! */ tt_int_op(microdesc_cache_rebuild(mc, 1), OP_EQ, 0); @@ -254,6 +257,7 @@ test_md_cache(void *data) smartlist_free(wanted); tor_free(s); tor_free(fn); + tor_free(encoded_family); } static const char truncated_md[] = -- cgit v1.2.3-54-g00ecf From d020124138cc0d16e685bfd35dd388a4db7f68af Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Mon, 19 Nov 2018 16:33:06 +0100 Subject: Add changes file for #28518. See: https://bugs.torproject.org/28518 --- changes/bug28518 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/bug28518 (limited to 'changes') diff --git a/changes/bug28518 b/changes/bug28518 new file mode 100644 index 0000000000..d7ebab29bb --- /dev/null +++ b/changes/bug28518 @@ -0,0 +1,4 @@ + o Minor features (FreeBSD): + - Warn relay operators if the "net.inet.ip.random_id" sysctl (IP ID + randomization) is disabled on their relay if it is running on FreeBSD + based operating systems. Closes ticket 28518. -- cgit v1.2.3-54-g00ecf From ffee0a6384e751486bb4ca2752b6a00527b923ca Mon Sep 17 00:00:00 2001 From: rl1987 Date: Tue, 20 Nov 2018 15:40:52 +0200 Subject: Add pre-push git hook to prevent fixup and squash commits from ending up in master --- changes/ticket27993 | 3 +++ scripts/maint/pre-push | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 changes/ticket27993 create mode 100755 scripts/maint/pre-push (limited to 'changes') diff --git a/changes/ticket27993 b/changes/ticket27993 new file mode 100644 index 0000000000..78ee7c2054 --- /dev/null +++ b/changes/ticket27993 @@ -0,0 +1,3 @@ + o Minor features (developer tooling): + - Provide git hook script to prevent "fixup!" and "squash!" commits from + ending up in master. Closes ticket 27993. diff --git a/scripts/maint/pre-push b/scripts/maint/pre-push new file mode 100755 index 0000000000..2cf1837b8d --- /dev/null +++ b/scripts/maint/pre-push @@ -0,0 +1,56 @@ +#!/bin/sh + +# git pre-push hook script to prevent "fixup!" and "squash!" commit +# from ending up in master, or in any branch if CUR_BRANCH check is removed. +# It is meant to be placed in .git/hooks directory. +# +# The following sample script was used as starting point: +# https://github.com/git/git/blob/master/templates/hooks--pre-push.sample + +z40=0000000000000000000000000000000000000000 + +CUR_BRANCH=$(git rev-parse --abbrev-ref HEAD) +if [ "$CUR_BRANCH" != "master" ] +then + exit 0 +fi + +echo "Running pre-push hook" + +# shellcheck disable=SC2034 +while read -r local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # Handle delete + : + else + if [ "$remote_sha" = $z40 ] + then + # New branch, examine all commits + range="$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + # Check for fixup! commit + commit=$(git rev-list -n 1 --grep '^fixup!' "$range") + if [ -n "$commit" ] + then + echo >&2 "Found fixup! commit in $local_ref, not pushing" + exit 1 + fi + + # Check for squash! commit + commit=$(git rev-list -n 1 --grep '^squash!' "$range") + if [ -n "$commit" ] + then + echo >&2 "Found squash! commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 + -- cgit v1.2.3-54-g00ecf From befcd6ab7f53e8d5d825949547e2530fdc91b177 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Tue, 20 Nov 2018 17:00:32 +0200 Subject: Add changes file for #28012 --- changes/ticket28012 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket28012 (limited to 'changes') diff --git a/changes/ticket28012 b/changes/ticket28012 new file mode 100644 index 0000000000..b2fe83e02a --- /dev/null +++ b/changes/ticket28012 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Fix issues that shellcheck found in updateRustDependencies.sh. + Resolves ticket 28012. -- cgit v1.2.3-54-g00ecf From 0a0c612b79cb5230cc70922634a37f73a1c87c10 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 24 Nov 2018 11:51:41 -0500 Subject: Add a consensus method in which md families get canonicalized. Implements prop298. Closes ticket 28266. --- changes/ticket28266 | 5 +++++ src/feature/dirauth/dirvote.c | 18 +++++++++++++++--- src/feature/dirauth/dirvote.h | 8 +++++++- src/test/test_microdesc.c | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 changes/ticket28266 (limited to 'changes') diff --git a/changes/ticket28266 b/changes/ticket28266 new file mode 100644 index 0000000000..d90dc74f76 --- /dev/null +++ b/changes/ticket28266 @@ -0,0 +1,5 @@ + o Minor features (directory authority): + - Directory authorities support a new consensus algorithm, + under which microdescriptor entries are encoded in a canonical + form. This improves their compressibility in transit and on the client. + Closes ticket 28266; implements proposal 298. diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index 066a9e6e8a..6c4e12cd51 100644 --- a/src/feature/dirauth/dirvote.c +++ b/src/feature/dirauth/dirvote.c @@ -28,6 +28,7 @@ #include "feature/nodelist/fmt_routerstatus.h" #include "feature/nodelist/microdesc.h" #include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodefamily.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerlist.h" #include "feature/relay/router.h" @@ -3799,8 +3800,16 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method) smartlist_add_asprintf(chunks, "a %s\n", fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport)); - if (family) - smartlist_add_asprintf(chunks, "family %s\n", family); + if (family) { + if (consensus_method < MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS) { + smartlist_add_asprintf(chunks, "family %s\n", family); + } else { + const uint8_t *id = (const uint8_t *)ri->cache_info.identity_digest; + char *canonical_family = nodefamily_canonicalize(family, id, 0); + smartlist_add_asprintf(chunks, "family %s\n", canonical_family); + tor_free(canonical_family); + } + } if (summary && strcmp(summary, "reject 1-65535")) smartlist_add_asprintf(chunks, "p %s\n", summary); @@ -3898,7 +3907,10 @@ static const struct consensus_method_range_t { int high; } microdesc_consensus_methods[] = { {MIN_SUPPORTED_CONSENSUS_METHOD, MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC - 1}, - {MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC, MAX_SUPPORTED_CONSENSUS_METHOD}, + {MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC, + MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS - 1}, + {MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS, + MAX_SUPPORTED_CONSENSUS_METHOD}, {-1, -1} }; diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h index a21e9f3455..6afb6047ff 100644 --- a/src/feature/dirauth/dirvote.h +++ b/src/feature/dirauth/dirvote.h @@ -57,7 +57,7 @@ #define MIN_SUPPORTED_CONSENSUS_METHOD 25 /** The highest consensus method that we currently support. */ -#define MAX_SUPPORTED_CONSENSUS_METHOD 28 +#define MAX_SUPPORTED_CONSENSUS_METHOD 29 /** Lowest consensus method where authorities vote on required/recommended * protocols. */ @@ -79,6 +79,12 @@ * addresses. See #23828 and #20916. */ #define MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC 28 +/** + * Lowest consensus method where microdescriptor lines are put in canonical + * form for improved compressibility and ease of storage. See proposal 298. + **/ +#define MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS 29 + /** Default bandwidth to clip unmeasured bandwidths to using method >= * MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not * get confused with the above macros.) */ diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c index debb11155a..fd79aee6be 100644 --- a/src/test/test_microdesc.c +++ b/src/test/test_microdesc.c @@ -421,6 +421,28 @@ static const char test_md2_21[] = "ntor-onion-key hbxdRnfVUJJY7+KcT4E3Rs7/zuClbN3hJrjSBiEGMgI=\n" "id ed25519 wqfLzgfCtRfYNg88LsL1QpzxS0itapJ1aj6TbnByx/Q\n"; +static const char test_md2_withfamily_28[] = + "onion-key\n" + "-----BEGIN RSA PUBLIC KEY-----\n" + "MIGJAoGBAL2R8EfubUcahxha4u02P4VAR0llQIMwFAmrHPjzcK7apcQgDOf2ovOA\n" + "+YQnJFxlpBmCoCZC6ssCi+9G0mqo650lFuTMP5I90BdtjotfzESfTykHLiChyvhd\n" + "l0dlqclb2SU/GKem/fLRXH16aNi72CdSUu/1slKs/70ILi34QixRAgMBAAE=\n" + "-----END RSA PUBLIC KEY-----\n" + "ntor-onion-key hbxdRnfVUJJY7+KcT4E3Rs7/zuClbN3hJrjSBiEGMgI=\n" + "family OtherNode !Strange\n" + "id ed25519 wqfLzgfCtRfYNg88LsL1QpzxS0itapJ1aj6TbnByx/Q\n"; + +static const char test_md2_withfamily_29[] = + "onion-key\n" + "-----BEGIN RSA PUBLIC KEY-----\n" + "MIGJAoGBAL2R8EfubUcahxha4u02P4VAR0llQIMwFAmrHPjzcK7apcQgDOf2ovOA\n" + "+YQnJFxlpBmCoCZC6ssCi+9G0mqo650lFuTMP5I90BdtjotfzESfTykHLiChyvhd\n" + "l0dlqclb2SU/GKem/fLRXH16aNi72CdSUu/1slKs/70ILi34QixRAgMBAAE=\n" + "-----END RSA PUBLIC KEY-----\n" + "ntor-onion-key hbxdRnfVUJJY7+KcT4E3Rs7/zuClbN3hJrjSBiEGMgI=\n" + "family !Strange $B7E27F104213C36F13E7E9829182845E495997A0 othernode\n" + "id ed25519 wqfLzgfCtRfYNg88LsL1QpzxS0itapJ1aj6TbnByx/Q\n"; + static void test_md_generate(void *arg) { @@ -451,6 +473,17 @@ test_md_generate(void *arg) tt_assert(ed25519_pubkey_eq(md->ed25519_identity_pkey, &ri->cache_info.signing_key_cert->signing_key)); + // Try family encoding. + microdesc_free(md); + ri->declared_family = smartlist_new(); + smartlist_add_strdup(ri->declared_family, "OtherNode !Strange"); + md = dirvote_create_microdescriptor(ri, 28); + tt_str_op(md->body, OP_EQ, test_md2_withfamily_28); + + microdesc_free(md); + md = dirvote_create_microdescriptor(ri, 29); + tt_str_op(md->body, OP_EQ, test_md2_withfamily_29); + done: microdesc_free(md); routerinfo_free(ri); -- cgit v1.2.3-54-g00ecf From 05dee063c8d74437c792bdee2432293f97b6307c Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 24 Nov 2018 16:35:58 -0500 Subject: Emit router families in canonical form This patch has routers use the same canonicalization logic as authorities when encoding their family lists. Additionally, they now warn if any router in their list is given by nickname, since that's error-prone. This patch also adds some long-overdue tests for family formatting. --- changes/ticket28266 | 5 ++ src/feature/relay/router.c | 135 +++++++++++++++++++++++++++++---------- src/feature/relay/router.h | 4 ++ src/test/test_router.c | 155 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 266 insertions(+), 33 deletions(-) (limited to 'changes') diff --git a/changes/ticket28266 b/changes/ticket28266 index d90dc74f76..e0bc171080 100644 --- a/changes/ticket28266 +++ b/changes/ticket28266 @@ -3,3 +3,8 @@ under which microdescriptor entries are encoded in a canonical form. This improves their compressibility in transit and on the client. Closes ticket 28266; implements proposal 298. + + o Minor features (relay): + - When listing relay families, list them in canonical form including the + relay's own identity, and try to give a more useful set of warnings. + Part of ticket 28266 and proposal 298. diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index 3f153e3a2d..d57fcc3a44 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -30,6 +30,7 @@ #include "feature/nodelist/dirlist.h" #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/nickname.h" +#include "feature/nodelist/nodefamily.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerlist.h" #include "feature/nodelist/torcert.h" @@ -340,6 +341,16 @@ set_server_identity_key(crypto_pk_t *k) } } +#ifdef TOR_UNIT_TESTS +/** Testing only -- set the server's RSA identity digest to + * be digest */ +void +set_server_identity_key_digest_testing(const uint8_t *digest) +{ + memcpy(server_identitykey_digest, digest, DIGEST_LEN); +} +#endif + /** Make sure that we have set up our identity keys to match or not match as * appropriate, and die with an assertion if we have not. */ static void @@ -1691,10 +1702,6 @@ router_get_descriptor_gen_reason(void) return desc_gen_reason; } -/** A list of nicknames that we've warned about including in our family - * declaration verbatim rather than as digests. */ -static smartlist_t *warned_nonexistent_family = NULL; - static int router_guess_address_from_dir_headers(uint32_t *guess); /** Make a current best guess at our address, either because @@ -1807,13 +1814,17 @@ router_check_descriptor_address_consistency(uint32_t ipv4h_desc_addr) CONN_TYPE_DIR_LISTENER); } +/** A list of nicknames that we've warned about including in our family, + * for one reason or another. */ +static smartlist_t *warned_family = NULL; + /** * Return a new smartlist containing the family members configured in * options. Warn about invalid or missing entries. Return NULL * if this relay should not declare a family. **/ -static smartlist_t * -get_declared_family(const or_options_t *options) +STATIC smartlist_t * +get_my_declared_family(const or_options_t *options) { if (!options->MyFamily) return NULL; @@ -1821,55 +1832,112 @@ get_declared_family(const or_options_t *options) if (options->BridgeRelay) return NULL; - if (!warned_nonexistent_family) - warned_nonexistent_family = smartlist_new(); + if (!warned_family) + warned_family = smartlist_new(); smartlist_t *declared_family = smartlist_new(); config_line_t *family; + + /* First we try to get the whole family in the form of hexdigests. */ for (family = options->MyFamily; family; family = family->next) { char *name = family->value; const node_t *member; - if (!strcasecmp(name, options->Nickname)) - continue; /* Don't list ourself, that's redundant */ + if (options->Nickname && !strcasecmp(name, options->Nickname)) + continue; /* Don't list ourself by nickname, that's redundant */ else member = node_get_by_nickname(name, 0); + if (!member) { + /* This node doesn't seem to exist, so warn about it if it is not + * a hexdigest. */ int is_legal = is_legal_nickname_or_hexdigest(name); - if (!smartlist_contains_string(warned_nonexistent_family, name) && + if (!smartlist_contains_string(warned_family, name) && !is_legal_hexdigest(name)) { if (is_legal) log_warn(LD_CONFIG, - "I have no descriptor for the router named \"%s\" in my " - "declared family; I'll use the nickname as is, but " - "this may confuse clients.", name); + "There is a router named %s in my declared family, but " + "I have no descriptor for it. I'll use the nickname " + "as is, but this may confuse clients. Please list it " + "by identity digest instead.", escaped(name)); else - log_warn(LD_CONFIG, "There is a router named \"%s\" in my " - "declared family, but that isn't a legal nickname. " + log_warn(LD_CONFIG, "There is a router named %s in my declared " + "family, but that isn't a legal digest or nickname. " "Skipping it.", escaped(name)); - smartlist_add_strdup(warned_nonexistent_family, name); + smartlist_add_strdup(warned_family, name); } if (is_legal) { smartlist_add_strdup(declared_family, name); } - } else if (router_digest_is_me(member->identity)) { - /* Don't list ourself in our own family; that's redundant */ - /* XXX shouldn't be possible */ } else { + /* List the node by digest. */ char *fp = tor_malloc(HEX_DIGEST_LEN+2); fp[0] = '$'; base16_encode(fp+1,HEX_DIGEST_LEN+1, member->identity, DIGEST_LEN); smartlist_add(declared_family, fp); - if (smartlist_contains_string(warned_nonexistent_family, name)) - smartlist_string_remove(warned_nonexistent_family, name); + + if (! is_legal_hexdigest(name) && + !smartlist_contains_string(warned_family, name)) { + /* Warn if this node was not specified by hexdigest. */ + log_warn(LD_CONFIG, "There is a router named %s in my declared " + "family, but it wasn't listed by digest. Please consider " + "saying %s instead, if that's what you meant.", + escaped(name), fp); + smartlist_add_strdup(warned_family, name); + } } } - /* remove duplicates from the list */ - smartlist_sort_strings(declared_family); - smartlist_uniq_strings(declared_family); + /* Now declared_family should have the closest we can come to the + * identities that the user wanted. + * + * Unlike older versions of Tor, we _do_ include our own identity: this + * helps microdescriptor compression, and helps in-memory compression + * on clients. */ + nodefamily_t *nf = nodefamily_from_members(declared_family, + router_get_my_id_digest(), + NF_WARN_MALFORMED, + NULL); + SMARTLIST_FOREACH(declared_family, char *, s, tor_free(s)); + smartlist_free(declared_family); + if (!nf) { + return NULL; + } + + char *s = nodefamily_format(nf); + nodefamily_free(nf); + + smartlist_t *result = smartlist_new(); + smartlist_split_string(result, s, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + tor_free(s); + + if (smartlist_len(result) == 1) { + /* This is a one-element list containing only ourself; instead return + * nothing */ + const char *singleton = smartlist_get(result, 0); + bool is_me = false; + if (singleton[0] == '$') { + char d[DIGEST_LEN]; + int n = base16_decode(d, sizeof(d), singleton+1, strlen(singleton+1)); + if (n == DIGEST_LEN && + fast_memeq(d, router_get_my_id_digest(), DIGEST_LEN)) { + is_me = true; + } + } + if (!is_me) { + // LCOV_EXCL_START + log_warn(LD_BUG, "Found a singleton family list with an element " + "that wasn't us! Element was %s", escaped(singleton)); + // LCOV_EXCL_STOP + } else { + SMARTLIST_FOREACH(result, char *, cp, tor_free(cp)); + smartlist_free(result); + return NULL; + } + } - return declared_family; + return result; } /** Build a fresh routerinfo, signed server descriptor, and extra-info document @@ -1986,7 +2054,7 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e) tor_free(p_tmp); } - ri->declared_family = get_declared_family(options); + ri->declared_family = get_my_declared_family(options); /* Now generate the extrainfo. */ ei = tor_malloc_zero(sizeof(extrainfo_t)); @@ -3077,9 +3145,9 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, void router_reset_warnings(void) { - if (warned_nonexistent_family) { - SMARTLIST_FOREACH(warned_nonexistent_family, char *, cp, tor_free(cp)); - smartlist_clear(warned_nonexistent_family); + if (warned_family) { + SMARTLIST_FOREACH(warned_family, char *, cp, tor_free(cp)); + smartlist_clear(warned_family); } } @@ -3103,11 +3171,12 @@ router_free_all(void) memwipe(&curve25519_onion_key, 0, sizeof(curve25519_onion_key)); memwipe(&last_curve25519_onion_key, 0, sizeof(last_curve25519_onion_key)); - if (warned_nonexistent_family) { - SMARTLIST_FOREACH(warned_nonexistent_family, char *, cp, tor_free(cp)); - smartlist_free(warned_nonexistent_family); + if (warned_family) { + SMARTLIST_FOREACH(warned_family, char *, cp, tor_free(cp)); + smartlist_free(warned_family); } } + /* From the given RSA key object, convert it to ASN-1 encoded format and set * the newly allocated object in onion_pkey_out. The length of the key is set * in onion_pkey_len_out. */ diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h index 4575172afb..872eed1f46 100644 --- a/src/feature/relay/router.h +++ b/src/feature/relay/router.h @@ -117,6 +117,10 @@ void router_free_all(void); /* Used only by router.c and test.c */ STATIC void get_platform_str(char *platform, size_t len); STATIC int router_write_fingerprint(int hashed); +STATIC smartlist_t *get_my_declared_family(const or_options_t *options); +#ifdef TOR_UNIT_TESTS +void set_server_identity_key_digest_testing(const uint8_t *digest); +#endif #endif #endif /* !defined(TOR_ROUTER_H) */ diff --git a/src/test/test_router.c b/src/test/test_router.c index 921ec42904..b92e96ff3e 100644 --- a/src/test/test_router.c +++ b/src/test/test_router.c @@ -7,16 +7,21 @@ * \brief Unittests for code in router.c **/ +#define CONFIG_PRIVATE +#define ROUTER_PRIVATE #include "core/or/or.h" #include "app/config/config.h" #include "core/mainloop/mainloop.h" #include "feature/hibernate/hibernate.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerinfo_st.h" #include "feature/nodelist/routerlist.h" #include "feature/relay/router.h" #include "feature/stats/rephist.h" #include "lib/crypt_ops/crypto_curve25519.h" #include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/encoding/confline.h" /* Test suite stuff */ #include "test/test.h" @@ -231,11 +236,161 @@ test_router_check_descriptor_bandwidth_changed(void *arg) UNMOCK(we_are_hibernating); } +static node_t fake_node; +static const node_t * +mock_node_get_by_nickname(const char *name, unsigned flags) +{ + (void)flags; + if (!strcasecmp(name, "crumpet")) + return &fake_node; + else + return NULL; +} + +static void +test_router_get_my_family(void *arg) +{ + (void)arg; + or_options_t *options = options_new(); + smartlist_t *sl = NULL; + char *join = NULL; + // Overwrite the result of router_get_my_identity_digest(). This + // happens to be okay, but only for testing. + set_server_identity_key_digest_testing( + (const uint8_t*)"holeinthebottomofthe"); + + setup_capture_of_logs(LOG_WARN); + + // No family listed -- so there's no list. + sl = get_my_declared_family(options); + tt_ptr_op(sl, OP_EQ, NULL); + expect_no_log_entry(); + +#define CLEAR() do { \ + if (sl) { \ + SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); \ + smartlist_free(sl); \ + } \ + tor_free(join); \ + mock_clean_saved_logs(); \ + } while (0) + + // Add a single nice friendly hex member. This should be enough + // to have our own ID added. + tt_ptr_op(options->MyFamily, OP_EQ, NULL); + config_line_append(&options->MyFamily, "MyFamily", + "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + + sl = get_my_declared_family(options); + tt_ptr_op(sl, OP_NE, NULL); + tt_int_op(smartlist_len(sl), OP_EQ, 2); + join = smartlist_join_strings(sl, " ", 0, NULL); + tt_str_op(join, OP_EQ, + "$686F6C65696E746865626F74746F6D6F66746865 " + "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + expect_no_log_entry(); + CLEAR(); + + // Add a hex member with a ~. The ~ part should get removed. + config_line_append(&options->MyFamily, "MyFamily", + "$0123456789abcdef0123456789abcdef01234567~Muffin"); + sl = get_my_declared_family(options); + tt_ptr_op(sl, OP_NE, NULL); + tt_int_op(smartlist_len(sl), OP_EQ, 3); + join = smartlist_join_strings(sl, " ", 0, NULL); + tt_str_op(join, OP_EQ, + "$0123456789ABCDEF0123456789ABCDEF01234567 " + "$686F6C65696E746865626F74746F6D6F66746865 " + "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + expect_no_log_entry(); + CLEAR(); + + // Nickname lookup will fail, so a nickname will appear verbatim. + config_line_append(&options->MyFamily, "MyFamily", + "BAGEL"); + sl = get_my_declared_family(options); + tt_ptr_op(sl, OP_NE, NULL); + tt_int_op(smartlist_len(sl), OP_EQ, 4); + join = smartlist_join_strings(sl, " ", 0, NULL); + tt_str_op(join, OP_EQ, + "$0123456789ABCDEF0123456789ABCDEF01234567 " + "$686F6C65696E746865626F74746F6D6F66746865 " + "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA " + "bagel"); + expect_single_log_msg_containing( + "There is a router named \"BAGEL\" in my declared family, but " + "I have no descriptor for it."); + CLEAR(); + + // A bogus digest should fail entirely. + config_line_append(&options->MyFamily, "MyFamily", + "$painauchocolat"); + sl = get_my_declared_family(options); + tt_ptr_op(sl, OP_NE, NULL); + tt_int_op(smartlist_len(sl), OP_EQ, 4); + join = smartlist_join_strings(sl, " ", 0, NULL); + tt_str_op(join, OP_EQ, + "$0123456789ABCDEF0123456789ABCDEF01234567 " + "$686F6C65696E746865626F74746F6D6F66746865 " + "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA " + "bagel"); + // "BAGEL" is still there, but it won't make a warning, because we already + // warned about it. + expect_single_log_msg_containing( + "There is a router named \"$painauchocolat\" in my declared " + "family, but that isn't a legal digest or nickname. Skipping it."); + CLEAR(); + + // Let's introduce a node we can look up by nickname + memset(&fake_node, 0, sizeof(fake_node)); + memcpy(fake_node.identity, "whydoyouasknonononon", DIGEST_LEN); + MOCK(node_get_by_nickname, mock_node_get_by_nickname); + + config_line_append(&options->MyFamily, "MyFamily", + "CRUmpeT"); + sl = get_my_declared_family(options); + tt_ptr_op(sl, OP_NE, NULL); + tt_int_op(smartlist_len(sl), OP_EQ, 5); + join = smartlist_join_strings(sl, " ", 0, NULL); + tt_str_op(join, OP_EQ, + "$0123456789ABCDEF0123456789ABCDEF01234567 " + "$686F6C65696E746865626F74746F6D6F66746865 " + "$776879646F796F7561736B6E6F6E6F6E6F6E6F6E " + "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA " + "bagel"); + // "BAGEL" is still there, but it won't make a warning, because we already + // warned about it. Some with "$painauchocolat". + expect_single_log_msg_containing( + "There is a router named \"CRUmpeT\" in my declared " + "family, but it wasn't listed by digest. Please consider saying " + "$776879646F796F7561736B6E6F6E6F6E6F6E6F6E instead, if that's " + "what you meant."); + CLEAR(); + UNMOCK(node_get_by_nickname); + + // Try a singleton list containing only us: It should give us NULL. + config_free_lines(options->MyFamily); + config_line_append(&options->MyFamily, "MyFamily", + "$686F6C65696E746865626F74746F6D6F66746865"); + sl = get_my_declared_family(options); + tt_ptr_op(sl, OP_EQ, NULL); + expect_no_log_entry(); + + done: + or_options_free(options); + teardown_capture_of_logs(); + CLEAR(); + UNMOCK(node_get_by_nickname); + +#undef CLEAR +} + #define ROUTER_TEST(name, flags) \ { #name, test_router_ ## name, flags, NULL, NULL } struct testcase_t router_tests[] = { ROUTER_TEST(check_descriptor_bandwidth_changed, TT_FORK), ROUTER_TEST(dump_router_to_string_no_bridge_distribution_method, TT_FORK), + ROUTER_TEST(get_my_family, TT_FORK), END_OF_TESTCASES }; -- cgit v1.2.3-54-g00ecf From 7da06e43da96f4253a756af546f27f03141b3784 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 24 Nov 2018 20:40:48 -0500 Subject: No longer exit for missing required protocolversions on an old consensus Specifically, if the consensus is older than the (estimted or measured) release date for this version of tor, we assume that the required versions may have changed in between that consensus and this release. Implements ticket 27735 and proposal 297. --- changes/prop297 | 7 +++++++ src/core/or/versions.c | 19 +++++++++++++++++++ src/core/or/versions.h | 2 ++ src/feature/nodelist/networkstatus.c | 5 ++++- 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 changes/prop297 (limited to 'changes') diff --git a/changes/prop297 b/changes/prop297 new file mode 100644 index 0000000000..4f93b232d2 --- /dev/null +++ b/changes/prop297 @@ -0,0 +1,7 @@ + o Minor features (required protocols): + - Tor no longer exits if it is missing a required protocol, if the + consensus that requires the protocol predates the release date of the + version of Tor. This change prevents Tor releases from exiting because + of an old cached consensus, on the theory that a newer cached + consensus might not require the protocol. Implements proposal 297; + closes ticket 27735. diff --git a/src/core/or/versions.c b/src/core/or/versions.c index 5d4effcaf8..d978935f4f 100644 --- a/src/core/or/versions.c +++ b/src/core/or/versions.c @@ -16,6 +16,25 @@ #include "core/or/tor_version_st.h" +/** + * Return the approximate date when this release came out, or was + * scheduled to come out, according to the APPROX_RELEASE_DATE set in + * configure.ac + **/ +time_t +tor_get_approx_release_date(void) +{ + char tbuf[ISO_TIME_LEN+1]; + tor_snprintf(tbuf, sizeof(tbuf), + "%s 00:00:00", APPROX_RELEASE_DATE); + time_t result = 0; + int r = parse_iso_time(tbuf, &result); + if (BUG(r < 0)) { + result = 0; + } + return result; +} + /** Return VS_RECOMMENDED if myversion is contained in * versionlist. Else, return VS_EMPTY if versionlist has no * entries. Else, return VS_OLD if every member of diff --git a/src/core/or/versions.h b/src/core/or/versions.h index 4fc50a0018..acd8998918 100644 --- a/src/core/or/versions.h +++ b/src/core/or/versions.h @@ -26,6 +26,8 @@ typedef enum version_status_t { VS_UNKNOWN, /**< We have no idea. */ } version_status_t; +time_t tor_get_approx_release_date(void); + version_status_t tor_version_is_obsolete(const char *myversion, const char *versionlist); int tor_version_parse_platform(const char *platform, diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index f1def9afb1..a25a539cd8 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -2684,6 +2684,9 @@ networkstatus_check_required_protocols(const networkstatus_t *ns, const char *required, *recommended; char *missing = NULL; + const bool consensus_postdates_this_release = + ns->valid_after >= tor_get_approx_release_date(); + tor_assert(warning_out); if (client_mode) { @@ -2701,7 +2704,7 @@ networkstatus_check_required_protocols(const networkstatus_t *ns, "%s on the Tor network. The missing protocols are: %s", func, missing); tor_free(missing); - return 1; + return consensus_postdates_this_release ? 1 : 0; } if (! protover_all_supported(recommended, &missing)) { -- cgit v1.2.3-54-g00ecf From 439ffcefd57031153e49e605389a1c218e737180 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sun, 25 Nov 2018 10:19:08 -0500 Subject: changes file for prop293 / ticket 26770 --- changes/ticket26770 | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 changes/ticket26770 (limited to 'changes') diff --git a/changes/ticket26770 b/changes/ticket26770 new file mode 100644 index 0000000000..7f3e92e9dd --- /dev/null +++ b/changes/ticket26770 @@ -0,0 +1,8 @@ + o Minor features (directory authority, relay): + - Authorities now vote on a "StaleDesc" flag to indicate that a relay's + descriptor is so old that the relay should upload again soon. Relays + understand this flag, and treat it as a signal to upload a new + descriptor. This flag will eventually let us remove the 'published' + date from routerstatus entries, and save a great deal of space in our + consensus diffs. Closes ticket 26770; implements proposal 293. + -- cgit v1.2.3-54-g00ecf From d6eafd06a9797d2747b0bd5988893c292076ef1f Mon Sep 17 00:00:00 2001 From: rl1987 Date: Fri, 12 Oct 2018 10:37:27 +0300 Subject: Add changes file --- changes/ticket28007 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket28007 (limited to 'changes') diff --git a/changes/ticket28007 b/changes/ticket28007 new file mode 100644 index 0000000000..1ac87862eb --- /dev/null +++ b/changes/ticket28007 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Cleanup scan-build.sh to silence shellcheck warnings. + Closes ticket 28007. -- cgit v1.2.3-54-g00ecf From e12fdeb18199925070f4e99e60f2c5bda7f6af82 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 26 Nov 2018 16:39:44 -0500 Subject: Changes file for "Dormant Mode" (28335, 2149). --- changes/ticket28335 | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 changes/ticket28335 (limited to 'changes') diff --git a/changes/ticket28335 b/changes/ticket28335 new file mode 100644 index 0000000000..eecf7c7fd9 --- /dev/null +++ b/changes/ticket28335 @@ -0,0 +1,7 @@ + o Major features (client): + - When Tor is running as a client, and it is unused for a long time, it + can now enter a "dormant" state. When Tor is dormant, it avoids + network activity and CPU wakeups until it is reawoken either by a user + request or by a controller command. For more information, see + the configuration options starting with "Dormant". Implements tickets + 2149 and 28335. -- cgit v1.2.3-54-g00ecf From 7a45bc74a430ff64f0696c77f075f9c830822413 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 29 Nov 2018 00:46:39 +1000 Subject: Dir: when Tor's clock is behind, use a future consensus to bootstrap When Tor's clock is behind the clocks on the authorities, allow Tor to bootstrap successfully. Fixes bug 28591; bugfix on 0.2.0.9-alpha. --- changes/bug28591 | 4 ++++ src/feature/nodelist/microdesc.c | 10 ++++++---- src/feature/nodelist/networkstatus.c | 35 ++++++++++++++++++++++++----------- src/feature/nodelist/networkstatus.h | 2 ++ src/test/test_entrynodes.c | 32 ++++++++++++++++++++++---------- src/test/test_routerlist.c | 1 - 6 files changed, 58 insertions(+), 26 deletions(-) create mode 100644 changes/bug28591 (limited to 'changes') diff --git a/changes/bug28591 b/changes/bug28591 new file mode 100644 index 0000000000..3a1c96ac16 --- /dev/null +++ b/changes/bug28591 @@ -0,0 +1,4 @@ + o Minor bugfixes (client, bootstrap): + - When Tor's clock is behind the clocks on the authorities, allow Tor to + bootstrap successfully. Fixes bug 28591; bugfix on 0.2.0.9-alpha. + diff --git a/src/feature/nodelist/microdesc.c b/src/feature/nodelist/microdesc.c index 3f5085412f..8c5a9ee611 100644 --- a/src/feature/nodelist/microdesc.c +++ b/src/feature/nodelist/microdesc.c @@ -110,8 +110,9 @@ microdesc_note_outdated_dirserver(const char *relay_digest) /* If we have a reasonably live consensus, then most of our dirservers should * still be caching all the microdescriptors in it. Reasonably live - * consensuses are up to a day old. But microdescriptors expire 7 days after - * the last consensus that referenced them. */ + * consensuses are up to a day old (or a day in the future). But + * microdescriptors expire 7 days after the last consensus that referenced + * them. */ if (!networkstatus_get_reasonably_live_consensus(approx_time(), FLAV_MICRODESC)) { return; @@ -544,8 +545,8 @@ microdesc_cache_clean(microdesc_cache_t *cache, time_t cutoff, int force) size_t bytes_dropped = 0; time_t now = time(NULL); - /* If we don't know a live consensus, don't believe last_listed values: we - * might be starting up after being down for a while. */ + /* If we don't know a reasonably live consensus, don't believe last_listed + * values: we might be starting up after being down for a while. */ if (! force && ! networkstatus_get_reasonably_live_consensus(now, FLAV_MICRODESC)) return; @@ -973,6 +974,7 @@ update_microdesc_downloads(time_t now) if (directory_too_idle_to_fetch_descriptors(options, now)) return; + /* Give up if we don't have a reasonably live consensus. */ consensus = networkstatus_get_reasonably_live_consensus(now, FLAV_MICRODESC); if (!consensus) return; diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index 51e720a984..a40c3dfb22 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -1377,7 +1377,7 @@ networkstatus_get_dl_status_by_flavor_running,(consensus_flavor_t flavor)) } /** Return the most recent consensus that we have downloaded, or NULL if we - * don't have one. */ + * don't have one. May return future or expired consensuses. */ MOCK_IMPL(networkstatus_t *, networkstatus_get_latest_consensus,(void)) { @@ -1388,7 +1388,7 @@ networkstatus_get_latest_consensus,(void)) } /** Return the latest consensus we have whose flavor matches f, or NULL - * if we don't have one. */ + * if we don't have one. May return future or expired consensuses. */ MOCK_IMPL(networkstatus_t *, networkstatus_get_latest_consensus_by_flavor,(consensus_flavor_t f)) { @@ -1422,10 +1422,11 @@ networkstatus_is_live(const networkstatus_t *ns, time_t now) return (ns->valid_after <= now && now <= ns->valid_until); } -/** Determine if consensus is valid or expired recently enough that - * we can still use it. +/** Determine if consensus is valid, or expired recently enough, or not + * too far in the future, so that we can still use it. * - * Return 1 if the consensus is reasonably live, or 0 if it is too old. + * Return 1 if the consensus is reasonably live, or 0 if it is too old or + * too new. */ int networkstatus_consensus_reasonably_live(const networkstatus_t *consensus, @@ -1434,29 +1435,42 @@ networkstatus_consensus_reasonably_live(const networkstatus_t *consensus, if (BUG(!consensus)) return 0; - return networkstatus_valid_until_is_reasonably_live(consensus->valid_until, + return networkstatus_valid_after_is_reasonably_live(consensus->valid_after, + now) && + networkstatus_valid_until_is_reasonably_live(consensus->valid_until, now); } +#define REASONABLY_LIVE_TIME (24*60*60) + +/** As networkstatus_consensus_reasonably_live, but takes a valid_after + * time, and checks to see if it is in the past, or not too far in the future. + */ +int +networkstatus_valid_after_is_reasonably_live(time_t valid_after, + time_t now) +{ + return (now >= valid_after - REASONABLY_LIVE_TIME); +} + /** As networkstatus_consensus_reasonably_live, but takes a valid_until - * time rather than an entire consensus. */ + * time, and checks to see if it is in the future, or not too far in the past. + */ int networkstatus_valid_until_is_reasonably_live(time_t valid_until, time_t now) { -#define REASONABLY_LIVE_TIME (24*60*60) return (now <= valid_until + REASONABLY_LIVE_TIME); } /** As networkstatus_get_live_consensus(), but is way more tolerant of expired - * consensuses. */ + * and future consensuses. */ MOCK_IMPL(networkstatus_t *, networkstatus_get_reasonably_live_consensus,(time_t now, int flavor)) { networkstatus_t *consensus = networkstatus_get_latest_consensus_by_flavor(flavor); if (consensus && - consensus->valid_after <= now && networkstatus_consensus_reasonably_live(consensus, now)) return consensus; else @@ -2082,7 +2096,6 @@ networkstatus_set_current_consensus(const char *consensus, nodelist_set_consensus(c); - /* XXXXNM Microdescs: needs a non-ns variant. ???? NM*/ update_consensus_networkstatus_fetch_time(now); /* Change the cell EWMA settings */ diff --git a/src/feature/nodelist/networkstatus.h b/src/feature/nodelist/networkstatus.h index 7b1a0ff72f..6f1d15d532 100644 --- a/src/feature/nodelist/networkstatus.h +++ b/src/feature/nodelist/networkstatus.h @@ -87,6 +87,8 @@ MOCK_DECL(networkstatus_t *, networkstatus_get_live_consensus,(time_t now)); int networkstatus_is_live(const networkstatus_t *ns, time_t now); int networkstatus_consensus_reasonably_live(const networkstatus_t *consensus, time_t now); +int networkstatus_valid_after_is_reasonably_live(time_t valid_after, + time_t now); int networkstatus_valid_until_is_reasonably_live(time_t valid_until, time_t now); MOCK_DECL(networkstatus_t *,networkstatus_get_reasonably_live_consensus, diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index 52b87a84a8..348c642a23 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -127,6 +127,9 @@ big_fake_network_cleanup(const struct testcase_t *testcase, void *ptr) return 1; /* NOP */ } +#define REASONABLY_FUTURE " reasonably-future" +#define REASONABLY_PAST " reasonably-past" + /* Unittest setup function: Setup a fake network. */ static void * big_fake_network_setup(const struct testcase_t *testcase) @@ -138,9 +141,10 @@ big_fake_network_setup(const struct testcase_t *testcase) const int N_NODES = 271; const char *argument = testcase->setup_data; - int reasonably_live_consensus = 0; + int reasonably_future_consensus = 0, reasonably_past_consensus = 0; if (argument) { - reasonably_live_consensus = strstr(argument, "reasonably-live") != NULL; + reasonably_future_consensus = strstr(argument, REASONABLY_FUTURE) != NULL; + reasonably_past_consensus = strstr(argument, REASONABLY_PAST) != NULL; } big_fake_net_nodes = smartlist_new(); @@ -198,11 +202,15 @@ big_fake_network_setup(const struct testcase_t *testcase) dummy_state = tor_malloc_zero(sizeof(or_state_t)); dummy_consensus = tor_malloc_zero(sizeof(networkstatus_t)); - if (reasonably_live_consensus) { - /* Make the dummy consensus valid from 4 hours ago, but expired an hour + if (reasonably_future_consensus) { + /* Make the dummy consensus valid in 6 hours, and expiring in 7 hours. */ + dummy_consensus->valid_after = approx_time() + 6*3600; + dummy_consensus->valid_until = approx_time() + 7*3600; + } else if (reasonably_past_consensus) { + /* Make the dummy consensus valid from 16 hours ago, but expired 12 hours * ago. */ - dummy_consensus->valid_after = approx_time() - 4*3600; - dummy_consensus->valid_until = approx_time() - 3600; + dummy_consensus->valid_after = approx_time() - 16*3600; + dummy_consensus->valid_until = approx_time() - 12*3600; } else { /* Make the dummy consensus valid for an hour either side of now. */ dummy_consensus->valid_after = approx_time() - 3600; @@ -3035,13 +3043,17 @@ static const struct testcase_setup_t upgrade_circuits = { #define BFN_TEST(name) \ EN_TEST_BASE(name, TT_FORK, &big_fake_network, NULL), \ - { #name "_reasonably_live", test_entry_guard_ ## name, TT_FORK, \ - &big_fake_network, (void*)("reasonably-live") } + { #name "_reasonably_future", test_entry_guard_ ## name, TT_FORK, \ + &big_fake_network, (void*)(REASONABLY_FUTURE) }, \ + { #name "_reasonably_past", test_entry_guard_ ## name, TT_FORK, \ + &big_fake_network, (void*)(REASONABLY_PAST) } #define UPGRADE_TEST(name, arg) \ EN_TEST_BASE(name, TT_FORK, &upgrade_circuits, arg), \ - { #name "_reasonably_live", test_entry_guard_ ## name, TT_FORK, \ - &upgrade_circuits, (void*)(arg " reasonably-live") } + { #name "_reasonably_future", test_entry_guard_ ## name, TT_FORK, \ + &upgrade_circuits, (void*)(arg REASONABLY_FUTURE) }, \ + { #name "_reasonably_past", test_entry_guard_ ## name, TT_FORK, \ + &upgrade_circuits, (void*)(arg REASONABLY_PAST) } struct testcase_t entrynodes_tests[] = { NO_PREFIX_TEST(node_preferred_orport), diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c index 67af2fd484..6ba4877b91 100644 --- a/src/test/test_routerlist.c +++ b/src/test/test_routerlist.c @@ -301,7 +301,6 @@ test_router_pick_directory_server_impl(void *arg) tt_assert(!networkstatus_consensus_is_bootstrapping(con_md->valid_until + 24*60*60)); /* These times are outside the test validity period */ - tt_assert(networkstatus_consensus_is_bootstrapping(now)); tt_assert(networkstatus_consensus_is_bootstrapping(now + 2*24*60*60)); tt_assert(networkstatus_consensus_is_bootstrapping(now - 2*24*60*60)); -- cgit v1.2.3-54-g00ecf From 7685f8ad35f8662e8af149ae4e530677646f88a0 Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Mon, 19 Nov 2018 19:43:23 -0600 Subject: Use table lookup for bootstrap_status_to_string It also no longer distinguishes the case of internal-only paths, which was often wrong anyway. Closes ticket 27402. --- changes/ticket27402 | 10 +++ src/feature/control/control_bootstrap.c | 129 +++++++++++--------------------- 2 files changed, 52 insertions(+), 87 deletions(-) create mode 100644 changes/ticket27402 (limited to 'changes') diff --git a/changes/ticket27402 b/changes/ticket27402 new file mode 100644 index 0000000000..b79fb56760 --- /dev/null +++ b/changes/ticket27402 @@ -0,0 +1,10 @@ + o Minor feature (bootstrap): + - When reporting bootstrap progress, stop distinguishing between + situations where it seems that only internal paths are available + and situations where it seems that external paths are available. + Previously, tor would often erroneously report that it had only + internal paths. Closes ticket 27402. + + o Code simplification and refactoring: + - Split out bootstrap progress reporting from control.c into a + separate file. Part of ticket 27402. diff --git a/src/feature/control/control_bootstrap.c b/src/feature/control/control_bootstrap.c index 58b342c219..7299757f91 100644 --- a/src/feature/control/control_bootstrap.c +++ b/src/feature/control/control_bootstrap.c @@ -16,7 +16,6 @@ #include "core/or/reasons.h" #include "feature/control/control.h" #include "feature/hibernate/hibernate.h" -#include "feature/nodelist/nodelist.h" #include "lib/malloc/malloc.h" /** A sufficiently large size to record the last bootstrap phase string. */ @@ -26,99 +25,55 @@ * of this so we can respond to getinfo status/bootstrap-phase queries. */ static char last_sent_bootstrap_message[BOOTSTRAP_MSG_LEN]; +/** Table to convert bootstrap statuses to strings. */ +static const struct { + bootstrap_status_t status; + const char *tag; + const char *summary; +} boot_to_str_tab[] = { + { BOOTSTRAP_STATUS_UNDEF, "undef", "Undefined" }, + { BOOTSTRAP_STATUS_STARTING, "starting", "Starting" }, + { BOOTSTRAP_STATUS_CONN_DIR, "conn_dir", "Connecting to directory server" }, + { BOOTSTRAP_STATUS_HANDSHAKE, "status_handshake", "Finishing handshake" }, + { BOOTSTRAP_STATUS_HANDSHAKE_DIR, "handshake_dir", + "Finishing handshake with directory server" }, + { BOOTSTRAP_STATUS_ONEHOP_CREATE, "onehop_create", + "Establishing an encrypted directory connection" }, + { BOOTSTRAP_STATUS_REQUESTING_STATUS, "requesting_status", + "Asking for networkstatus consensus" }, + { BOOTSTRAP_STATUS_LOADING_STATUS, "loading_status", + "Loading networkstatus consensus" }, + { BOOTSTRAP_STATUS_LOADING_KEYS, "loading_keys", + "Loading authority key certs" }, + { BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, "requesting_descriptors", + "Asking for relay descriptors" }, + { BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, "loading_descriptors", + "Loading relay descriptors" }, + { BOOTSTRAP_STATUS_CONN_OR, "conn_or", "Connecting to the Tor network" }, + { BOOTSTRAP_STATUS_HANDSHAKE_OR, "handshake_or", + "Finishing handshake with first hop" }, + { BOOTSTRAP_STATUS_CIRCUIT_CREATE, "circuit_create", + "Establishing a Tor circuit" }, + { BOOTSTRAP_STATUS_DONE, "done", "Done" }, +}; +#define N_BOOT_TO_STR (sizeof(boot_to_str_tab)/sizeof(boot_to_str_tab[0])) + /** Convert the name of a bootstrapping phase s into strings * tag and summary suitable for display by the controller. */ static int bootstrap_status_to_string(bootstrap_status_t s, const char **tag, const char **summary) { - switch (s) { - case BOOTSTRAP_STATUS_UNDEF: - *tag = "undef"; - *summary = "Undefined"; - break; - case BOOTSTRAP_STATUS_STARTING: - *tag = "starting"; - *summary = "Starting"; - break; - case BOOTSTRAP_STATUS_CONN_DIR: - *tag = "conn_dir"; - *summary = "Connecting to directory server"; - break; - case BOOTSTRAP_STATUS_HANDSHAKE: - *tag = "status_handshake"; - *summary = "Finishing handshake"; - break; - case BOOTSTRAP_STATUS_HANDSHAKE_DIR: - *tag = "handshake_dir"; - *summary = "Finishing handshake with directory server"; - break; - case BOOTSTRAP_STATUS_ONEHOP_CREATE: - *tag = "onehop_create"; - *summary = "Establishing an encrypted directory connection"; - break; - case BOOTSTRAP_STATUS_REQUESTING_STATUS: - *tag = "requesting_status"; - *summary = "Asking for networkstatus consensus"; - break; - case BOOTSTRAP_STATUS_LOADING_STATUS: - *tag = "loading_status"; - *summary = "Loading networkstatus consensus"; - break; - case BOOTSTRAP_STATUS_LOADING_KEYS: - *tag = "loading_keys"; - *summary = "Loading authority key certs"; - break; - case BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS: - *tag = "requesting_descriptors"; - /* XXXX this appears to incorrectly report internal on most loads */ - *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ? - "Asking for relay descriptors for internal paths" : - "Asking for relay descriptors"; - break; - /* If we're sure there are no exits in the consensus, - * inform the controller by adding "internal" - * to the status summaries. - * (We only check this while loading descriptors, - * so we may not know in the earlier stages.) - * But if there are exits, we can't be sure whether - * we're creating internal or exit paths/circuits. - * XXXX Or should be use different tags or statuses - * for internal and exit/all? */ - case BOOTSTRAP_STATUS_LOADING_DESCRIPTORS: - *tag = "loading_descriptors"; - *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ? - "Loading relay descriptors for internal paths" : - "Loading relay descriptors"; - break; - case BOOTSTRAP_STATUS_CONN_OR: - *tag = "conn_or"; - *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ? - "Connecting to the Tor network internally" : - "Connecting to the Tor network"; - break; - case BOOTSTRAP_STATUS_HANDSHAKE_OR: - *tag = "handshake_or"; - *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ? - "Finishing handshake with first hop of internal circuit" : - "Finishing handshake with first hop"; - break; - case BOOTSTRAP_STATUS_CIRCUIT_CREATE: - *tag = "circuit_create"; - *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ? - "Establishing an internal Tor circuit" : - "Establishing a Tor circuit"; - break; - case BOOTSTRAP_STATUS_DONE: - *tag = "done"; - *summary = "Done"; - break; - default: -// log_warn(LD_BUG, "Unrecognized bootstrap status code %d", s); - *tag = *summary = "unknown"; - return -1; + for (size_t i = 0; i < N_BOOT_TO_STR; i++) { + if (s == boot_to_str_tab[i].status) { + *tag = boot_to_str_tab[i].tag; + *summary = boot_to_str_tab[i].summary; + return 0; + } } - return 0; + + *tag = *summary = "unknown"; + return -1; } /** What percentage through the bootstrap process are we? We remember -- cgit v1.2.3-54-g00ecf From 009205dabe4ba7aba43dffead4087ca94ef9a8e3 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Thu, 13 Sep 2018 10:18:06 +0300 Subject: Add changes file --- changes/ticket27620 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket27620 (limited to 'changes') diff --git a/changes/ticket27620 b/changes/ticket27620 new file mode 100644 index 0000000000..6c491696d0 --- /dev/null +++ b/changes/ticket27620 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Rework SOCKS wire format handling to rely on trunnel-generated + parsing/generation code. Resolves ticket 27620. -- cgit v1.2.3-54-g00ecf From 822cb93cab59e9735e2efda70bc88c47cc92c498 Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Wed, 26 Sep 2018 19:14:33 -0400 Subject: Add new option ClientAutoIPv6ORPort to switch between IPv4 and IPv6 OR ports --- changes/ticket27490 | 6 ++++++ doc/tor.1.txt | 6 ++++++ src/app/config/config.c | 1 + src/app/config/or_options_st.h | 3 +++ src/core/mainloop/connection.c | 5 +++++ src/core/or/policies.c | 15 ++++++++++++++- src/feature/client/bridges.c | 3 ++- 7 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 changes/ticket27490 (limited to 'changes') diff --git a/changes/ticket27490 b/changes/ticket27490 new file mode 100644 index 0000000000..523477dfea --- /dev/null +++ b/changes/ticket27490 @@ -0,0 +1,6 @@ + o Minor features (ipv6): + - We add an option ClientAutoIPv6ORPort which makes clients randomly + prefer a node's IPv4 or IPv6 ORPort. The random preference is set + every time a node is loaded from a new consensus or bridge config. + Closes ticket 27490. Patch by Neel Chauhan. + diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 406372433f..bd4dbbcbdb 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -1748,6 +1748,12 @@ The following options are useful only for clients (that is, if other clients prefer IPv4. Other things may influence the choice. This option breaks a tie to the favor of IPv6. (Default: auto) +[[ClientAutoIPv6ORPort]] **ClientAutoIPv6ORPort** **0**|**1**:: + If this option is set to 1, Tor clients randomly prefer a node's IPv4 or + IPv6 ORPort. The random preference is set every time a node is loaded + from a new consensus or bridge config. When this option is set to 1, + **ClientPreferIPv6ORPort** is ignored. (Default: 0) + [[PathsNeededToBuildCircuits]] **PathsNeededToBuildCircuits** __NUM__:: Tor clients don't build circuits for user traffic until they know about enough of the network so that they could potentially construct diff --git a/src/app/config/config.c b/src/app/config/config.c index 01b48e3c5f..6a510c56da 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -332,6 +332,7 @@ static config_var_t option_vars_[] = { V(ClientOnly, BOOL, "0"), V(ClientPreferIPv6ORPort, AUTOBOOL, "auto"), V(ClientPreferIPv6DirPort, AUTOBOOL, "auto"), + V(ClientAutoIPv6ORPort, BOOL, "0"), V(ClientRejectInternalAddresses, BOOL, "1"), V(ClientTransportPlugin, LINELIST, NULL), V(ClientUseIPv6, BOOL, "0"), diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h index 3524b99b53..ff3d30d7ec 100644 --- a/src/app/config/or_options_st.h +++ b/src/app/config/or_options_st.h @@ -666,6 +666,9 @@ struct or_options_t { * accessing this value directly. */ int ClientPreferIPv6DirPort; + /** If true, prefer an IPv4 or IPv6 OR port at random. */ + int ClientAutoIPv6ORPort; + /** The length of time that we think a consensus should be fresh. */ int V3AuthVotingInterval; /** The length of time we think it will take to distribute votes. */ diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c index 4231bec014..9f8169082c 100644 --- a/src/core/mainloop/connection.c +++ b/src/core/mainloop/connection.c @@ -2069,6 +2069,11 @@ connection_connect_log_client_use_ip_version(const connection_t *conn) return; } + if (fascist_firewall_use_ipv6(options)) { + log_info(LD_NET, "Our outgoing connection is using IPv%d.", + tor_addr_family(&real_addr) == AF_INET6 ? 6 : 4); + } + /* Check if we couldn't satisfy an address family preference */ if ((!pref_ipv6 && tor_addr_family(&real_addr) == AF_INET6) || (pref_ipv6 && tor_addr_family(&real_addr) == AF_INET)) { diff --git a/src/core/or/policies.c b/src/core/or/policies.c index 3443a17107..e51a49cf60 100644 --- a/src/core/or/policies.c +++ b/src/core/or/policies.c @@ -28,6 +28,7 @@ #include "feature/nodelist/routerparse.h" #include "feature/stats/geoip.h" #include "ht.h" +#include "lib/crypt_ops/crypto_rand.h" #include "lib/encoding/confline.h" #include "core/or/addr_policy_st.h" @@ -487,6 +488,15 @@ fascist_firewall_prefer_ipv6_impl(const or_options_t *options) return -1; } +/* Choose whether we prefer IPv4 or IPv6 by randomly choosing an address + * family. Return 0 for IPv4, and 1 for IPv6. */ +static int +fascist_firewall_rand_prefer_ipv6_addr(void) +{ + /* TODO: Check for failures, and infer our preference based on this. */ + return crypto_rand_int(2); +} + /** Do we prefer to connect to IPv6 ORPorts? * Use node_ipv6_or_preferred() whenever possible: it supports bridge client * per-node IPv6 preferences. @@ -501,7 +511,10 @@ fascist_firewall_prefer_ipv6_orport(const or_options_t *options) } /* We can use both IPv4 and IPv6 - which do we prefer? */ - if (options->ClientPreferIPv6ORPort == 1) { + if (options->ClientAutoIPv6ORPort == 1) { + /* If ClientAutoIPv6ORPort is 1, we prefer IPv4 or IPv6 at random. */ + return fascist_firewall_rand_prefer_ipv6_addr(); + } else if (options->ClientPreferIPv6ORPort == 1) { return 1; } diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c index e8afb5a924..e3ed288415 100644 --- a/src/feature/client/bridges.c +++ b/src/feature/client/bridges.c @@ -844,7 +844,8 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) } } - if (options->ClientPreferIPv6ORPort == -1) { + if (options->ClientPreferIPv6ORPort == -1 || + options->ClientAutoIPv6ORPort == 0) { /* Mark which address to use based on which bridge_t we got. */ node->ipv6_preferred = (tor_addr_family(&bridge->addr) == AF_INET6 && !tor_addr_is_null(&node->ri->ipv6_addr)); -- cgit v1.2.3-54-g00ecf From 894d207f844cf5fa5816432abfe8d1c02763cd59 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Mon, 3 Dec 2018 15:19:33 +0200 Subject: manpage: Mention that adding new HS is unsupported if Sandbox is enabled --- changes/doc28560 | 3 +++ doc/tor.1.txt | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 changes/doc28560 (limited to 'changes') diff --git a/changes/doc28560 b/changes/doc28560 new file mode 100644 index 0000000000..c3356bda0a --- /dev/null +++ b/changes/doc28560 @@ -0,0 +1,3 @@ + o Documentation (hidden service manpage, sandbox): + - Mention that you cannot add new Onion Service if Tor is already + running with Sandbox enabled. Closes ticket 28560. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 8e6ec7f1a2..dbfb6358c4 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -610,7 +610,8 @@ GENERAL OPTIONS Logs ServerDNSResolvConfFile Tor must remain in client or server mode (some changes to ClientOnly and - ORPort are not allowed). + ORPort are not allowed). Launching new Onion Services through Control + Port is not supported with current syscall sandboxing implementation. ClientOnionAuthDir and any files in it won't reload on HUP signal. (Default: 0) @@ -2821,6 +2822,8 @@ The following options are used to configure a hidden service. Store data files for a hidden service in DIRECTORY. Every hidden service must have a separate directory. You may use this option multiple times to specify multiple services. If DIRECTORY does not exist, Tor will create it. + Please note that you cannot add new Onion Service to already running Tor + instance if **Sandbox** is enabled. (Note: in current versions of Tor, if DIRECTORY is a relative path, it will be relative to the current working directory of Tor instance, not to its DataDirectory. Do not -- cgit v1.2.3-54-g00ecf From ecaecaddd89ce0d89e5f90effbf066065ccccd10 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Thu, 6 Dec 2018 15:31:33 +0200 Subject: Add changes file --- changes/ticket28551 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket28551 (limited to 'changes') diff --git a/changes/ticket28551 b/changes/ticket28551 new file mode 100644 index 0000000000..46ba9d713b --- /dev/null +++ b/changes/ticket28551 @@ -0,0 +1,3 @@ + o Minor features (Continuous Integration): + - Log Python version during each Travis CI job. Resolves issue + 28551. -- cgit v1.2.3-54-g00ecf From 766fd6cf7666cecc25a94e6cfe46b8b27188ff5d Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 7 Dec 2018 09:29:39 +1000 Subject: Fallbacks: use a 24 hour consensus expiry tolerance Tor clients will use a consensus that expired up to 24 hours ago. Clients on 0.3.5.5-alpha? and earlier won't select guards from an expired consensus, but they can still bootstrap if they have existing guards. Update the fallback expiry tolerance to match tor's checks. Part of 28768, follow-up on 24661. --- changes/ticket28768 | 4 ++++ scripts/maint/updateFallbackDirs.py | 29 +++++++++++++++++------------ 2 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 changes/ticket28768 (limited to 'changes') diff --git a/changes/ticket28768 b/changes/ticket28768 new file mode 100644 index 0000000000..ce991c8a42 --- /dev/null +++ b/changes/ticket28768 @@ -0,0 +1,4 @@ + o Minor features (fallback directory mirrors): + - Accept fallbacks that deliver reasonably live consensuses. + (Consensuses that expired less than 24 hours ago.) + Closes ticket 28768. diff --git a/scripts/maint/updateFallbackDirs.py b/scripts/maint/updateFallbackDirs.py index cf923bfa32..41c4da675e 100755 --- a/scripts/maint/updateFallbackDirs.py +++ b/scripts/maint/updateFallbackDirs.py @@ -98,19 +98,24 @@ MUST_BE_RUNNING_NOW = (PERFORM_IPV4_DIRPORT_CHECKS # Clients have been using microdesc consensuses by default for a while now DOWNLOAD_MICRODESC_CONSENSUS = True -# If a relay delivers an expired consensus, if it expired less than this many -# seconds ago, we still allow the relay. This should never be less than -90, -# as all directory mirrors should have downloaded a consensus 90 minutes -# before it expires. It should never be more than 24 hours, because clients -# reject consensuses that are older than REASONABLY_LIVE_TIME. -# For the consensus expiry check to be accurate, the machine running this -# script needs an accurate clock. +# If a relay delivers an invalid consensus, if it expired less than this many +# seconds ago, accept the relay as a fallback. For the consensus expiry check +# to be accurate, the machine running this script needs an accurate clock. # -# Relays on 0.3.0 and later return a 404 when they are about to serve an -# expired consensus. This makes them fail the download check. -# We use a tolerance of 0, so that 0.2.x series relays also fail the download -# check if they serve an expired consensus. -CONSENSUS_EXPIRY_TOLERANCE = 0 +# Relays on 0.3.0 and later return a 404 when they are about to serve a +# consensus that expired more than 24 hours ago. 0.2.9 and earlier relays +# will serve consensuses that are very old. +# +# A 404 makes relays fail the download check. We use a tolerance of 24 hours, +# so that 0.2.9 relays also fail the download check if they serve a consensus +# that is not reasonably live. +# +# CONSENSUS_EXPIRY_TOLERANCE should never be more than 24 hours, because +# clients reject consensuses that are older than REASONABLY_LIVE_TIME. Clients +# on 0.3.5.5-alpha? and earlier also won't select guards from consensuses that +# have expired, but can bootstrap if they already have guards in their state +# file. +CONSENSUS_EXPIRY_TOLERANCE = 24*60*60 # Output fallback name, flags, bandwidth, and ContactInfo in a C comment? OUTPUT_COMMENTS = True if OUTPUT_CANDIDATES else False -- cgit v1.2.3-54-g00ecf From c3fe405e217d1551b3a58f2469f05650dd9d7579 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 7 Dec 2018 09:41:28 +1000 Subject: Fallbacks: use a 24 hour future consensus tolerance Tor clients on 0.3.5.6-rc? and later will use a consensus that will become valid up to 24 hours in the future. Clients on 0.3.5.5-alpha? and earlier won't accept future consensuses. Update the fallback expiry tolerance to match tor's checks. Part of 28768, follow-up on 28591. --- changes/ticket28768 | 4 ++-- scripts/maint/updateFallbackDirs.py | 21 ++++++++++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) (limited to 'changes') diff --git a/changes/ticket28768 b/changes/ticket28768 index ce991c8a42..27d90febc8 100644 --- a/changes/ticket28768 +++ b/changes/ticket28768 @@ -1,4 +1,4 @@ o Minor features (fallback directory mirrors): - Accept fallbacks that deliver reasonably live consensuses. - (Consensuses that expired less than 24 hours ago.) - Closes ticket 28768. + (Consensuses that will become valid less than 24 hours in the future, + or that expired less than 24 hours ago.) Closes ticket 28768. diff --git a/scripts/maint/updateFallbackDirs.py b/scripts/maint/updateFallbackDirs.py index 41c4da675e..142d468273 100755 --- a/scripts/maint/updateFallbackDirs.py +++ b/scripts/maint/updateFallbackDirs.py @@ -98,14 +98,19 @@ MUST_BE_RUNNING_NOW = (PERFORM_IPV4_DIRPORT_CHECKS # Clients have been using microdesc consensuses by default for a while now DOWNLOAD_MICRODESC_CONSENSUS = True -# If a relay delivers an invalid consensus, if it expired less than this many -# seconds ago, accept the relay as a fallback. For the consensus expiry check -# to be accurate, the machine running this script needs an accurate clock. +# If a relay delivers an invalid consensus, if it will become valid less than +# this many seconds in the future, or expired less than this many seconds ago, +# accept the relay as a fallback. For the consensus expiry check to be +# accurate, the machine running this script needs an accurate clock. # # Relays on 0.3.0 and later return a 404 when they are about to serve a # consensus that expired more than 24 hours ago. 0.2.9 and earlier relays # will serve consensuses that are very old. # +# Relays on 0.3.5.6-rc? and later return a 404 when they are about to serve a +# consensus that will become valid more than 24 hours in the future. Older +# relays don't serve future consensuses. +# # A 404 makes relays fail the download check. We use a tolerance of 24 hours, # so that 0.2.9 relays also fail the download check if they serve a consensus # that is not reasonably live. @@ -1127,6 +1132,7 @@ class Candidate(object): ).run()[0] end = datetime.datetime.utcnow() time_since_expiry = (end - consensus.valid_until).total_seconds() + time_until_valid = (consensus.valid_after - end).total_seconds() except Exception, stem_error: end = datetime.datetime.utcnow() log_excluded('Unable to retrieve a consensus from %s: %s', nickname, @@ -1151,6 +1157,15 @@ class Candidate(object): status += ', invalid' level = logging.WARNING download_failed = True + elif (time_until_valid > 0): + status = 'future consensus, valid in %ds'%(int(time_until_valid)) + if time_until_valid <= CONSENSUS_EXPIRY_TOLERANCE: + status += ', tolerating up to %ds'%(CONSENSUS_EXPIRY_TOLERANCE) + level = logging.INFO + else: + status += ', invalid' + level = logging.WARNING + download_failed = True else: status = 'ok' level = logging.DEBUG -- cgit v1.2.3-54-g00ecf From 6bc5c06dc25630c5a5f97f1da2af29f88683d243 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 7 Dec 2018 13:23:57 +1000 Subject: Fallbacks: accept relays that are a fuzzy match to the whitelist If a relay matches at least one fingerprint, IPv4 address, or IPv6 address in the fallback whitelist, it can become a fallback. This reduces the work required to keep the list up to date. Closes ticket 28768. --- changes/ticket24838 | 6 ++++++ scripts/maint/fallback.whitelist | 26 ++++++++++++++------------ scripts/maint/updateFallbackDirs.py | 30 ++++++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 14 deletions(-) create mode 100644 changes/ticket24838 (limited to 'changes') diff --git a/changes/ticket24838 b/changes/ticket24838 new file mode 100644 index 0000000000..d068e31b91 --- /dev/null +++ b/changes/ticket24838 @@ -0,0 +1,6 @@ + o Minor features (fallback directory mirrors): + - Accept relays that are a fuzzy match to a fallback whitelist entry. + If a relay matches at least one fingerprint, IPv4 address, or IPv6 + address in the fallback whitelist, it can become a fallback. This + reduces the work required to keep the list up to date. + Closes ticket 24838. diff --git a/scripts/maint/fallback.whitelist b/scripts/maint/fallback.whitelist index 97291d73be..eb7fd92d4b 100644 --- a/scripts/maint/fallback.whitelist +++ b/scripts/maint/fallback.whitelist @@ -1,16 +1,18 @@ # updateFallbackDirs.py directory mirror whitelist - -# All attributes must match for the directory mirror to be included. -# If the fallback has an ipv6 key, the whitelist line must also have -# it, and vice versa, otherwise they don't match. - -# To replace this list with the hard-coded fallback list (for testing), use -# "updateFallbackDirs.py check_existing", or a command similar to: -# cat src/app/config/fallback_dirs.inc | grep \" | grep -v weight | \ -# tr -d '\n' | \ -# sed 's/"" / /g' | sed 's/""/"/g' | tr \" '\n' | grep -v '^$' \ -# > scripts/maint/fallback.whitelist - +# +# At least one of these keys must match for a directory mirror to be included +# in the fallback list: +# id +# ipv4 +# ipv6 +# The ports and nickname are ignored. Missing or extra ipv6 addresses +# are ignored. +# +# The latest relay details from Onionoo are included in the generated list. +# +# To check the hard-coded fallback list (for testing), use: +# $ updateFallbackDirs.py check_existing +# # If a relay operator wants their relay to be a FallbackDir, # enter the following information here: # : orport= id= ( ipv6=[]: )? diff --git a/scripts/maint/updateFallbackDirs.py b/scripts/maint/updateFallbackDirs.py index b334352152..14372d0e83 100755 --- a/scripts/maint/updateFallbackDirs.py +++ b/scripts/maint/updateFallbackDirs.py @@ -1061,14 +1061,40 @@ class Candidate(object): return False return True + def entry_matches_fuzzy(self, entry): + """ Is entry a fuzzy match for this fallback? + A fallback is a fuzzy match for entry if at least one of these keys + in entry matches: + id + ipv4 + ipv6 (if present in both the fallback and whitelist) + The ports and nickname are ignored. Missing or extra ipv6 addresses + are ignored. + + Doesn't log any warning messages. """ + if self.id_matches(entry['id'], exact=False): + return True + if self.ipv4_addr_matches(entry['ipv4'], exact=False): + return True + if entry.has_key('ipv6') and self.has_ipv6(): + # if both entry and fallback have an ipv6 address, compare them + if self.ipv6_addr_matches(entry['ipv6_addr'], exact=False): + return True + return False + def is_in_whitelist(self, relaylist, exact=False): """ If exact is True (existing fallback list), check if this fallback is an exact match for any whitelist entry, using entry_matches_exact(). - """ + + If exact is False (new fallback whitelist), check if this fallback is + a fuzzy match for any whitelist entry, using entry_matches_fuzzy(). """ for entry in relaylist: if exact: if self.entry_matches_exact(entry): return True + else: + if self.entry_matches_fuzzy(entry): + return True return False def cw_to_bw_factor(self): @@ -2193,7 +2219,7 @@ def process_default(): logging.getLogger('stem').setLevel(logging.WARNING) whitelist = {'data': read_from_file(WHITELIST_FILE_NAME, MAX_LIST_FILE_SIZE), 'name': WHITELIST_FILE_NAME} - list_fallbacks(whitelist, exact=True) + list_fallbacks(whitelist, exact=False) ## Main Function def main(): -- cgit v1.2.3-54-g00ecf From d9b9c1fa76dacacd502141aeca08c5a9722d0898 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 7 Dec 2018 17:03:46 +1000 Subject: Changes file for 24805 --- changes/ticket24805 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket24805 (limited to 'changes') diff --git a/changes/ticket24805 b/changes/ticket24805 new file mode 100644 index 0000000000..4ba6f6ecd4 --- /dev/null +++ b/changes/ticket24805 @@ -0,0 +1,3 @@ + o Minor features (fallback directory list): + - Update the fallback whitelist based on operator opt-ins and opt-outs. + Closes ticket 24805, patch by Phoul. -- cgit v1.2.3-54-g00ecf From c037bf58173db56766381a7c1cd5973789f0fd0f Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 4 Dec 2018 12:11:42 -0500 Subject: changes file for ticket26864 --- changes/ticket28624 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/ticket28624 (limited to 'changes') diff --git a/changes/ticket28624 b/changes/ticket28624 new file mode 100644 index 0000000000..353f962be9 --- /dev/null +++ b/changes/ticket28624 @@ -0,0 +1,5 @@ + o Minor features (battery management, client, dormant mode): + - The client's memory of whether it is "dormant", and how long it has + spend idle, persists across invocations. Implements ticket 28624. + - There is a DormantOnFirstStartup option that integrators can use if + they expect that in many cases, Tor will be installed but not used. -- cgit v1.2.3-54-g00ecf From 4bc3983f64ab2a60a79127f47573836373ddf587 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 13 Dec 2018 19:35:02 -0500 Subject: Add a DROPOWNERSHIP controller command to undo TAKEOWNERSHIP. Closes ticket 28843. --- changes/ticket28843 | 3 +++ src/feature/control/control.c | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 changes/ticket28843 (limited to 'changes') diff --git a/changes/ticket28843 b/changes/ticket28843 new file mode 100644 index 0000000000..00905293c4 --- /dev/null +++ b/changes/ticket28843 @@ -0,0 +1,3 @@ + o Minor features (controller): + - Add a DROPOWNERSHIP command to undo the effects of TAKEOWNERSHIP. + Implements ticket 28843. diff --git a/src/feature/control/control.c b/src/feature/control/control.c index c2da7fe48b..50f43c0f44 100644 --- a/src/feature/control/control.c +++ b/src/feature/control/control.c @@ -1741,6 +1741,26 @@ handle_control_takeownership(control_connection_t *conn, uint32_t len, return 0; } +/** Called when we get a DROPOWNERSHIP command. Mark this connection + * as a non-owning connection, so that we will not exit if the connection + * closes. */ +static int +handle_control_dropownership(control_connection_t *conn, uint32_t len, + const char *body) +{ + (void)len; + (void)body; + + conn->is_owning_control_connection = 0; + + log_info(LD_CONTROL, "Control connection %d has dropped ownership of this " + "Tor instance.", + (int)(conn->base_.s)); + + send_control_done(conn); + return 0; +} + /** Return true iff addr is unusable as a mapaddress target because of * containing funny characters. */ static int @@ -5548,6 +5568,9 @@ connection_control_process_inbuf(control_connection_t *conn) } else if (!strcasecmp(conn->incoming_cmd, "TAKEOWNERSHIP")) { if (handle_control_takeownership(conn, cmd_data_len, args)) return -1; + } else if (!strcasecmp(conn->incoming_cmd, "DROPOWNERSHIP")) { + if (handle_control_dropownership(conn, cmd_data_len, args)) + return -1; } else if (!strcasecmp(conn->incoming_cmd, "MAPADDRESS")) { if (handle_control_mapaddress(conn, cmd_data_len, args)) return -1; -- cgit v1.2.3-54-g00ecf From 06046c726fb09ec745d2a565abfef28097856a19 Mon Sep 17 00:00:00 2001 From: Matt Traudt Date: Fri, 14 Dec 2018 09:24:19 -0500 Subject: Add changes file for <30min HeartbeatPeriod patch --- changes/ticket28840 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket28840 (limited to 'changes') diff --git a/changes/ticket28840 b/changes/ticket28840 new file mode 100644 index 0000000000..05d3fbb94c --- /dev/null +++ b/changes/ticket28840 @@ -0,0 +1,3 @@ + o Minor features (testing): + - Allow HeartbeatPeriod of less than 30 minutes in testing Tor networks. + Closes ticket 28840, patch by robgjansen -- cgit v1.2.3-54-g00ecf From 9dc53bc68f5e038c9531e3b12a58026d4007f652 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 14 Dec 2018 14:48:12 -0500 Subject: Remove a needless memset() in get_token_arguments() I believe we originally added this for "just in case" safety, but it isn't actually needed -- we never copy uninitialized stack here. What's more, this one memset is showing up on our startup profiles, so we ought to remove it. Closes ticket 28852. --- changes/ticket28852 | 4 ++++ src/feature/dirparse/parsecommon.c | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/ticket28852 (limited to 'changes') diff --git a/changes/ticket28852 b/changes/ticket28852 new file mode 100644 index 0000000000..a58cc3ba0e --- /dev/null +++ b/changes/ticket28852 @@ -0,0 +1,4 @@ + o Minor features (performance): + - Remove a needless memset() call from get_token_arguments, + thereby speeding up the tokenization of directory objects by about + 20%. Closes ticket 28852. diff --git a/src/feature/dirparse/parsecommon.c b/src/feature/dirparse/parsecommon.c index e00af0eea2..5280f2ed2f 100644 --- a/src/feature/dirparse/parsecommon.c +++ b/src/feature/dirparse/parsecommon.c @@ -169,7 +169,6 @@ get_token_arguments(memarea_t *area, directory_token_t *tok, char *cp = mem; int j = 0; char *args[MAX_ARGS]; - memset(args, 0, sizeof(args)); while (*cp) { if (j == MAX_ARGS) return -1; -- cgit v1.2.3-54-g00ecf From 3dd1f064a7d5708585f88beffaf3897ba6555208 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 14 Dec 2018 16:07:10 -0500 Subject: Rewrite the core of parse_short_policy() to be faster. The old implementation did some funky out-of-order lexing, and tended to parse every port twice if the %d-%d pattern didn't match. Closes ticket 28853. --- changes/ticket28853 | 3 ++ src/core/or/policies.c | 80 ++++++++++++++++++++++++++------------------------ 2 files changed, 45 insertions(+), 38 deletions(-) create mode 100644 changes/ticket28853 (limited to 'changes') diff --git a/changes/ticket28853 b/changes/ticket28853 new file mode 100644 index 0000000000..e76f6bd8c9 --- /dev/null +++ b/changes/ticket28853 @@ -0,0 +1,3 @@ + o Minor features (performance): + - Replace parse_short_policy() with a faster implementation, to improve + microdescriptor parsing time. Closes ticket 28853. diff --git a/src/core/or/policies.c b/src/core/or/policies.c index 123fc8566e..bffdb1fddd 100644 --- a/src/core/or/policies.c +++ b/src/core/or/policies.c @@ -2720,7 +2720,7 @@ parse_short_policy(const char *summary) int is_accept; int n_entries; short_policy_entry_t entries[MAX_EXITPOLICY_SUMMARY_LEN]; /* overkill */ - const char *next; + char *next; if (!strcmpstart(summary, "accept ")) { is_accept = 1; @@ -2735,57 +2735,56 @@ parse_short_policy(const char *summary) n_entries = 0; for ( ; *summary; summary = next) { - const char *comma = strchr(summary, ','); - unsigned low, high; - char dummy; - char ent_buf[32]; - size_t len; - - next = comma ? comma+1 : strchr(summary, '\0'); - len = comma ? (size_t)(comma - summary) : strlen(summary); - if (n_entries == MAX_EXITPOLICY_SUMMARY_LEN) { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Impossibly long policy summary %s", escaped(orig_summary)); return NULL; } - if (! TOR_ISDIGIT(*summary) || len > (sizeof(ent_buf)-1)) { - /* unrecognized entry format. skip it. */ - continue; - } - if (len < 1) { - /* empty; skip it. */ - /* XXX This happens to be unreachable, since if len==0, then *summary is - * ',' or '\0', and the TOR_ISDIGIT test above would have failed. */ - continue; + unsigned low, high; + int ok; + low = (unsigned) tor_parse_ulong(summary, 10, 1, 65535, &ok, &next); + if (!ok) { + if (! TOR_ISDIGIT(*summary) || *summary == ',') { + /* Unrecognized format: skip it. */ + goto skip_ent; + } else { + goto bad_ent; + } } - memcpy(ent_buf, summary, len); - ent_buf[len] = '\0'; + switch (*next) { + case ',': + ++next; + /* fall through */ + case '\0': + high = low; + break; + case '-': + high = (unsigned) tor_parse_ulong(next+1, 10, low, 65535, &ok, &next); + if (!ok) + goto bad_ent; + + if (*next == ',') + ++next; + else if (*next != '\0') + goto bad_ent; - if (tor_sscanf(ent_buf, "%u-%u%c", &low, &high, &dummy) == 2) { - if (low<1 || low>65535 || high<1 || high>65535 || low>high) { - log_fn(LOG_PROTOCOL_WARN, LD_DIR, - "Found bad entry in policy summary %s", escaped(orig_summary)); - return NULL; - } - } else if (tor_sscanf(ent_buf, "%u%c", &low, &dummy) == 1) { - if (low<1 || low>65535) { - log_fn(LOG_PROTOCOL_WARN, LD_DIR, - "Found bad entry in policy summary %s", escaped(orig_summary)); - return NULL; - } - high = low; - } else { - log_fn(LOG_PROTOCOL_WARN, LD_DIR,"Found bad entry in policy summary %s", - escaped(orig_summary)); - return NULL; + break; + default: + goto bad_ent; } entries[n_entries].min_port = low; entries[n_entries].max_port = high; n_entries++; + + continue; + skip_ent: + next = strchr(next, ','); + if (!next) + break; + ++next; } if (n_entries == 0) { @@ -2806,6 +2805,11 @@ parse_short_policy(const char *summary) result->n_entries = n_entries; memcpy(result->entries, entries, sizeof(short_policy_entry_t)*n_entries); return result; + + bad_ent: + log_fn(LOG_PROTOCOL_WARN, LD_DIR,"Found bad entry in policy summary %s", + escaped(orig_summary)); + return NULL; } /** Write policy back out into a string. */ -- cgit v1.2.3-54-g00ecf From 508837b62bcb31afbba711ec3dd7b7c18630d604 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 17 Dec 2018 17:54:01 -0500 Subject: Document the output of --version Closes 28889 --- changes/document_version | 2 ++ doc/tor.1.txt | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/document_version (limited to 'changes') diff --git a/changes/document_version b/changes/document_version new file mode 100644 index 0000000000..a45992b6b5 --- /dev/null +++ b/changes/document_version @@ -0,0 +1,2 @@ + o Documentation: + - Document the exact output of "tor --version". Closes ticket 28889. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 8c419b1a63..4ecc4ee382 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -89,7 +89,8 @@ COMMAND-LINE OPTIONS future version. (This is a warning, not a promise.) [[opt-version]] **--version**:: - Display Tor version and exit. + Display Tor version and exit. The output is a line of the format, + "Tor version [version number]." [[opt-quiet]] **--quiet**|**--hush**:: Override the default console log. By default, Tor starts out logging -- cgit v1.2.3-54-g00ecf From 90187b1bfc377a177a62043b1959640848c6bcf7 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 18 Dec 2018 08:15:38 -0500 Subject: Remove changes that are already merged in 0.3.5.x releases --- changes/bug27197 | 3 --- changes/bug27740 | 4 ---- changes/bug27741 | 5 ----- changes/bug27750 | 6 ------ changes/bug27800 | 4 ---- changes/bug27804 | 3 --- changes/bug27841 | 7 ------- changes/bug27948 | 6 ------ changes/bug27963_timeradd | 4 ---- changes/bug27968 | 3 --- changes/bug28096 | 13 ------------- changes/bug28115 | 3 --- changes/bug28127 | 7 ------- changes/bug28183 | 4 ---- changes/bug28202 | 4 ---- changes/bug28245 | 6 ------ changes/bug28298 | 4 ---- changes/bug28303 | 3 --- changes/bug28348_034 | 5 ----- changes/bug28399 | 4 ---- changes/bug28413 | 4 ---- changes/bug28419 | 3 --- changes/bug28435 | 3 --- changes/bug28441 | 4 ---- changes/bug28454 | 4 ---- changes/bug28485 | 3 --- changes/bug28524 | 4 ---- changes/bug28554 | 3 --- changes/bug28562 | 5 ----- changes/bug28619 | 6 ------ changes/geoip-2018-11-06 | 4 ---- changes/geoip-2018-12-05 | 4 ---- changes/rust_asan | 8 -------- changes/ticket19566 | 6 ------ changes/ticket24803 | 5 ----- changes/ticket27471 | 5 ----- changes/ticket27751 | 2 -- changes/ticket27838 | 4 ---- changes/ticket27913 | 3 --- changes/ticket27995 | 4 ---- changes/ticket28026 | 3 --- changes/ticket28113 | 5 ----- changes/ticket28128 | 4 ---- changes/ticket28229_diag | 3 --- changes/ticket28275 | 4 ---- changes/ticket28318 | 3 --- changes/ticket28459 | 4 ---- changes/ticket28574 | 4 ---- changes/ticket28731 | 4 ---- 49 files changed, 216 deletions(-) delete mode 100644 changes/bug27197 delete mode 100644 changes/bug27740 delete mode 100644 changes/bug27741 delete mode 100644 changes/bug27750 delete mode 100644 changes/bug27800 delete mode 100644 changes/bug27804 delete mode 100644 changes/bug27841 delete mode 100644 changes/bug27948 delete mode 100644 changes/bug27963_timeradd delete mode 100644 changes/bug27968 delete mode 100644 changes/bug28096 delete mode 100644 changes/bug28115 delete mode 100644 changes/bug28127 delete mode 100644 changes/bug28183 delete mode 100644 changes/bug28202 delete mode 100644 changes/bug28245 delete mode 100644 changes/bug28298 delete mode 100644 changes/bug28303 delete mode 100644 changes/bug28348_034 delete mode 100644 changes/bug28399 delete mode 100644 changes/bug28413 delete mode 100644 changes/bug28419 delete mode 100644 changes/bug28435 delete mode 100644 changes/bug28441 delete mode 100644 changes/bug28454 delete mode 100644 changes/bug28485 delete mode 100644 changes/bug28524 delete mode 100644 changes/bug28554 delete mode 100644 changes/bug28562 delete mode 100644 changes/bug28619 delete mode 100644 changes/geoip-2018-11-06 delete mode 100644 changes/geoip-2018-12-05 delete mode 100644 changes/rust_asan delete mode 100644 changes/ticket19566 delete mode 100644 changes/ticket24803 delete mode 100644 changes/ticket27471 delete mode 100644 changes/ticket27751 delete mode 100644 changes/ticket27838 delete mode 100644 changes/ticket27913 delete mode 100644 changes/ticket27995 delete mode 100644 changes/ticket28026 delete mode 100644 changes/ticket28113 delete mode 100644 changes/ticket28128 delete mode 100644 changes/ticket28229_diag delete mode 100644 changes/ticket28275 delete mode 100644 changes/ticket28318 delete mode 100644 changes/ticket28459 delete mode 100644 changes/ticket28574 delete mode 100644 changes/ticket28731 (limited to 'changes') diff --git a/changes/bug27197 b/changes/bug27197 deleted file mode 100644 index e389f85065..0000000000 --- a/changes/bug27197 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (protover, rust): - - Reject extra commas in version string. Fixes bug 27197; bugfix on - 0.3.3.3-alpha. diff --git a/changes/bug27740 b/changes/bug27740 deleted file mode 100644 index 76a17b7dda..0000000000 --- a/changes/bug27740 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (rust): - - Return a string that can be safely freed by C code, not one created by - the rust allocator, in protover_all_supported(). Fixes bug 27740; bugfix - on 0.3.3.1-alpha. diff --git a/changes/bug27741 b/changes/bug27741 deleted file mode 100644 index 531e264b63..0000000000 --- a/changes/bug27741 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (rust, directory authority): - - Fix an API mismatch in the rust implementation of - protover_compute_vote(). This bug could have caused crashes on any - directory authorities running Tor with Rust (which we do not yet - recommend). Fixes bug 27741; bugfix on 0.3.3.6. diff --git a/changes/bug27750 b/changes/bug27750 deleted file mode 100644 index c234788b1c..0000000000 --- a/changes/bug27750 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (connection, relay): - - Avoid a wrong BUG() stacktrace in case a closing connection is being held - open because the write side is rate limited but not the read side. Now, - the connection read side is simply shutdown instead of kept open until tor - is able to flush the connection and then fully close it. Fixes bug 27750; - bugfix on 0.3.4.1-alpha. diff --git a/changes/bug27800 b/changes/bug27800 deleted file mode 100644 index 63d5dbc681..0000000000 --- a/changes/bug27800 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (directory authority): - - Log additional info when we get a relay that shares an ed25519 - ID with a different relay, instead making a BUG() warning. - Fixes bug 27800; bugfix on 0.3.2.1-alpha. diff --git a/changes/bug27804 b/changes/bug27804 deleted file mode 100644 index fa7fec0bc5..0000000000 --- a/changes/bug27804 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (rust): - - Fix a potential null dereference in protover_all_supported(). - Add a test for it. Fixes bug 27804; bugfix on 0.3.3.1-alpha. diff --git a/changes/bug27841 b/changes/bug27841 deleted file mode 100644 index 9cd1da7275..0000000000 --- a/changes/bug27841 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor bugfixes (onion services): - - On an intro point for a version 3 onion service, we do not close - an introduction circuit on an NACK. This lets the client decide - whether to reuse the circuit or discard it. Previously, we closed - intro circuits on NACKs. Fixes bug 27841; bugfix on 0.3.2.1-alpha. - Patch by Neel Chaunan - diff --git a/changes/bug27948 b/changes/bug27948 deleted file mode 100644 index fea16f3d0f..0000000000 --- a/changes/bug27948 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (tests): - - Treat backtrace test failures as expected on BSD-derived systems - (NetBSD, OpenBSD, and macOS/Darwin) until we solve bug 17808. - (FreeBSD failures have been treated as expected since 18204 in 0.2.8.) - Fixes bug 27948; bugfix on 0.2.5.2-alpha. - diff --git a/changes/bug27963_timeradd b/changes/bug27963_timeradd deleted file mode 100644 index 34b361cf8d..0000000000 --- a/changes/bug27963_timeradd +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (compilation, opensolaris): - - Add a missing include to compat_pthreads.c, to fix compilation - on OpenSolaris and its descendants. Fixes bug 27963; bugfix - on 0.3.5.1-alpha. diff --git a/changes/bug27968 b/changes/bug27968 deleted file mode 100644 index 78c8eee33a..0000000000 --- a/changes/bug27968 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (testing): - - Avoid hangs and race conditions in test_rebind.py. - Fixes bug 27968; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug28096 b/changes/bug28096 deleted file mode 100644 index 6847df9798..0000000000 --- a/changes/bug28096 +++ /dev/null @@ -1,13 +0,0 @@ - o Minor bugfixes (Windows): - - Correctly identify Windows 8.1, Windows 10, and Windows Server 2008 - and later from their NT versions. - Fixes bug 28096; bugfix on 0.2.2.34; reported by Keifer Bly. - - On recent Windows versions, the GetVersionEx() function may report - an earlier Windows version than the running OS. To avoid user - confusion, add "[or later]" to Tor's version string on affected - versions of Windows. - Fixes bug 28096; bugfix on 0.2.2.34; reported by Keifer Bly. - - Remove Windows versions that were never supported by the - GetVersionEx() function. Stop duplicating the latest Windows - version in get_uname(). - Fixes bug 28096; bugfix on 0.2.2.34; reported by Keifer Bly. diff --git a/changes/bug28115 b/changes/bug28115 deleted file mode 100644 index e3e29968eb..0000000000 --- a/changes/bug28115 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (portability): - - Make the OPE code (which is used for v3 onion services) run correctly - on big-endian platforms. Fixes bug 28115; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug28127 b/changes/bug28127 deleted file mode 100644 index 541128c88e..0000000000 --- a/changes/bug28127 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor bugfixes (onion services): - - Unless we have explicitly set HiddenServiceVersion, detect the onion - service version and then look for invalid options. Previously, we - did the reverse, but that broke existing configs which were pointed - to a v2 hidden service and had options like HiddenServiceAuthorizeClient - set Fixes bug 28127; bugfix on 0.3.5.1-alpha. Patch by Neel Chauhan. - diff --git a/changes/bug28183 b/changes/bug28183 deleted file mode 100644 index 8d35dcdc01..0000000000 --- a/changes/bug28183 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (Linux seccomp2 sandbox): - - Permit the "shutdown()" system call, which is apparently - used by OpenSSL under some circumstances. Fixes bug 28183; - bugfix on 0.2.5.1-alpha. diff --git a/changes/bug28202 b/changes/bug28202 deleted file mode 100644 index 182daac4f1..0000000000 --- a/changes/bug28202 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (C correctness): - - Avoid undefined behavior in an end-of-string check when parsing the - BEGIN line in a directory object. Fixes bug 28202; bugfix on - 0.2.0.3-alpha. diff --git a/changes/bug28245 b/changes/bug28245 deleted file mode 100644 index d7e6deb810..0000000000 --- a/changes/bug28245 +++ /dev/null @@ -1,6 +0,0 @@ - o Major bugfixes (OpenSSL, portability): - - Fix our usage of named groups when running as a TLS 1.3 client in - OpenSSL 1.1.1. Previously, we only initialized EC groups when running - as a server, which caused clients to fail to negotiate TLS 1.3 with - relays. Fixes bug 28245; bugfix on 0.2.9.15 when TLS 1.3 support was - added. diff --git a/changes/bug28298 b/changes/bug28298 deleted file mode 100644 index 8db340f3df..0000000000 --- a/changes/bug28298 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (configuration): - - Resume refusing to start with relative file paths and RunAsDaemon - set (regression from the fix for bug 22731). Fixes bug 28298; - bugfix on 0.3.3.1-alpha. diff --git a/changes/bug28303 b/changes/bug28303 deleted file mode 100644 index 80f1302e5e..0000000000 --- a/changes/bug28303 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (compilation): - - Fix a pair of missing headers on OpenBSD. Fixes bug 28303; - bugfix on 0.3.5.1-alpha. Patch from Kris Katterjohn. diff --git a/changes/bug28348_034 b/changes/bug28348_034 deleted file mode 100644 index 3913c03a4c..0000000000 --- a/changes/bug28348_034 +++ /dev/null @@ -1,5 +0,0 @@ - o Major bugfixes (embedding, main loop): - - When DisableNetwork becomes set, actually disable periodic events that - are already enabled. (Previously, we would refrain from enabling new - ones, but we would leave the old ones turned on.) - Fixes bug 28348; bugfix on 0.3.4.1-alpha. diff --git a/changes/bug28399 b/changes/bug28399 deleted file mode 100644 index 9096db70b0..0000000000 --- a/changes/bug28399 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (continuous integration, Windows): - - Stop using an external OpenSSL install, and stop installing MSYS2 - packages, when building using mingw on Appveyor Windows CI. - Fixes bug 28399; bugfix on 0.3.4.1-alpha. diff --git a/changes/bug28413 b/changes/bug28413 deleted file mode 100644 index 4c88bea7e7..0000000000 --- a/changes/bug28413 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (compilation): - - Initialize a variable in aes_new_cipher(), since some compilers - cannot tell that we always initialize it before use. Fixes bug 28413; - bugfix on 0.2.9.3-alpha. diff --git a/changes/bug28419 b/changes/bug28419 deleted file mode 100644 index 52ceb0a2a7..0000000000 --- a/changes/bug28419 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (memory leaks): - - Fix a harmless memory leak in libtorrunner.a. Fixes bug 28419; - bugfix on 0.3.3.1-alpha. Patch from Martin Kepplinger. \ No newline at end of file diff --git a/changes/bug28435 b/changes/bug28435 deleted file mode 100644 index 2a886cb8b7..0000000000 --- a/changes/bug28435 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (documentation): - - Make Doxygen work again after the 0.3.5 source tree moves. - Fixes bug 28435; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug28441 b/changes/bug28441 deleted file mode 100644 index d259b9f742..0000000000 --- a/changes/bug28441 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (logging): - - Stop talking about the Named flag in log messages. Clients have - ignored the Named flag since 0.3.2. Fixes bug 28441; - bugfix on 0.3.2.1-alpha. diff --git a/changes/bug28454 b/changes/bug28454 deleted file mode 100644 index ca46ae2777..0000000000 --- a/changes/bug28454 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (continuous integration, Windows): - - Manually configure the zstd compiler options, when building using - mingw on Appveyor Windows CI. The MSYS2 mingw zstd package does not - come with a pkg-config file. Fixes bug 28454; bugfix on 0.3.4.1-alpha. diff --git a/changes/bug28485 b/changes/bug28485 deleted file mode 100644 index a8309ae21f..0000000000 --- a/changes/bug28485 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (compilation): - - Add missing dependency on libgdi32.dll for tor-print-ed-signing-cert.exe - on Windows. Fixes bug 28485; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug28524 b/changes/bug28524 deleted file mode 100644 index 1cad700422..0000000000 --- a/changes/bug28524 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (restart-in-process, boostrap): - - Add missing resets of bootstrap tracking state when shutting - down (regression caused by ticket 27169). Fixes bug 28524; - bugfix on 0.3.5.1-alpha. diff --git a/changes/bug28554 b/changes/bug28554 deleted file mode 100644 index 9a0b281406..0000000000 --- a/changes/bug28554 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (unit tests, guard selection): - - Stop leaking memory in an entry guard unit test. Fixes bug 28554; - bugfix on 0.3.0.1-alpha. diff --git a/changes/bug28562 b/changes/bug28562 deleted file mode 100644 index e14362164d..0000000000 --- a/changes/bug28562 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (testing): - - Use a separate DataDirectory for the test_rebind script. - Previously, this script would run using the default DataDirectory, - and sometimes fail. Fixes bug 28562; bugfix on 0.3.5.1-alpha. - Patch from Taylor R Campbell. diff --git a/changes/bug28619 b/changes/bug28619 deleted file mode 100644 index 86be8cb2fb..0000000000 --- a/changes/bug28619 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (hidden service v3): - - When deleting an ephemeral onion service (DEL_ONION), do not close any - rendezvous circuits in order to let the existing client connections - finish by themselves or closed by the application. The HS v2 is doing - that already so now we have the same behavior for all versions. Fixes - bug 28619; bugfix on 0.3.3.1-alpha. diff --git a/changes/geoip-2018-11-06 b/changes/geoip-2018-11-06 deleted file mode 100644 index 5c18ea4244..0000000000 --- a/changes/geoip-2018-11-06 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (geoip): - - Update geoip and geoip6 to the November 6 2018 Maxmind GeoLite2 - Country database. Closes ticket 28395. - diff --git a/changes/geoip-2018-12-05 b/changes/geoip-2018-12-05 deleted file mode 100644 index 20ccf2d8a5..0000000000 --- a/changes/geoip-2018-12-05 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (geoip): - - Update geoip and geoip6 to the December 5 2018 Maxmind GeoLite2 - Country database. Closes ticket 28744. - diff --git a/changes/rust_asan b/changes/rust_asan deleted file mode 100644 index 1ca7ae6888..0000000000 --- a/changes/rust_asan +++ /dev/null @@ -1,8 +0,0 @@ - o Major bugfixes (compilation, rust): - - Rust tests can now build and run successfully with the - --enable-fragile-hardening option enabled. - Doing this currently requires the rust beta channel; it will - be possible with stable rust as of rust version 1.31 is out. - Patch from Alex Crichton. - Fixes bugs 27272, 27273, and 27274. - Bugfix on 0.3.1.1-alpha. diff --git a/changes/ticket19566 b/changes/ticket19566 deleted file mode 100644 index bf7071e660..0000000000 --- a/changes/ticket19566 +++ /dev/null @@ -1,6 +0,0 @@ - o Code simplification and refactoring (shared random, dirauth): - - Change many tor_assert() to use BUG() instead. The idea is to not crash - a dirauth but rather scream loudly with a stacktrace and let it continue - run. The shared random subsystem is very resilient and if anything wrong - happens with it, at worst a non coherent value will be put in the vote - and discarded by the other authorities. Closes ticket 19566. diff --git a/changes/ticket24803 b/changes/ticket24803 deleted file mode 100644 index e76a9eeab9..0000000000 --- a/changes/ticket24803 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (fallback directory list): - - Replace the 150 fallbacks originally introduced in Tor 0.3.3.1-alpha in - January 2018 (of which ~115 were still functional), with a list of - 157 fallbacks (92 new, 65 existing, 85 removed) generated in - December 2018. Closes ticket 24803. diff --git a/changes/ticket27471 b/changes/ticket27471 deleted file mode 100644 index ffe77d268e..0000000000 --- a/changes/ticket27471 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (hidden service v3, client): - - When replacing a descriptor in the client cache with a newer descriptor, - make sure to close all client introduction circuits of the old - descriptor so we don't end up with unusable leftover circuits. Fixes bug - 27471; bugfix on 0.3.2.1-alpha. diff --git a/changes/ticket27751 b/changes/ticket27751 deleted file mode 100644 index 593c473b61..0000000000 --- a/changes/ticket27751 +++ /dev/null @@ -1,2 +0,0 @@ - o Minor features (continuous integration): - - Add a Travis CI build for --enable-nss on Linux gcc. Closes ticket 27751. diff --git a/changes/ticket27838 b/changes/ticket27838 deleted file mode 100644 index 1699730d7a..0000000000 --- a/changes/ticket27838 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (hidden service v3): - - Build the service descriptor signing key certificate before uploading so - we always have a fresh one leaving no chances for it to expire service - side. Fixes bug 27838; bugfix on 0.3.2.1-alpha. diff --git a/changes/ticket27913 b/changes/ticket27913 deleted file mode 100644 index 81ce725932..0000000000 --- a/changes/ticket27913 +++ /dev/null @@ -1,3 +0,0 @@ - o Testing: - - Add new CI job to Travis configuration that runs stem-based - integration tests. Closes ticket 27913. diff --git a/changes/ticket27995 b/changes/ticket27995 deleted file mode 100644 index 8c75425749..0000000000 --- a/changes/ticket27995 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (hidden service v3, client authorization): - - Fix an assert() when adding a client authorization for the first time - and then sending a HUP signal to the service. Before that, tor would - stop abruptly. Fixes bug 27995; bugfix on 0.3.5.1-alpha. diff --git a/changes/ticket28026 b/changes/ticket28026 deleted file mode 100644 index a6911c2cab..0000000000 --- a/changes/ticket28026 +++ /dev/null @@ -1,3 +0,0 @@ - o Documentation (hidden service manpage): - - Improve HSv3 client authorization by making some options more explicit - and detailed. Closes ticket 28026. Patch by "mtigas". diff --git a/changes/ticket28113 b/changes/ticket28113 deleted file mode 100644 index 30dd825a9b..0000000000 --- a/changes/ticket28113 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (relay shutdown, systemd): - - Notify systemd of ShutdownWaitLength so it can be set to longer than - systemd's TimeoutStopSec. In tor's systemd service file, set - TimeoutSec to 60 seconds, to allow tor some time to shut down. - Fixes bug 28113; bugfix on 0.2.6.2-alpha. diff --git a/changes/ticket28128 b/changes/ticket28128 deleted file mode 100644 index 6d08c74242..0000000000 --- a/changes/ticket28128 +++ /dev/null @@ -1,4 +0,0 @@ - o Documentation (hidden service manpage, sandbox): - - Document in the man page that changing ClientOnionAuthDir value or - adding a new file in the directory will not work at runtime upon sending - a HUP if Sandbox 1. Closes ticket 28128. diff --git a/changes/ticket28229_diag b/changes/ticket28229_diag deleted file mode 100644 index cd02b81faa..0000000000 --- a/changes/ticket28229_diag +++ /dev/null @@ -1,3 +0,0 @@ - o Testing: - - Increase logging and tag all log entries with timestamps - in test_rebind.py. Provides diagnostics for issue 28229. diff --git a/changes/ticket28275 b/changes/ticket28275 deleted file mode 100644 index eadca86b7b..0000000000 --- a/changes/ticket28275 +++ /dev/null @@ -1,4 +0,0 @@ - o Documentation (hidden service v3, man page): - - Note in the man page that the only real way to fully revoke an onion - service v3 client authorization is by restarting the tor process. Closes - ticket 28275. diff --git a/changes/ticket28318 b/changes/ticket28318 deleted file mode 100644 index 24dc1e9580..0000000000 --- a/changes/ticket28318 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (Windows, continuous integration): - - Build tor on Windows Server 2012 R2 and Windows Server 2016 using - Appveyor's CI. Closes ticket 28318. diff --git a/changes/ticket28459 b/changes/ticket28459 deleted file mode 100644 index 6b5839b52b..0000000000 --- a/changes/ticket28459 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (continuous integration, Windows): - - Always show the configure and test logs, and upload them as build - artifacts, when building for Windows using Appveyor CI. - Implements 28459. diff --git a/changes/ticket28574 b/changes/ticket28574 deleted file mode 100644 index 562810f511..0000000000 --- a/changes/ticket28574 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (continuous integration, Windows): - - Explicitly specify the path to the OpenSSL library and do not download - OpenSSL from Pacman, but instead use the library that is already provided - by AppVeyor. Fixes bug 28574; bugfix on master. diff --git a/changes/ticket28731 b/changes/ticket28731 deleted file mode 100644 index f8b116cc12..0000000000 --- a/changes/ticket28731 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (bootstrap): - - Add the bootstrap tag name to the log messages, so people - troubleshooting connection problems can look up a symbol instead - of a number. Closes ticket 28731. -- cgit v1.2.3-54-g00ecf From 44a80bb36115ebf865ba688a0f0d0f8023d992d6 Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Mon, 17 Dec 2018 23:41:53 +0100 Subject: Add missing changes files for #26360, #28179, #28180. See: https://bugs.torproject.org/26179 See: https://bugs.torproject.org/28180 See: https://bugs.torproject.org/28360 --- changes/ticket26360 | 4 ++++ changes/ticket28179 | 5 +++++ changes/ticket28180 | 3 +++ 3 files changed, 12 insertions(+) create mode 100644 changes/ticket26360 create mode 100644 changes/ticket28179 create mode 100644 changes/ticket28180 (limited to 'changes') diff --git a/changes/ticket26360 b/changes/ticket26360 new file mode 100644 index 0000000000..80afbd1c17 --- /dev/null +++ b/changes/ticket26360 @@ -0,0 +1,4 @@ + o Minor bugfixes (pluggable transports): + - Make sure that data is continously read from standard out and error of the + PT child-process to avoid deadlocking when the pipes' buffer is full. + Fixes bug 26360; bugfix on 0.2.3.6-alpha. diff --git a/changes/ticket28179 b/changes/ticket28179 new file mode 100644 index 0000000000..f548c4a79a --- /dev/null +++ b/changes/ticket28179 @@ -0,0 +1,5 @@ + o Minor features (process): + - Add new Process API for handling child processes. This + new API allows Tor to have bi-directional + communication with child processes on both Unix and Windows. + Closes ticket 28179. diff --git a/changes/ticket28180 b/changes/ticket28180 new file mode 100644 index 0000000000..2ec547bd47 --- /dev/null +++ b/changes/ticket28180 @@ -0,0 +1,3 @@ + o Minor features (pluggable transports): + - Add support for logging to Tor's logging subsystem from a pluggable + transport process. Partial implementation for ticket 28180 -- cgit v1.2.3-54-g00ecf From 976c62e62a38c9f30c32ca742a43d59633a0e6ab Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 14 Dec 2018 13:34:32 -0500 Subject: Changes file for ticket28839 --- changes/ticket28839 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket28839 (limited to 'changes') diff --git a/changes/ticket28839 b/changes/ticket28839 new file mode 100644 index 0000000000..e9f81dc405 --- /dev/null +++ b/changes/ticket28839 @@ -0,0 +1,3 @@ + o Minor features (performance): + - Speed up microdesriptor parsing by about 30%, to help + improve startup time. Closes ticket 28839. -- cgit v1.2.3-54-g00ecf From e2c36b9ca064580208ac0976aaad28f08f3a744b Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Thu, 20 Dec 2018 04:08:04 +0100 Subject: Add and update changes files for #28846. This ticket finishes the implementatoin of #28180 and adds the new STATUS message from #28846. See: https://bugs.torproject.org/28846 --- changes/ticket28180 | 2 +- changes/ticket28846 | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/ticket28846 (limited to 'changes') diff --git a/changes/ticket28180 b/changes/ticket28180 index 2ec547bd47..59de1c6251 100644 --- a/changes/ticket28180 +++ b/changes/ticket28180 @@ -1,3 +1,3 @@ o Minor features (pluggable transports): - Add support for logging to Tor's logging subsystem from a pluggable - transport process. Partial implementation for ticket 28180 + transport process. Closes ticket 28180 diff --git a/changes/ticket28846 b/changes/ticket28846 new file mode 100644 index 0000000000..efb5b9938e --- /dev/null +++ b/changes/ticket28846 @@ -0,0 +1,3 @@ + o Minor features (pluggable transports): + - Add support for emitting STATUS updates to Tor's control port from a + pluggable transport process. Closes ticket 28846. -- cgit v1.2.3-54-g00ecf From a517daa56f5848d25ba79617a1a7b82ed2b0a7c0 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 20 Dec 2018 08:36:25 -0500 Subject: base32_decode(): Return number of bytes written on success. This makes it consistent with base64_decode(). Closes ticket 28913. --- changes/ticket28913 | 4 ++++ src/feature/control/control.c | 3 ++- src/feature/rend/rendcache.c | 3 +-- src/lib/encoding/binascii.c | 4 ++-- src/test/test_crypto.c | 8 ++++---- src/test/test_util_format.c | 4 ++-- 6 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 changes/ticket28913 (limited to 'changes') diff --git a/changes/ticket28913 b/changes/ticket28913 new file mode 100644 index 0000000000..e09847464d --- /dev/null +++ b/changes/ticket28913 @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Make the base32_decode() API return the number of bytes written, + for consistency with base64_decode(). + Closes ticket 28913. diff --git a/src/feature/control/control.c b/src/feature/control/control.c index 7fae3b7a1b..1e3db6337e 100644 --- a/src/feature/control/control.c +++ b/src/feature/control/control.c @@ -4428,7 +4428,8 @@ handle_control_hsfetch(control_connection_t *conn, uint32_t len, } else if (strcmpstart(arg1, v2_str) == 0 && rend_valid_descriptor_id(arg1 + v2_str_len) && base32_decode(digest, sizeof(digest), arg1 + v2_str_len, - REND_DESC_ID_V2_LEN_BASE32) == 0) { + REND_DESC_ID_V2_LEN_BASE32) == + REND_DESC_ID_V2_LEN_BASE32) { /* We have a well formed version 2 descriptor ID. Keep the decoded value * of the id. */ desc_id = digest; diff --git a/src/feature/rend/rendcache.c b/src/feature/rend/rendcache.c index b851e71959..ecd85e4a5a 100644 --- a/src/feature/rend/rendcache.c +++ b/src/feature/rend/rendcache.c @@ -854,7 +854,7 @@ rend_cache_store_v2_desc_as_client(const char *desc, *entry = NULL; } if (base32_decode(want_desc_id, sizeof(want_desc_id), - desc_id_base32, strlen(desc_id_base32)) != 0) { + desc_id_base32, strlen(desc_id_base32)) < 0) { log_warn(LD_BUG, "Couldn't decode base32 %s for descriptor id.", escaped_safe_str_client(desc_id_base32)); goto err; @@ -1005,4 +1005,3 @@ rend_cache_store_v2_desc_as_client(const char *desc, tor_free(intro_content); return retval; } - diff --git a/src/lib/encoding/binascii.c b/src/lib/encoding/binascii.c index 067db075ad..a7662658f0 100644 --- a/src/lib/encoding/binascii.c +++ b/src/lib/encoding/binascii.c @@ -84,7 +84,7 @@ base32_encode(char *dest, size_t destlen, const char *src, size_t srclen) } /** Implements base32 decoding as in RFC 4648. - * Returns 0 if successful, -1 otherwise. + * Return the number of bytes decoded if successful; -1 otherwise. */ int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen) @@ -147,7 +147,7 @@ base32_decode(char *dest, size_t destlen, const char *src, size_t srclen) memset(tmp, 0, srclen); /* on the heap, this should be safe */ tor_free(tmp); tmp = NULL; - return 0; + return i; } #define BASE64_OPENSSL_LINELEN 64 diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index 81d2fa6f33..e924cea423 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -1865,13 +1865,13 @@ test_crypto_base32_decode(void *arg) /* Encode and decode a random string. */ base32_encode(encoded, 96 + 1, plain, 60); res = base32_decode(decoded, 60, encoded, 96); - tt_int_op(res,OP_EQ, 0); + tt_int_op(res, OP_EQ, 60); tt_mem_op(plain,OP_EQ, decoded, 60); /* Encode, uppercase, and decode a random string. */ base32_encode(encoded, 96 + 1, plain, 60); tor_strupper(encoded); res = base32_decode(decoded, 60, encoded, 96); - tt_int_op(res,OP_EQ, 0); + tt_int_op(res, OP_EQ, 60); tt_mem_op(plain,OP_EQ, decoded, 60); /* Change encoded string and decode. */ if (encoded[0] == 'A' || encoded[0] == 'a') @@ -1879,12 +1879,12 @@ test_crypto_base32_decode(void *arg) else encoded[0] = 'A'; res = base32_decode(decoded, 60, encoded, 96); - tt_int_op(res,OP_EQ, 0); + tt_int_op(res, OP_EQ, 60); tt_mem_op(plain,OP_NE, decoded, 60); /* Bad encodings. */ encoded[0] = '!'; res = base32_decode(decoded, 60, encoded, 96); - tt_int_op(0, OP_GT, res); + tt_int_op(res, OP_LT, 0); done: ; diff --git a/src/test/test_util_format.c b/src/test/test_util_format.c index fd57125b86..f91171dc28 100644 --- a/src/test/test_util_format.c +++ b/src/test/test_util_format.c @@ -346,7 +346,7 @@ test_util_format_base32_decode(void *arg) const char *src = "mjwgc2dcnrswqmjs"; ret = base32_decode(dst, strlen(expected), src, strlen(src)); - tt_int_op(ret, OP_EQ, 0); + tt_int_op(ret, OP_EQ, 10); tt_str_op(expected, OP_EQ, dst); } @@ -357,7 +357,7 @@ test_util_format_base32_decode(void *arg) const char *src = "mjwgc2dcnrswq"; ret = base32_decode(dst, strlen(expected), src, strlen(src)); - tt_int_op(ret, OP_EQ, 0); + tt_int_op(ret, OP_EQ, 8); tt_mem_op(expected, OP_EQ, dst, strlen(expected)); } -- cgit v1.2.3-54-g00ecf From cf4b3dbd445799bfad21e84777eff91d3a409f21 Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Thu, 20 Dec 2018 15:07:05 +0100 Subject: Use the subsystem list to initialize and shutdown process module. This patch makes the process module use the subsystem list for initializing and shutting down. See: https://bugs.torproject.org/28847 --- changes/ticket28847 | 3 +++ src/app/main/subsystem_list.c | 2 ++ src/lib/process/include.am | 2 ++ src/lib/process/process_sys.c | 33 +++++++++++++++++++++++++++++++++ src/lib/process/process_sys.h | 14 ++++++++++++++ 5 files changed, 54 insertions(+) create mode 100644 changes/ticket28847 create mode 100644 src/lib/process/process_sys.c create mode 100644 src/lib/process/process_sys.h (limited to 'changes') diff --git a/changes/ticket28847 b/changes/ticket28847 new file mode 100644 index 0000000000..63100c5813 --- /dev/null +++ b/changes/ticket28847 @@ -0,0 +1,3 @@ + o Minor features (process): + - Use the subsystem module to initialize and shut down the process module. + Closes ticket 28847. diff --git a/src/app/main/subsystem_list.c b/src/app/main/subsystem_list.c index 8640329e92..122f7af215 100644 --- a/src/app/main/subsystem_list.c +++ b/src/app/main/subsystem_list.c @@ -18,6 +18,7 @@ #include "lib/time/time_sys.h" #include "lib/tls/tortls_sys.h" #include "lib/wallclock/wallclock_sys.h" +#include "lib/process/process_sys.h" #include @@ -32,6 +33,7 @@ const subsys_fns_t *tor_subsystems[] = { &sys_logging, /* -90 */ &sys_time, /* -90 */ &sys_network, /* -90 */ + &sys_process, /* -80 */ &sys_compress, /* -70 */ &sys_crypto, /* -60 */ &sys_tortls, /* -50 */ diff --git a/src/lib/process/include.am b/src/lib/process/include.am index a2d54b6238..83b67bf029 100644 --- a/src/lib/process/include.am +++ b/src/lib/process/include.am @@ -10,6 +10,7 @@ src_lib_libtor_process_a_SOURCES = \ src/lib/process/env.c \ src/lib/process/pidfile.c \ src/lib/process/process.c \ + src/lib/process/process_sys.c \ src/lib/process/process_unix.c \ src/lib/process/process_win32.c \ src/lib/process/restrict.c \ @@ -27,6 +28,7 @@ noinst_HEADERS += \ src/lib/process/env.h \ src/lib/process/pidfile.h \ src/lib/process/process.h \ + src/lib/process/process_sys.h \ src/lib/process/process_unix.h \ src/lib/process/process_win32.h \ src/lib/process/restrict.h \ diff --git a/src/lib/process/process_sys.c b/src/lib/process/process_sys.c new file mode 100644 index 0000000000..a880ff146e --- /dev/null +++ b/src/lib/process/process_sys.c @@ -0,0 +1,33 @@ +/* Copyright (c) 2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file process_sys.c + * \brief Subsystem object for process setup. + **/ + +#include "orconfig.h" +#include "lib/subsys/subsys.h" +#include "lib/process/process_sys.h" +#include "lib/process/process.h" + +static int +subsys_process_initialize(void) +{ + process_init(); + return 0; +} + +static void +subsys_process_shutdown(void) +{ + process_free_all(); +} + +const subsys_fns_t sys_process = { + .name = "process", + .level = -80, + .supported = true, + .initialize = subsys_process_initialize, + .shutdown = subsys_process_shutdown +}; diff --git a/src/lib/process/process_sys.h b/src/lib/process/process_sys.h new file mode 100644 index 0000000000..b299334b6b --- /dev/null +++ b/src/lib/process/process_sys.h @@ -0,0 +1,14 @@ +/* Copyright (c) 2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file process_sys.h + * \brief Declare subsystem object for the process module. + **/ + +#ifndef TOR_PROCESS_SYS_H +#define TOR_PROCESS_SYS_H + +extern const struct subsys_fns_t sys_process; + +#endif /* !defined(TOR_PROCESS_SYS_H) */ -- cgit v1.2.3-54-g00ecf From 2100b35f0799276f9854dd625621deda33a9ecc3 Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Thu, 20 Dec 2018 15:50:34 -0600 Subject: changes file for ticket27167 --- changes/ticket27167 | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 changes/ticket27167 (limited to 'changes') diff --git a/changes/ticket27167 b/changes/ticket27167 new file mode 100644 index 0000000000..81c66630c8 --- /dev/null +++ b/changes/ticket27167 @@ -0,0 +1,11 @@ + o Major features (bootstrap): + - Report the first connection to a relay as the earliest phases of + bootstrap progress, regardless of whether it's a connection for + building application circuits. This allows finer-grained + reporting of early progress than previously possible with the + improvements of ticket 27169. Closes tickets 27167 and 27103. + Addresses ticket 27308. + - Separately report the intermediate stage of having connected to + a proxy or pluggable transport, versus succesfully using that + proxy or pluggable transport to connect to a relay. Closes + tickets 27100 and 28884. -- cgit v1.2.3-54-g00ecf From 8eadfad71daaad985ac1262436bc232d4b184d71 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sun, 23 Dec 2018 19:58:25 +0200 Subject: Tweak ControlPort description in manpage --- changes/doc28805 | 4 ++++ doc/tor.1.txt | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 changes/doc28805 (limited to 'changes') diff --git a/changes/doc28805 b/changes/doc28805 new file mode 100644 index 0000000000..6c9fea44fa --- /dev/null +++ b/changes/doc28805 @@ -0,0 +1,4 @@ + o Documentation (manpage): + - Improve ControlPort description in tor manpage to mention that it + accepts address/port pair, and can be used multiple times. Closes ticket + 28805. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 4ff789a931..b058bebcb3 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -350,7 +350,7 @@ GENERAL OPTIONS all sockets will be set to this limit. Must be a value between 2048 and 262144, in 1024 byte increments. Default of 8192 is recommended. -[[ControlPort]] **ControlPort** __PORT__|**unix:**__path__|**auto** [__flags__]:: +[[ControlPort]] **ControlPort** \['address':]__port__|**unix:**__path__|**auto** [__flags__]:: If set, Tor will accept connections on this port and allow those connections to control the Tor process using the Tor Control Protocol (described in control-spec.txt in @@ -361,7 +361,8 @@ GENERAL OPTIONS methods means either method is sufficient to authenticate to Tor.) This option is required for many Tor controllers; most use the value of 9051. If a unix domain socket is used, you may quote the path using standard - C escape sequences. + C escape sequences. You can specify this directive multiple times, to + bind to multiple address/port pairs. Set it to "auto" to have Tor pick a port for you. (Default: 0) + + Recognized flags are... -- cgit v1.2.3-54-g00ecf From dbf1725a135405cfa3e4aea9d66e0d62fed1f360 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Thu, 3 Jan 2019 10:36:38 +0200 Subject: Completely remove 'GETINFO status/version/num-{concurring,versioning}' --- changes/ticket28757 | 5 +++++ src/feature/control/control.c | 9 --------- 2 files changed, 5 insertions(+), 9 deletions(-) create mode 100644 changes/ticket28757 (limited to 'changes') diff --git a/changes/ticket28757 b/changes/ticket28757 new file mode 100644 index 0000000000..62c6d099ff --- /dev/null +++ b/changes/ticket28757 @@ -0,0 +1,5 @@ + o Removed features: + - Stop responding to 'GETINFO status/version/num-concurring' and + 'GETINFO status/version/num-versioning' control port commands, as those + were deprecated back in 0.2.0.30. Also stop listing them in output of + 'GETINFO info/names'. Resolves ticket 28757. diff --git a/src/feature/control/control.c b/src/feature/control/control.c index da62c94981..f10d5eb84a 100644 --- a/src/feature/control/control.c +++ b/src/feature/control/control.c @@ -3069,11 +3069,6 @@ getinfo_helper_events(control_connection_t *control_conn, case VS_UNKNOWN: *answer = tor_strdup("unknown"); break; default: tor_fragile_assert(); } - } else if (!strcmp(question, "status/version/num-versioning") || - !strcmp(question, "status/version/num-concurring")) { - tor_asprintf(answer, "%d", get_n_authorities(V3_DIRINFO)); - log_warn(LD_GENERAL, "%s is deprecated; it no longer gives useful " - "information", question); } } else if (!strcmp(question, "status/clients-seen")) { char *bridge_stats = geoip_get_bridge_stats_controller(time(NULL)); @@ -3366,10 +3361,6 @@ static const getinfo_item_t getinfo_items[] = { "A fresh relay/ei descriptor pair for Tor's current state. Not stored."), DOC("status/version/recommended", "List of currently recommended versions."), DOC("status/version/current", "Status of the current version."), - DOC("status/version/num-versioning", "Number of versioning authorities."), - DOC("status/version/num-concurring", - "Number of versioning authorities agreeing on the status of the " - "current version"), ITEM("address", misc, "IP address of this Tor host, if we can guess it."), ITEM("traffic/read", misc,"Bytes read since the process was started."), ITEM("traffic/written", misc, -- cgit v1.2.3-54-g00ecf From af85a0f28fcea7d5fbb5cad2b807d75911230894 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 4 Jan 2019 15:04:00 -0500 Subject: Remove from master those changes files that will appear in 0.3.5.7 or earlier. --- changes/bug28568 | 4 ---- changes/bug28612 | 4 ---- changes/bug28974 | 3 --- changes/ticket28838 | 8 -------- changes/ticket28851 | 4 ---- changes/ticket28879 | 5 ----- changes/ticket28881 | 4 ---- changes/ticket28883 | 4 ---- changes/ticket28912 | 6 ------ changes/ticket28924 | 4 ---- changes/ticket28973 | 6 ------ 11 files changed, 52 deletions(-) delete mode 100644 changes/bug28568 delete mode 100644 changes/bug28612 delete mode 100644 changes/bug28974 delete mode 100644 changes/ticket28838 delete mode 100644 changes/ticket28851 delete mode 100644 changes/ticket28879 delete mode 100644 changes/ticket28881 delete mode 100644 changes/ticket28883 delete mode 100644 changes/ticket28912 delete mode 100644 changes/ticket28924 delete mode 100644 changes/ticket28973 (limited to 'changes') diff --git a/changes/bug28568 b/changes/bug28568 deleted file mode 100644 index 919ec08903..0000000000 --- a/changes/bug28568 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (testing): - - Stop running stem's unit tests as part of "make test-stem". But continue - to run stem's unit and online tests during "make test-stem-full". - Fixes bug 28568; bugfix on 0.2.6.3-alpha. diff --git a/changes/bug28612 b/changes/bug28612 deleted file mode 100644 index 559f254234..0000000000 --- a/changes/bug28612 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (windows services): - - Make Tor start correctly as an NT service again: previously it - was broken by refactoring. Fixes bug 28612; bugfix on 0.3.5.3-alpha. - diff --git a/changes/bug28974 b/changes/bug28974 deleted file mode 100644 index 2d74f5674f..0000000000 --- a/changes/bug28974 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (compilation): - - Fix compilation for Android by adding a missing header to - freespace.c. Fixes bug 28974; bugfix on 0.3.5.1-alpha. diff --git a/changes/ticket28838 b/changes/ticket28838 deleted file mode 100644 index 6c290bf82b..0000000000 --- a/changes/ticket28838 +++ /dev/null @@ -1,8 +0,0 @@ - o Minor features (performance): - - Remove about 96% of the work from the function that we run at - startup to test our curve25519_basepoint implementation. Since - this function has yet to find an actual failure, we'll only - run it for 8 iterations instead of 200. Based on our profile - information, this change should save around 8% of our startup - time on typical desktops, and may have a similar effect on - other platforms. Closes ticket 28838. diff --git a/changes/ticket28851 b/changes/ticket28851 deleted file mode 100644 index bab0318662..0000000000 --- a/changes/ticket28851 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (performance): - - Stop re-validating our hardcoded Diffie-Hellman parameters on every - startup. Doing this wasted time and cycles, especially on low-powered - devices. Closes ticket 28851. diff --git a/changes/ticket28879 b/changes/ticket28879 deleted file mode 100644 index 126420f6ca..0000000000 --- a/changes/ticket28879 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (correctness): - - Fix an unreached code-path where we checked the value of "hostname" - inside send_resolved_hostnam_cell(). Previously, we used it before - checking it; now we check it first. Fixes bug 28879; bugfix on - 0.1.2.7-alpha. diff --git a/changes/ticket28881 b/changes/ticket28881 deleted file mode 100644 index 1b015a6c37..0000000000 --- a/changes/ticket28881 +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring: - - When parsing a port configuration, make it more - obvious to static analyzer tools that we will always initialize the - address. Closes ticket 28881. diff --git a/changes/ticket28883 b/changes/ticket28883 deleted file mode 100644 index 1d8b6cb416..0000000000 --- a/changes/ticket28883 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (testing): - - Make sure that test_rebind.py actually obeys its timeout, even - when it receives a large number of log messages. Fixes bug 28883; - bugfix on 0.3.5.4-alpha. diff --git a/changes/ticket28912 b/changes/ticket28912 deleted file mode 100644 index 4119b778bc..0000000000 --- a/changes/ticket28912 +++ /dev/null @@ -1,6 +0,0 @@ - o Major bugfixes (relay, directory): - - A connection serving directory information wouldn't get reactivated after - the first chunk of data was sent (usually 32KB). Tor now always activate - the main loop event that goes through these connections as long as at - least one connection is still active. Fixes bug 28912; bugfix on - 0.3.4.1-alpha. Patch by "cypherpunks3". diff --git a/changes/ticket28924 b/changes/ticket28924 deleted file mode 100644 index 055a6cf285..0000000000 --- a/changes/ticket28924 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (compilation): - - When possible, place our warning flags in a separate file, to avoid - flooding verbose build logs to an unacceptable amount. Closes ticket - 28924. diff --git a/changes/ticket28973 b/changes/ticket28973 deleted file mode 100644 index b1d208ee51..0000000000 --- a/changes/ticket28973 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor features (OpenSSL bug workaround): - - Work around a bug in OpenSSL 1.1.1a, which prevented the TLS 1.3 - key export function from handling long labels. When this bug - is detected, Tor will disable TLS 1.3. We recommend upgrading to - a version of OpenSSL without this bug when it becomes available. - Closes ticket 28973. -- cgit v1.2.3-54-g00ecf From a891d81c5f62cdda37b4371ebe2782e23e4f6db1 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 9 Jan 2019 08:48:11 -0500 Subject: Changes file for 28856 --- changes/ticket28856 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket28856 (limited to 'changes') diff --git a/changes/ticket28856 b/changes/ticket28856 new file mode 100644 index 0000000000..b136470494 --- /dev/null +++ b/changes/ticket28856 @@ -0,0 +1,3 @@ + o Minor features (performance): + - Speed up directory parsing a little by avoiding use of the + non-inlined strcmp_len() function. Closes ticket 28856. -- cgit v1.2.3-54-g00ecf From 44db455cc894b4a0fda80a28ed5ea55bf4d41231 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 29 Nov 2018 01:03:03 +1000 Subject: Dir: allow directory mirrors to serve future consensuses When Tor's clock is behind the clocks on the authorities, allow Tor to serve future consensuses. Fixes bug 28654; bugfix on 0.3.0.1-alpha. --- changes/bug28654 | 3 ++ src/feature/dircache/dircache.c | 73 ++++++++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 22 deletions(-) create mode 100644 changes/bug28654 (limited to 'changes') diff --git a/changes/bug28654 b/changes/bug28654 new file mode 100644 index 0000000000..4ca843309f --- /dev/null +++ b/changes/bug28654 @@ -0,0 +1,3 @@ + o Minor bugfixes (directory mirror): + - When Tor's clock is behind the clocks on the authorities, allow Tor to + serve future consensuses. Fixes bug 28654; bugfix on 0.3.0.1-alpha. diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c index 872a88018f..ce90f49108 100644 --- a/src/feature/dircache/dircache.c +++ b/src/feature/dircache/dircache.c @@ -495,28 +495,47 @@ handle_get_frontpage(dir_connection_t *conn, const get_handler_args_t *args) } /** Warn that the cached consensus consensus of type - * flavor is too old and will not be served to clients. Rate-limit the - * warning to avoid logging an entry on every request. + * flavor too new or too old, based on is_too_new, + * and will not be served to clients. Rate-limit the warning to avoid logging + * an entry on every request. */ static void -warn_consensus_is_too_old(const struct consensus_cache_entry_t *consensus, - const char *flavor, time_t now) +warn_consensus_is_not_reasonably_live( + const struct consensus_cache_entry_t *consensus, + const char *flavor, time_t now, bool is_too_new) { -#define TOO_OLD_WARNING_INTERVAL (60*60) - static ratelim_t warned = RATELIM_INIT(TOO_OLD_WARNING_INTERVAL); +#define NOT_REASONABLY_LIVE_WARNING_INTERVAL (60*60) + static ratelim_t warned[2] = { RATELIM_INIT( + NOT_REASONABLY_LIVE_WARNING_INTERVAL), + RATELIM_INIT( + NOT_REASONABLY_LIVE_WARNING_INTERVAL) }; char timestamp[ISO_TIME_LEN+1]; - time_t valid_until; - char *dupes; + /* valid_after if is_too_new, valid_until if !is_too_new */ + time_t valid_time = 0; + char *dupes = NULL; - if (consensus_cache_entry_get_valid_until(consensus, &valid_until)) - return; - - if ((dupes = rate_limit_log(&warned, now))) { - format_local_iso_time(timestamp, valid_until); - log_warn(LD_DIRSERV, "Our %s%sconsensus is too old, so we will not " - "serve it to clients. It was valid until %s local time and we " - "continued to serve it for up to 24 hours after it expired.%s", - flavor ? flavor : "", flavor ? " " : "", timestamp, dupes); + if (is_too_new) { + if (consensus_cache_entry_get_valid_after(consensus, &valid_time)) + return; + dupes = rate_limit_log(&warned[1], now); + } else { + if (consensus_cache_entry_get_valid_until(consensus, &valid_time)) + return; + dupes = rate_limit_log(&warned[0], now); + } + + if (dupes) { + format_local_iso_time(timestamp, valid_time); + log_warn(LD_DIRSERV, "Our %s%sconsensus is too %s, so we will not " + "serve it to clients. It was valid %s %s local time and we " + "continued to serve it for up to 24 hours %s.%s", + flavor ? flavor : "", + flavor ? " " : "", + is_too_new ? "new" : "old", + is_too_new ? "after" : "until", + timestamp, + is_too_new ? "before it was valid" : "after it expired", + dupes); tor_free(dupes); } } @@ -859,7 +878,6 @@ handle_get_current_consensus(dir_connection_t *conn, if (req.diff_only && !cached_consensus) { write_short_http_response(conn, 404, "No such diff available"); - // XXXX warn_consensus_is_too_old(v, req.flavor, now); geoip_note_ns_response(GEOIP_REJECT_NOT_FOUND); goto done; } @@ -870,19 +888,30 @@ handle_get_current_consensus(dir_connection_t *conn, &compression_used); } - time_t fresh_until, valid_until; - int have_fresh_until = 0, have_valid_until = 0; + time_t valid_after, fresh_until, valid_until; + int have_valid_after = 0, have_fresh_until = 0, have_valid_until = 0; if (cached_consensus) { + have_valid_after = + !consensus_cache_entry_get_valid_after(cached_consensus, &valid_after); have_fresh_until = !consensus_cache_entry_get_fresh_until(cached_consensus, &fresh_until); have_valid_until = !consensus_cache_entry_get_valid_until(cached_consensus, &valid_until); } - if (cached_consensus && have_valid_until && + if (cached_consensus && have_valid_after && + !networkstatus_valid_after_is_reasonably_live(valid_after, now)) { + write_short_http_response(conn, 404, "Consensus is too new"); + warn_consensus_is_not_reasonably_live(cached_consensus, req.flavor, now, + 1); + geoip_note_ns_response(GEOIP_REJECT_NOT_FOUND); + goto done; + } else if ( + cached_consensus && have_valid_until && !networkstatus_valid_until_is_reasonably_live(valid_until, now)) { write_short_http_response(conn, 404, "Consensus is too old"); - warn_consensus_is_too_old(cached_consensus, req.flavor, now); + warn_consensus_is_not_reasonably_live(cached_consensus, req.flavor, now, + 0); geoip_note_ns_response(GEOIP_REJECT_NOT_FOUND); goto done; } -- cgit v1.2.3-54-g00ecf From 1bcececdd8e2ff4d6e921270984ba7800c914f64 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sat, 5 Jan 2019 11:01:07 +0200 Subject: Fix CID 1442277 --- changes/bug28989 | 5 +++++ src/test/test_hs_service.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 changes/bug28989 (limited to 'changes') diff --git a/changes/bug28989 b/changes/bug28989 new file mode 100644 index 0000000000..3e3ccccaf3 --- /dev/null +++ b/changes/bug28989 @@ -0,0 +1,5 @@ + o Minor bugfixes (unit tests): + - Instead of relying on hs_free_all() to clean up all onion service + objects we created in test_build_descriptors(), deallocate + them one by one. This lets Coverity know that we are not leaking memory + here and fixes CID 1442277. Fixes bug 28989; bugfix on 0.3.5.1-alpha. diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c index b2aafc1cd6..3357ca2c56 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -289,6 +289,20 @@ helper_create_service(void) return service; } +/* Helper: Deallocate a given service object, its child objects and + * remove it from onion service map. + * */ +static void +helper_destroy_service(hs_service_t *service) +{ + if (!service) + return; + + remove_service(get_hs_service_map(), service); + + hs_service_free(service); +} + /* Helper: Return a newly allocated service object with clients. */ static hs_service_t * helper_create_service_with_clients(int num_clients) @@ -1626,6 +1640,7 @@ test_build_descriptors(void *arg) { int ret; time_t now = time(NULL); + hs_service_t *last_service = NULL; (void) arg; @@ -1650,6 +1665,7 @@ test_build_descriptors(void *arg) * is disabled. */ { hs_service_t *service = helper_create_service(); + last_service = service; service_descriptor_free(service->desc_current); service->desc_current = NULL; @@ -1660,12 +1676,16 @@ test_build_descriptors(void *arg) hs_desc_superencrypted_data_t *superencrypted; superencrypted = &service->desc_current->desc->superencrypted_data; tt_int_op(smartlist_len(superencrypted->clients), OP_EQ, 16); + + helper_destroy_service(service); + last_service = NULL; } /* Generate a valid number of fake auth clients when the number of * clients is zero. */ { hs_service_t *service = helper_create_service_with_clients(0); + last_service = service; service_descriptor_free(service->desc_current); service->desc_current = NULL; @@ -1673,12 +1693,16 @@ test_build_descriptors(void *arg) hs_desc_superencrypted_data_t *superencrypted; superencrypted = &service->desc_current->desc->superencrypted_data; tt_int_op(smartlist_len(superencrypted->clients), OP_EQ, 16); + + helper_destroy_service(service); + last_service = NULL; } /* Generate a valid number of fake auth clients when the number of * clients is not a multiple of 16. */ { hs_service_t *service = helper_create_service_with_clients(20); + last_service = service; service_descriptor_free(service->desc_current); service->desc_current = NULL; @@ -1686,12 +1710,16 @@ test_build_descriptors(void *arg) hs_desc_superencrypted_data_t *superencrypted; superencrypted = &service->desc_current->desc->superencrypted_data; tt_int_op(smartlist_len(superencrypted->clients), OP_EQ, 32); + + helper_destroy_service(service); + last_service = NULL; } /* Do not generate any fake desc client when the number of clients is * a multiple of 16 but not zero. */ { hs_service_t *service = helper_create_service_with_clients(32); + last_service = service; service_descriptor_free(service->desc_current); service->desc_current = NULL; @@ -1699,9 +1727,13 @@ test_build_descriptors(void *arg) hs_desc_superencrypted_data_t *superencrypted; superencrypted = &service->desc_current->desc->superencrypted_data; tt_int_op(smartlist_len(superencrypted->clients), OP_EQ, 32); + + helper_destroy_service(service); + last_service = NULL; } done: + helper_destroy_service(last_service); hs_free_all(); } -- cgit v1.2.3-54-g00ecf From 30a925fe96ed69284a915c8e80d0f7ef7b556786 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sat, 15 Dec 2018 13:53:37 +0200 Subject: Add changes file --- changes/ticket28058 | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 changes/ticket28058 (limited to 'changes') diff --git a/changes/ticket28058 b/changes/ticket28058 new file mode 100644 index 0000000000..00ac595864 --- /dev/null +++ b/changes/ticket28058 @@ -0,0 +1,2 @@ + o Testing: + - Run shellcheck for stuff in scripts/ directory. Closes ticket 28058. -- cgit v1.2.3-54-g00ecf From 7fbe7a256383eebae35c8eec31fe88807c82d394 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Mon, 7 Jan 2019 11:09:33 +0200 Subject: In updateFallbackDirs.py, say 'fallback list' instead of 'whitelist' --- changes/bug24953 | 4 ++++ scripts/maint/updateFallbackDirs.py | 15 ++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 changes/bug24953 (limited to 'changes') diff --git a/changes/bug24953 b/changes/bug24953 new file mode 100644 index 0000000000..d142dfd6cc --- /dev/null +++ b/changes/bug24953 @@ -0,0 +1,4 @@ + o Minor bugfixes (fallback scripts): + - In updateFallbackDirs.py, call the filter file a "fallback list" + instead of a "whitelist" in check_existing mode. + Fixes bug 24953; bugfix on 0.3.0.3-alpha. diff --git a/scripts/maint/updateFallbackDirs.py b/scripts/maint/updateFallbackDirs.py index 14372d0e83..e93db7ab3f 100755 --- a/scripts/maint/updateFallbackDirs.py +++ b/scripts/maint/updateFallbackDirs.py @@ -1594,7 +1594,7 @@ class CandidateList(dict): """ Apply the fallback whitelist_obj to this fallback list, passing exact to is_in_whitelist(). """ excluded_count = 0 - logging.debug('Applying whitelist') + logging.debug('Applying fallback list') # parse the whitelist whitelist = self.load_relaylist(whitelist_obj) filtered_fallbacks = [] @@ -1609,14 +1609,18 @@ class CandidateList(dict): else: # exclude excluded_count += 1 - log_excluded('Excluding %s: not in whitelist.', + log_excluded('Excluding %s: not in fallback list.', f._fpr) self.fallbacks = filtered_fallbacks return excluded_count @staticmethod - def summarise_filters(initial_count, excluded_count): - return '/* Whitelist excluded %d of %d candidates. */'%( + def summarise_filters(initial_count, excluded_count, check_existing): + list_type = 'Whitelist' + if check_existing: + list_type = 'Fallback list' + + return '/* %s excluded %d of %d candidates. */'%(list_type, excluded_count, initial_count) # calculate each fallback's measured bandwidth based on the median @@ -2284,7 +2288,8 @@ def list_fallbacks(whitelist, exact=False): # instead, there will be an info-level log during the eligibility check. initial_count = len(candidates.fallbacks) excluded_count = candidates.apply_filter_lists(whitelist, exact=exact) - print candidates.summarise_filters(initial_count, excluded_count) + print candidates.summarise_filters(initial_count, excluded_count, + whitelist['check_existing']) eligible_count = len(candidates.fallbacks) # calculate the measured bandwidth of each relay, -- cgit v1.2.3-54-g00ecf From 6440fdb8de64f7a42924e2ff1ee2d960c18e6888 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Tue, 15 Jan 2019 22:50:52 +0000 Subject: Changes file for Ticket 28142. --- changes/ticket28142 | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 changes/ticket28142 (limited to 'changes') diff --git a/changes/ticket28142 b/changes/ticket28142 new file mode 100644 index 0000000000..b74b2bd47e --- /dev/null +++ b/changes/ticket28142 @@ -0,0 +1,10 @@ + o Major features (circuit padding): + - Implement preliminary support for the circuit padding portion of + Proposal 254. The implementation supports Adaptive Padding (aka + WTF-PAD) state machines for use between experimental clients and + relays. Support is also provided for APE-style state machines that + use probability distributions instead of histograms to specify + inter-packet delay. At the moment, Tor does not provide any padding + state machines that are used in normal operation -- this feature + exists solely for experimentation in this release. Closes + ticket 28142. -- cgit v1.2.3-54-g00ecf From 2dd23086f13ecfc9843a9612e208a3592ac46141 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 15 Jan 2019 19:18:00 -0500 Subject: Remove fallback scripts and whitelist They have been extracted to a new fallback-scripts.git repository. Closes ticket 27914. --- changes/ticket27914 | 4 + scripts/maint/fallback.whitelist | 1064 ------------- scripts/maint/generateFallbackDirLine.py | 38 - scripts/maint/lookupFallbackDirContact.py | 28 - scripts/maint/updateFallbackDirs.py | 2383 ----------------------------- 5 files changed, 4 insertions(+), 3513 deletions(-) create mode 100644 changes/ticket27914 delete mode 100644 scripts/maint/fallback.whitelist delete mode 100755 scripts/maint/generateFallbackDirLine.py delete mode 100755 scripts/maint/lookupFallbackDirContact.py delete mode 100755 scripts/maint/updateFallbackDirs.py (limited to 'changes') diff --git a/changes/ticket27914 b/changes/ticket27914 new file mode 100644 index 0000000000..433e9657af --- /dev/null +++ b/changes/ticket27914 @@ -0,0 +1,4 @@ + o Removed features: + - The scripts used to generate and maintain the list of fallback + directories have been extracted into a new "fallback-scripts" + repository. Closes ticket 27914. diff --git a/scripts/maint/fallback.whitelist b/scripts/maint/fallback.whitelist deleted file mode 100644 index 60d3e7bb85..0000000000 --- a/scripts/maint/fallback.whitelist +++ /dev/null @@ -1,1064 +0,0 @@ -# updateFallbackDirs.py directory mirror whitelist -# -# At least one of these keys must match for a directory mirror to be included -# in the fallback list: -# id -# ipv4 -# ipv6 -# The ports and nickname are ignored. Missing or extra ipv6 addresses -# are ignored. -# -# The latest relay details from Onionoo are included in the generated list. -# -# To check the hard-coded fallback list (for testing), use: -# $ updateFallbackDirs.py check_existing -# -# If a relay operator wants their relay to be a FallbackDir, -# enter the following information here: -# : orport= id= ( ipv6=[]: )? -# or use: -# scripts/maint/generateFallbackDirLine.py fingerprint ... - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008362.html -# https://trac.torproject.org/projects/tor/ticket/22321#comment:22 -78.47.18.110:443 orport=80 id=F8D27B163B9247B232A2EEE68DD8B698695C28DE ipv6=[2a01:4f8:120:4023::110]:80 # fluxe3 -131.188.40.188:1443 orport=80 id=EBE718E1A49EE229071702964F8DB1F318075FF8 ipv6=[2001:638:a000:4140::ffff:188]:80 # fluxe4 - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008366.html -5.39.88.19:9030 orport=9001 id=7CB8C31432A796731EA7B6BF4025548DFEB25E0C ipv6=[2001:41d0:8:9a13::1]:9050 - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008370.html -# https://lists.torproject.org/pipermail/tor-relays/2016-January/008517.html -# https://lists.torproject.org/pipermail/tor-relays/2016-January/008555.html -212.47.237.95:9030 orport=9001 id=3F5D8A879C58961BB45A3D26AC41B543B40236D6 -212.47.237.95:9130 orport=9101 id=6FB38EB22E57EF7ED5EF00238F6A48E553735D88 - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008372.html -# IPv6 tunnel available on request (is this a good idea?) -108.53.208.157:80 orport=443 id=4F0DB7E687FC7C0AE55C8F243DA8B0EB27FBF1F2 - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008373.html -167.114.35.28:9030 orport=9001 id=E65D300F11E1DB12C534B0146BDAB6972F1A8A48 - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008378.html -144.76.14.145:110 orport=143 id=14419131033443AE6E21DA82B0D307F7CAE42BDB ipv6=[2a01:4f8:190:9490::dead]:443 - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008379.html -# Email sent directly to teor, verified using relay contact info -91.121.84.137:4951 orport=4051 id=6DE61A6F72C1E5418A66BFED80DFB63E4C77668F - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008381.html -# Sent additional emails to teor with updated relays -81.7.11.96:9030 orport=9001 id=8FA37B93397015B2BC5A525C908485260BE9F422 # Doedel22 -# 9F5068310818ED7C70B0BC4087AB55CB12CB4377 not found in current consensus -178.254.19.101:80 orport=443 id=F9246DEF2B653807236DA134F2AEAB103D58ABFE # Freebird31 -178.254.19.101:9030 orport=9001 id=0C475BA4D3AA3C289B716F95954CAD616E50C4E5 # Freebird32 -81.7.14.253:9001 orport=443 id=1AE039EE0B11DB79E4B4B29CBA9F752864A0259E # Ichotolot60 -81.7.11.186:1080 orport=443 id=B86137AE9681701901C6720E55C16805B46BD8E3 # BeastieJoy60 -85.25.213.211:465 orport=80 id=CE47F0356D86CF0A1A2008D97623216D560FB0A8 # BeastieJoy61 -85.25.159.65:995 orport=80 id=52BFADA8BEAA01BA46C8F767F83C18E2FE50C1B9 # BeastieJoy63 -81.7.3.67:993 orport=443 id=A2E6BB5C391CD46B38C55B4329C35304540771F1 # BeastieJoy62 -81.7.14.31:9001 orport=443 id=7600680249A22080ECC6173FBBF64D6FCF330A61 # Ichotolot62 - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008382.html -51.255.33.237:9091 orport=9001 id=A360C21FA87FFA2046D92C17086A6B47E5C68109 - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008383.html -81.7.14.246:80 orport=443 id=CE75BF0972ADD52AF8807602374E495C815DB304 ipv6=[2a02:180:a:51::dead]:443 - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008384.html -# Sent additional email to teor with fingerprint change -149.202.98.161:80 orport=443 id=FC64CD763F8C1A319BFBBF62551684F4E1E42332 ipv6=[2001:41d0:8:4528::161]:443 -193.111.136.162:80 orport=443 id=C79552275DFCD486B942510EF663ED36ACA1A84B ipv6=[2001:4ba0:cafe:10d0::1]:443 - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008416.html -185.100.84.212:80 orport=443 id=330CD3DB6AD266DC70CDB512B036957D03D9BC59 ipv6=[2a06:1700:0:7::1]:443 - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008417.html -178.16.208.56:80 orport=443 id=2CDCFED0142B28B002E89D305CBA2E26063FADE2 ipv6=[2a00:1c20:4089:1234:cd49:b58a:9ebe:67ec]:443 -178.16.208.57:80 orport=443 id=92CFD9565B24646CAC2D172D3DB503D69E777B8A ipv6=[2a00:1c20:4089:1234:7825:2c5d:1ecd:c66f]:443 - -# https://lists.torproject.org/pipermail/tor-relays/2016-January/008513.html -178.62.173.203:9030 orport=9001 id=DD85503F2D1F52EF9EAD621E942298F46CD2FC10 ipv6=[2a03:b0c0:0:1010::a4:b001]:9001 - -# https://lists.torproject.org/pipermail/tor-relays/2016-January/008534.html -5.9.110.236:9030 orport=9001 id=0756B7CD4DFC8182BE23143FAC0642F515182CEB ipv6=[2a01:4f8:162:51e2::2]:9001 - -# https://lists.torproject.org/pipermail/tor-relays/2016-January/008542.html -178.62.199.226:80 orport=443 id=CBEFF7BA4A4062045133C053F2D70524D8BBE5BE ipv6=[2a03:b0c0:2:d0::b7:5001]:443 - -# Email sent directly to teor, verified using relay contact info -94.23.204.175:9030 orport=9001 id=5665A3904C89E22E971305EE8C1997BCA4123C69 - -# Email sent directly to teor, verified using relay contact info -171.25.193.77:80 orport=443 id=A10C4F666D27364036B562823E5830BC448E046A ipv6=[2001:67c:289c:3::77]:443 -171.25.193.78:80 orport=443 id=A478E421F83194C114F41E94F95999672AED51FE ipv6=[2001:67c:289c:3::78]:443 -171.25.193.20:80 orport=443 id=DD8BD7307017407FCC36F8D04A688F74A0774C02 ipv6=[2001:67c:289c::20]:443 -# same machine as DD8BD7307017407FCC36F8D04A688F74A0774C02 -171.25.193.25:80 orport=443 id=185663B7C12777F052B2C2D23D7A239D8DA88A0F ipv6=[2001:67c:289c::25]:443 - -# Email sent directly to teor, verified using relay contact info -212.47.229.2:9030 orport=9001 id=20462CBA5DA4C2D963567D17D0B7249718114A68 ipv6=[2001:bc8:4400:2100::f03]:9001 -93.115.97.242:9030 orport=9001 id=B5212DB685A2A0FCFBAE425738E478D12361710D -46.28.109.231:9030 orport=9001 id=F70B7C5CD72D74C7F9F2DC84FA9D20D51BA13610 ipv6=[2a02:2b88:2:1::4205:1]:9001 - -# Email sent directly to teor, verified using relay contact info -85.235.250.88:80 orport=443 id=72B2B12A3F60408BDBC98C6DF53988D3A0B3F0EE # TykRelay01 -185.96.88.29:80 orport=443 id=86C281AD135058238D7A337D546C902BE8505DDE # TykRelay051 -# This fallback opted-in in previous releases, then changed its details, -# and so we blacklisted it. Now we want to whitelist changes. -# Assume details update is permanent -185.96.180.29:80 orport=443 id=F93D8F37E35C390BCAD9F9069E13085B745EC216 # TykRelay06 - -# Email sent directly to teor, verified using relay contact info -185.11.180.67:80 orport=9001 id=794D8EA8343A4E820320265D05D4FA83AB6D1778 - -# Email sent directly to teor, verified using relay contact info -178.16.208.62:80 orport=443 id=5CF8AFA5E4B0BB88942A44A3F3AAE08C3BDFD60B ipv6=[2a00:1c20:4089:1234:a6a4:2926:d0af:dfee]:443 -46.165.221.166:80 orport=443 id=EE5F897C752D46BCFF531641B853FC6BC78DD4A7 -178.16.208.60:80 orport=443 id=B44FBE5366AD98B46D829754FA4AC599BAE41A6A ipv6=[2a00:1c20:4089:1234:67bc:79f3:61c0:6e49]:443 -178.16.208.55:80 orport=443 id=C4AEA05CF380BAD2230F193E083B8869B4A29937 ipv6=[2a00:1c20:4089:1234:7b2c:11c5:5221:903e]:443 -178.16.208.61:80 orport=443 id=3B52392E2256C35CDCF7801FF898FC88CE6D431A ipv6=[2a00:1c20:4089:1234:2712:a3d0:666b:88a6]:443 -81.89.96.88:80 orport=443 id=55ED4BB49F6D3F36D8D9499BE43500E017A5EF82 ipv6=[2a02:180:1:1:14c5:b0b7:2d7d:5f3a]:443 -209.222.8.196:80 orport=443 id=C86D2F3DEFE287A0EEB28D4887AF14E35C172733 ipv6=[2001:19f0:1620:41c1:426c:5adf:2ed5:4e88]:443 -81.89.96.89:80 orport=443 id=28651F419F5A1CF74511BB500C58112192DD4943 ipv6=[2a02:180:1:1:2ced:24e:32ea:a03b]:443 -46.165.221.166:9030 orport=9001 id=8C7106C880FE8AA1319DD71B59623FCB8914C9F1 -178.16.208.62:80 orport=443 id=5CF8AFA5E4B0BB88942A44A3F3AAE08C3BDFD60B ipv6=[2a00:1c20:4089:1234:a6a4:2926:d0af:dfee]:443" -46.165.221.166:80 orport=443 id=EE5F897C752D46BCFF531641B853FC6BC78DD4A7 -178.16.208.60:80 orport=443 id=B44FBE5366AD98B46D829754FA4AC599BAE41A6A ipv6=[2a00:1c20:4089:1234:67bc:79f3:61c0:6e49]:443 -178.16.208.55:80 orport=443 id=C4AEA05CF380BAD2230F193E083B8869B4A29937 ipv6=[2a00:1c20:4089:1234:7b2c:11c5:5221:903e]:443 -178.16.208.61:80 orport=443 id=3B52392E2256C35CDCF7801FF898FC88CE6D431A ipv6=[2a00:1c20:4089:1234:2712:a3d0:666b:88a6]:443 -81.89.96.88:80 orport=443 id=55ED4BB49F6D3F36D8D9499BE43500E017A5EF82 ipv6=[2a02:180:1:1:14c5:b0b7:2d7d:5f3a]:443 -209.222.8.196:80 orport=443 id=C86D2F3DEFE287A0EEB28D4887AF14E35C172733 ipv6=[2001:19f0:1620:41c1:426c:5adf:2ed5:4e88]:443 -81.89.96.89:80 orport=443 id=28651F419F5A1CF74511BB500C58112192DD4943 ipv6=[2a02:180:1:1:2ced:24e:32ea:a03b]:443 -46.165.221.166:9030 orport=9001 id=8C7106C880FE8AA1319DD71B59623FCB8914C9F1 -178.16.208.56:80 orport=443 id=2CDCFED0142B28B002E89D305CBA2E26063FADE2 ipv6=[2a00:1c20:4089:1234:cd49:b58a:9ebe:67ec]:443 -178.16.208.58:80 orport=443 id=A4C98CEA3F34E05299417E9F885A642C88EF6029 ipv6=[2a00:1c20:4089:1234:cdae:1b3e:cc38:3d45]:443 -178.16.208.57:80 orport=443 id=92CFD9565B24646CAC2D172D3DB503D69E777B8A ipv6=[2a00:1c20:4089:1234:7825:2c5d:1ecd:c66f]:443 -178.16.208.59:80 orport=443 id=136F9299A5009A4E0E96494E723BDB556FB0A26B ipv6=[2a00:1c20:4089:1234:bff6:e1bb:1ce3:8dc6]:443 - -# Email sent directly to teor, verified using relay contact info -5.39.76.158:80 orport=443 id=C41F60F8B00E7FEF5CCC5BC6BB514CA1B8AAB651 - -# Email sent directly to teor, verified using relay contact info -109.163.234.2:80 orport=443 id=14F92FF956105932E9DEC5B82A7778A0B1BD9A52 -109.163.234.4:80 orport=443 id=4888770464F0E900EFEF1BA181EA873D13F7713C -109.163.234.5:80 orport=443 id=5EB8D862E70981B8690DEDEF546789E26AB2BD24 -109.163.234.7:80 orport=443 id=23038A7F2845EBA2234ECD6651BD4A7762F51B18 -109.163.234.8:80 orport=443 id=0818DAE0E2DDF795AEDEAC60B15E71901084F281 -109.163.234.9:80 orport=443 id=ABF7FBF389C9A747938B639B20E80620B460B2A9 -62.102.148.67:80 orport=443 id=4A0C3E177AF684581EF780981AEAF51A98A6B5CF -# Assume details update is permanent -77.247.181.166:80 orport=443 id=77131D7E2EC1CA9B8D737502256DA9103599CE51 # CriticalMass -77.247.181.164:80 orport=443 id=204DFD2A2C6A0DC1FA0EACB495218E0B661704FD # HaveHeart -77.247.181.162:80 orport=443 id=7BFB908A3AA5B491DA4CA72CCBEE0E1F2A939B55 # sofia - -# https://twitter.com/biotimylated/status/718994247500718080 -212.47.252.149:9030 orport=9001 id=2CAC39BAA996791CEFAADC9D4754D65AF5EB77C0 - -# Email sent directly to teor, verified using relay contact info -46.165.230.5:80 orport=443 id=A0F06C2FADF88D3A39AA3072B406F09D7095AC9E - -# Email sent directly to teor, verified using relay contact info -94.242.246.24:23 orport=8080 id=EC116BCB80565A408CE67F8EC3FE3B0B02C3A065 ipv6=[2a01:608:ffff:ff07::1:24]:9004 -94.242.246.23:443 orport=9001 id=F65E0196C94DFFF48AFBF2F5F9E3E19AAE583FD0 ipv6=[2a01:608:ffff:ff07::1:23]:9003 -85.248.227.164:444 orport=9002 id=B84F248233FEA90CAD439F292556A3139F6E1B82 ipv6=[2a00:1298:8011:212::164]:9004 -85.248.227.163:443 orport=9001 id=C793AB88565DDD3C9E4C6F15CCB9D8C7EF964CE9 ipv6=[2a00:1298:8011:212::163]:9003 - -# Email sent directly to teor, verified using relay contact info -148.251.190.229:9030 orport=9010 id=BF0FB582E37F738CD33C3651125F2772705BB8E8 ipv6=[2a01:4f8:211:c68::2]:9010 - -# Email sent directly to teor, verified using relay contact info -5.79.68.161:81 orport=443 id=9030DCF419F6E2FBF84F63CBACBA0097B06F557E ipv6=[2001:1af8:4700:a012:1::1]:443 -5.79.68.161:9030 orport=9001 id=B7EC0C02D7D9F1E31B0C251A6B058880778A0CD1 ipv6=[2001:1af8:4700:a012:1::1]:9001 - -# Email sent directly to teor, verified using relay contact info -62.210.92.11:9030 orport=9001 id=0266B0660F3F20A7D1F3D8335931C95EF50F6C6B ipv6=[2001:bc8:338c::1]:9001 -62.210.92.11:9130 orport=9101 id=387B065A38E4DAA16D9D41C2964ECBC4B31D30FF ipv6=[2001:bc8:338c::1]:9101 - -# Email sent directly to teor, verified using relay contact info -188.165.194.195:9030 orport=9001 id=49E7AD01BB96F6FE3AB8C3B15BD2470B150354DF - -# Message sent directly to teor, verified using relay contact info -95.215.44.110:80 orport=443 id=D56AA4A1AA71961F5279FB70A6DCF7AD7B993EB5 -95.215.44.122:80 orport=443 id=998D8FE06B867AA3F8D257A7D28FFF16964D53E2 -95.215.44.111:80 orport=443 id=A7C7FD510B20BC8BE8F2A1D911364E1A23FBD09F - -# Email sent directly to teor, verified using relay contact info -86.59.119.88:80 orport=443 id=ACD889D86E02EDDAB1AFD81F598C0936238DC6D0 -86.59.119.83:80 orport=443 id=FC9AC8EA0160D88BCCFDE066940D7DD9FA45495B - -# Email sent directly to teor, verified using relay contact info -193.11.164.243:9030 orport=9001 id=FFA72BD683BC2FCF988356E6BEC1E490F313FB07 ipv6=[2001:6b0:7:125::243]:9001 -109.105.109.162:52860 orport=60784 id=32EE911D968BE3E016ECA572BB1ED0A9EE43FC2F ipv6=[2001:948:7:2::163]:5001 - -# Email sent directly to teor, verified using relay contact info -146.0.32.144:9030 orport=9001 id=35E8B344F661F4F2E68B17648F35798B44672D7E - -# Email sent directly to teor, verified using relay contact info -46.252.26.2:45212 orport=49991 id=E589316576A399C511A9781A73DA4545640B479D - -# Email sent directly to teor, verified using relay contact info -89.187.142.208:80 orport=443 id=64186650FFE4469EBBE52B644AE543864D32F43C - -# Email sent directly to teor -# Assume details update is permanent -212.51.134.123:9030 orport=9001 id=50586E25BE067FD1F739998550EDDCB1A14CA5B2 # Jans - -# Email sent directly to teor, verified using relay contact info -46.101.143.173:80 orport=443 id=F960DF50F0FD4075AC9B505C1D4FFC8384C490FB - -# Email sent directly to teor, verified using relay contact info -193.171.202.146:9030 orport=9001 id=01A9258A46E97FF8B2CAC7910577862C14F2C524 - -# Email sent directly to teor, verified using relay contact info -# Assume details update is permanent -197.231.221.211:9030 orport=443 id=BC630CBBB518BE7E9F4E09712AB0269E9DC7D626 # IPredator - -# Email sent directly to teor, verified using relay contact info -185.61.138.18:8080 orport=4443 id=2541759BEC04D37811C2209A88E863320271EC9C - -# Email sent directly to teor, verified using relay contact info -193.11.114.45:9031 orport=9002 id=80AAF8D5956A43C197104CEF2550CD42D165C6FB -193.11.114.43:9030 orport=9001 id=12AD30E5D25AA67F519780E2111E611A455FDC89 ipv6=[2001:6b0:30:1000::99]:9050 -193.11.114.46:9032 orport=9003 id=B83DC1558F0D34353BB992EF93AFEAFDB226A73E - -# Email sent directly to teor, verified using relay contact info -138.201.250.33:9012 orport=9011 id=2BA2C8E96B2590E1072AECE2BDB5C48921BF8510 - -# Email sent directly to teor, verified using relay contact info -37.221.162.226:9030 orport=9001 id=D64366987CB39F61AD21DBCF8142FA0577B92811 - -# Email sent directly to teor, verified using relay contact info -91.219.237.244:80 orport=443 id=92ECC9E0E2AF81BB954719B189AC362E254AD4A5 - -# Email sent directly to teor, verified using relay contact info -185.21.100.50:9030 orport=9001 id=58ED9C9C35E433EE58764D62892B4FFD518A3CD0 ipv6=[2a00:1158:2:cd00:0:74:6f:72]:443 - -# Email sent directly to teor, verified using relay contact info -193.35.52.53:9030 orport=9001 id=DAA39FC00B196B353C2A271459C305C429AF09E4 - -# Email sent directly to teor, verified using relay contact info -134.119.3.164:9030 orport=9001 id=D1B8AAA98C65F3DF7D8BB3AF881CAEB84A33D8EE - -# Email sent directly to teor, verified using relay contact info -173.212.254.192:31336 orport=31337 id=99E246DB480B313A3012BC3363093CC26CD209C7 - -# Email sent directly to teor, verified using relay contact info -178.62.22.36:80 orport=443 id=A0766C0D3A667A3232C7D569DE94A28F9922FCB1 ipv6=[2a03:b0c0:1:d0::174:1]:9050 -188.166.23.127:80 orport=443 id=8672E8A01B4D3FA4C0BBE21C740D4506302EA487 ipv6=[2a03:b0c0:2:d0::27b:7001]:9050 -198.199.64.217:80 orport=443 id=B1D81825CFD7209BD1B4520B040EF5653C204A23 ipv6=[2604:a880:400:d0::1a9:b001]:9050 -159.203.32.149:80 orport=443 id=55C7554AFCEC1062DCBAC93E67B2E03C6F330EFC ipv6=[2604:a880:cad:d0::105:f001]:9050 - -# Email sent directly to teor, verified using relay contact info -5.196.31.80:9030 orport=9900 id=DFB2EB472643FAFCD5E73D2E37D51DB67203A695 ipv6=[2001:41d0:52:400::a65]:9900 - -# Email sent directly to teor, verified using relay contact info -188.138.112.60:1433 orport=1521 id=C414F28FD2BEC1553024299B31D4E726BEB8E788 - -# Email sent directly to teor, verified using relay contact info -213.61.66.118:9031 orport=9001 id=30648BC64CEDB3020F4A405E4AB2A6347FB8FA22 -213.61.66.117:9032 orport=9002 id=6E44A52E3D1FF7683FE5C399C3FB5E912DE1C6B4 -213.61.66.115:9034 orport=9004 id=480CCC94CEA04D2DEABC0D7373868E245D4C2AE2 -213.61.66.116:9033 orport=9003 id=A9DEB920B42B4EC1DE6249034039B06D61F38690 - -# Email sent directly to teor, verified using relay contact info -136.243.187.165:9030 orport=443 id=1AC65257D7BFDE7341046625470809693A8ED83E - -# Email sent directly to teor, verified using relay contact info -212.47.230.49:9030 orport=9001 id=3D6D0771E54056AEFC28BB1DE816951F11826E97 - -# Email sent directly to teor, verified using relay contact info -192.99.55.69:80 orport=443 id=0682DE15222A4A4A0D67DBA72A8132161992C023 -192.99.59.140:80 orport=443 id=3C9148DA49F20654730FAC83FFF693A4D49D0244 -51.254.215.13:80 orport=443 id=73C30C8ABDD6D9346C822966DE73B9F82CB6178A -51.254.215.129:80 orport=443 id=7B4491D05144B20AE8519AE784B94F0525A8BB79 -192.99.59.139:80 orport=443 id=82EC878ADA7C205146B9F5193A7310867FAA0D7B -51.254.215.124:80 orport=443 id=98999EBE89B5FA9AA0C58421F0B46C3D0AF51CBA -51.254.214.208:80 orport=443 id=C3F0D1417848EAFC41277A73DEB4A9F2AEC23DDF -192.99.59.141:80 orport=443 id=F45426551795B9DA78BEDB05CD5F2EACED8132E4 -192.99.59.14:80 orport=443 id=161A1B29A37EBF096D2F8A9B1E176D6487FE42AE - -# Email sent directly to teor, verified using relay contact info -151.80.42.103:9030 orport=9001 id=9007C1D8E4F03D506A4A011B907A9E8D04E3C605 ipv6=[2001:41d0:e:f67::114]:9001 - -# Email sent directly to teor, verified using relay contact info -176.31.159.231:80 orport=443 id=D5DBCC0B4F029F80C7B8D33F20CF7D97F0423BB1 -176.31.159.230:80 orport=443 id=631748AFB41104D77ADBB7E5CD4F8E8AE876E683 -195.154.79.128:80 orport=443 id=C697612CA5AED06B8D829FCC6065B9287212CB2F -195.154.9.161:80 orport=443 id=B6295A9960F89BD0C743EEBC5670450EA6A34685 -46.148.18.74:8080 orport=443 id=6CACF0B5F03C779672F3C5C295F37C8D234CA3F7 - -# Email sent directly to teor, verified using relay contact info -37.187.102.108:80 orport=443 id=F4263275CF54A6836EE7BD527B1328836A6F06E1 ipv6=[2001:41d0:a:266c::1]:443 # EvilMoe -212.47.241.21:80 orport=443 id=892F941915F6A0C6E0958E52E0A9685C190CF45C # EvilMoe - -# Email sent directly to teor, verified using relay contact info -212.129.38.254:9030 orport=9001 id=FDF845FC159C0020E2BDDA120C30C5C5038F74B4 - -# Email sent directly to teor -37.157.195.87:8030 orport=443 id=12FD624EE73CEF37137C90D38B2406A66F68FAA2 # thanatosCZ -5.189.169.190:8030 orport=8080 id=8D79F73DCD91FC4F5017422FAC70074D6DB8DD81 # thanatosDE - -# Email sent directly to teor, verified using relay contact info -37.187.7.74:80 orport=443 id=AEA43CB1E47BE5F8051711B2BF01683DB1568E05 ipv6=[2001:41d0:a:74a::1]:443 - -# Email sent directly to teor, verified using relay contact info -185.66.250.141:9030 orport=9001 id=B1726B94885CE3AC3910CA8B60622B97B98E2529 - -# Email sent directly to teor, verified using relay contact info -# Email sent directly to Phoul -185.104.120.7:9030 orport=443 id=445F1C853966624FB3CF1E12442570DC553CC2EC ipv6=[2a06:3000::120:7]:443 -185.104.120.2:9030 orport=21 id=518FF8708698E1DA09C823C36D35DF89A2CAD956 ipv6=[2a06:3000::120:2]:443 -185.104.120.4:9030 orport=9001 id=F92B3CB9BBE0CB22409843FB1AE4DBCD5EFAC835 ipv6=[2a06:3000::120:4]:443 -185.104.120.3:9030 orport=21 id=707C1B61AC72227B34487B56D04BAA3BA1179CE8 ipv6=[2a06:3000::120:3]:443 -185.104.120.5:80 orport=443 id=3EBDF84DE3B16F0EBF7D51450F07913A02EFDA6C ipv6=[2a06:3000::120:5]:443 -185.104.120.60:80 orport=443 id=D05C9C7068EB5A45F670D5E38A14907EE6223141 ipv6=[2a06:3000::120:60]:443 - - -# Email sent directly to teor, verified using relay contact info -37.187.102.186:9030 orport=9001 id=489D94333DF66D57FFE34D9D59CC2D97E2CB0053 ipv6=[2001:41d0:a:26ba::1]:9001 - -# Email sent directly to teor, verified using relay contact info -198.96.155.3:8080 orport=5001 id=BCEDF6C193AA687AE471B8A22EBF6BC57C2D285E - -# Email sent directly to teor, verified using relay contact info -212.83.154.33:8888 orport=443 id=3C79699D4FBC37DE1A212D5033B56DAE079AC0EF -212.83.154.33:8080 orport=8443 id=322C6E3A973BC10FC36DE3037AD27BC89F14723B - -# Email sent directly to teor, verified using relay contact info -51.255.41.65:9030 orport=9001 id=9231DF741915AA1630031A93026D88726877E93A - -# Email sent directly to teor, verified using relay contact info -78.142.142.246:80 orport=443 id=5A5E03355C1908EBF424CAF1F3ED70782C0D2F74 - -# Email sent directly to teor, verified using relay contact info -195.154.97.91:80 orport=443 id=BD33C50D50DCA2A46AAED54CA319A1EFEBF5D714 - -# Email sent directly to teor, verified using relay contact info -62.210.129.246:80 orport=443 id=79E169B25E4C7CE99584F6ED06F379478F23E2B8 - -# Email sent directly to teor, verified using relay contact info -5.196.74.215:9030 orport=9001 id=5818055DFBAF0FA7F67E8125FD63E3E7F88E28F6 - -# Email sent directly to teor, verified using relay contact info -212.47.233.86:9030 orport=9001 id=B4CAFD9CBFB34EC5DAAC146920DC7DFAFE91EA20 - -# Email sent directly to teor, verified using relay contact info -85.214.206.219:9030 orport=9001 id=98F8D5F359949E41DE8DF3DBB1975A86E96A84A0 - -# Email sent directly to teor, verified using relay contact info -46.166.170.4:80 orport=443 id=19F42DB047B72C7507F939F5AEA5CD1FA4656205 -46.166.170.5:80 orport=443 id=DA705AD4591E7B4708FA2CAC3D53E81962F3E6F6 - -# Email sent directly to teor, verified using relay contact info -5.189.157.56:80 orport=443 id=77F6D6A6B6EAFB8F5DADDC07A918BBF378ED6725 - -# Email sent directly to teor, verified using relay contact info -46.28.110.244:80 orport=443 id=9F7D6E6420183C2B76D3CE99624EBC98A21A967E -185.13.39.197:80 orport=443 id=001524DD403D729F08F7E5D77813EF12756CFA8D -95.130.12.119:80 orport=443 id=587E0A9552E4274B251F29B5B2673D38442EE4BF - -# Email sent directly to teor, verified using relay contact info -212.129.62.232:80 orport=443 id=B143D439B72D239A419F8DCE07B8A8EB1B486FA7 - -# Email sent directly to teor, verified using relay contact info -91.219.237.229:80 orport=443 id=1ECD73B936CB6E6B3CD647CC204F108D9DF2C9F7 - -# Email sent directly to teor, verified using relay contact info -178.62.197.82:80 orport=443 id=0D3EBA17E1C78F1E9900BABDB23861D46FCAF163 - -# Email sent directly to teor, verified using relay contact info -82.223.21.74:9030 orport=9001 id=7A32C9519D80CA458FC8B034A28F5F6815649A98 ipv6=[2001:470:53e0::cafe]:9050 - -# Email sent directly to teor, verified using relay contact info -146.185.177.103:80 orport=9030 id=9EC5E097663862DF861A18C32B37C5F82284B27D - -# Email sent directly to teor, verified using relay contact info -37.187.22.87:9030 orport=9001 id=36B9E7AC1E36B62A9D6F330ABEB6012BA7F0D400 ipv6=[2001:41d0:a:1657::1]:9001 - -# Email sent directly to teor, verified using relay contact info -37.59.46.159:9030 orport=9001 id=CBD0D1BD110EC52963082D839AC6A89D0AE243E7 - -# Email sent directly to teor, verified using relay contact info -212.47.250.243:9030 orport=9001 id=5B33EDBAEA92F446768B3753549F3B813836D477 -# Confirm with operator before adding these -#163.172.133.36:9030 orport=9001 id=D8C2BD36F01FA86F4401848A0928C4CB7E5FDFF9 -#158.69.216.70:9030 orport=9001 id=0ACE25A978D4422C742D6BC6345896719BF6A7EB - -# Email sent directly to teor, verified using relay contact info -5.199.142.236:9030 orport=9001 id=F4C0EDAA0BF0F7EC138746F8FEF1CE26C7860265 - -# Email sent directly to teor, verified using relay contact info -46.8.249.10:80 orport=443 id=31670150090A7C3513CB7914B9610E786391A95D - -# Email sent directly to teor, verified using relay contact info -144.76.163.93:9030 orport=9001 id=22F08CF09764C4E8982640D77F71ED72FF26A9AC - -# Email sent directly to teor, verified using relay contact info -46.4.24.161:9030 orport=9001 id=DB4C76A3AD7E234DA0F00D6F1405D8AFDF4D8DED -46.4.24.161:9031 orport=9002 id=7460F3D12EBE861E4EE073F6233047AACFE46AB4 -46.38.51.132:9030 orport=9001 id=810DEFA7E90B6C6C383C063028EC397A71D7214A -163.172.194.53:9030 orport=9001 id=8C00FA7369A7A308F6A137600F0FA07990D9D451 ipv6=[2001:bc8:225f:142:6c69:7461:7669:73]:9001 - -# Email sent directly to teor, verified using relay contact info -176.10.107.180:9030 orport=9001 id=3D7E274A87D9A89AF064C13D1EE4CA1F184F2600 - -# Email sent directly to teor, verified using relay contact info -46.28.207.19:80 orport=443 id=5B92FA5C8A49D46D235735504C72DBB3472BA321 -46.28.207.141:80 orport=443 id=F69BED36177ED727706512BA6A97755025EEA0FB -46.28.205.170:80 orport=443 id=AF322D83A4D2048B22F7F1AF5F38AFF4D09D0B76 -95.183.48.12:80 orport=443 id=7187CED1A3871F837D0E60AC98F374AC541CB0DA - -# Email sent directly to teor, verified using relay contact info -93.180.156.84:9030 orport=9001 id=8844D87E9B038BE3270938F05AF797E1D3C74C0F - -# Email sent directly to teor, verified using relay contact info -37.187.115.157:9030 orport=9001 id=D5039E1EBFD96D9A3F9846BF99EC9F75EDDE902A - -# Email sent directly to teor, verified using relay contact info -5.34.183.205:80 orport=443 id=DDD7871C1B7FA32CB55061E08869A236E61BDDF8 - -# Email sent directly to teor, verified using relay contact info -51.254.246.203:9030 orport=9001 id=47B596B81C9E6277B98623A84B7629798A16E8D5 - -# Email sent directly to teor, verified using relay contact info -5.9.146.203:80 orport=443 id=1F45542A24A61BF9408F1C05E0DCE4E29F2CBA11 - -# Email sent directly to teor, verified using relay contact info -# Updated details from atlas based on ticket #20010 -163.172.176.167:80 orport=443 id=230A8B2A8BA861210D9B4BA97745AEC217A94207 -163.172.149.155:80 orport=443 id=0B85617241252517E8ECF2CFC7F4C1A32DCD153F -163.172.149.122:80 orport=443 id=A9406A006D6E7B5DA30F2C6D4E42A338B5E340B2 - -# Email sent directly to teor, verified using relay contact info -204.11.50.131:9030 orport=9001 id=185F2A57B0C4620582602761097D17DB81654F70 - -# Email sent directly to teor, verified using relay contact info -151.236.222.217:44607 orport=9001 id=94D58704C2589C130C9C39ED148BD8EA468DBA54 - -# Email sent directly to teor, verified using relay contact info -185.35.202.221:9030 orport=9001 id=C13B91384CDD52A871E3ECECE4EF74A7AC7DCB08 ipv6=[2a02:ed06::221]:9001 - -# Email sent directly to teor, verified using relay contact info -5.9.151.241:9030 orport=4223 id=9BF04559224F0F1C3C953D641F1744AF0192543A ipv6=[2a01:4f8:190:34f0::2]:4223 - -# Email sent directly to teor, verified using relay contact info -89.40.71.149:8081 orport=8080 id=EC639EDAA5121B47DBDF3D6B01A22E48A8CB6CC7 - -# Email sent directly to teor, verified using relay contact info -92.222.20.130:80 orport=443 id=0639612FF149AA19DF3BCEA147E5B8FED6F3C87C - -# Email sent directly to teor, verified using relay contact info -80.112.155.100:9030 orport=9001 id=53B000310984CD86AF47E5F3CD0BFF184E34B383 ipv6=[2001:470:7b02::38]:9001 - -# Email sent directly to teor, verified using relay contact info -83.212.99.68:80 orport=443 id=DDBB2A38252ADDA53E4492DDF982CA6CC6E10EC0 ipv6=[2001:648:2ffc:1225:a800:bff:fe3d:67b5]:443 - -# Email sent directly to teor, verified using relay contact info -95.130.11.147:9030 orport=443 id=6B697F3FF04C26123466A5C0E5D1F8D91925967A - -# Email sent directly to teor, verified using relay contact info -128.199.55.207:9030 orport=9001 id=BCEF908195805E03E92CCFE669C48738E556B9C5 ipv6=[2a03:b0c0:2:d0::158:3001]:9001 - -# Email sent directly to teor, verified using relay contact info -178.32.216.146:9030 orport=9001 id=17898F9A2EBC7D69DAF87C00A1BD2FABF3C9E1D2 - -# Email sent directly to teor, verified using relay contact info -212.83.40.238:9030 orport=9001 id=F409FA7902FD89270E8DE0D7977EA23BC38E5887 - -# Email sent directly to teor, verified using relay contact info -204.8.156.142:80 orport=443 id=94C4B7B8C50C86A92B6A20107539EE2678CF9A28 - -# Email sent directly to teor, verified using relay contact info -80.240.139.111:80 orport=443 id=DD3BE7382C221F31723C7B294310EF9282B9111B - -# Email sent directly to teor, verified using relay contact info -185.97.32.18:9030 orport=9001 id=04250C3835019B26AA6764E85D836088BE441088 - -# Email sent directly to teor -149.56.45.200:9030 orport=9001 id=FE296180018833AF03A8EACD5894A614623D3F76 ipv6=[2607:5300:201:3000::17d3]:9002 # PiotrTorpotkinOne - -# Email sent directly to teor, verified using relay contact info -81.2.209.10:443 orport=80 id=B6904ADD4C0D10CDA7179E051962350A69A63243 ipv6=[2001:15e8:201:1::d10a]:80 - -# Email sent directly to teor, verified using relay contact info -# IPv6 address unreliable -195.154.164.243:80 orport=443 id=AC66FFA4AB35A59EBBF5BF4C70008BF24D8A7A5C #ipv6=[2001:bc8:399f:f000::1]:993 -138.201.26.2:80 orport=443 id=6D3A3ED5671E4E3F58D4951438B10AE552A5FA0F -81.7.16.182:80 orport=443 id=51E1CF613FD6F9F11FE24743C91D6F9981807D82 ipv6=[2a02:180:1:1::517:10b6]:993 -134.119.36.135:80 orport=443 id=763C9556602BD6207771A7A3D958091D44C43228 ipv6=[2a00:1158:3::2a8]:993 -46.228.199.19:80 orport=443 id=E26AFC5F718E21AC502899B20C653AEFF688B0D2 ipv6=[2001:4ba0:cafe:4a::1]:993 -37.200.98.5:80 orport=443 id=231C2B9C8C31C295C472D031E06964834B745996 ipv6=[2a00:1158:3::11a]:993 -46.23.70.195:80 orport=443 id=C9933B3725239B6FAB5227BA33B30BE7B48BB485 -185.15.244.124:80 orport=443 id=935BABE2564F82016C19AEF63C0C40B5753BA3D2 ipv6=[2001:4ba0:cafe:e35::1]:993 -195.154.116.232:80 orport=443 id=B35C5739C8C5AB72094EB2B05738FD1F8EEF6EBD ipv6=[2001:bc8:399f:200::1]:993 -195.154.121.198:80 orport=443 id=0C77421C890D16B6D201283A2244F43DF5BC89DD ipv6=[2001:bc8:399f:100::1]:993 -37.187.20.59:80 orport=443 id=91D23D8A539B83D2FB56AA67ECD4D75CC093AC55 ipv6=[2001:41d0:a:143b::1]:993 -217.12.208.117:80 orport=443 id=E6E18151300F90C235D3809F90B31330737CEB43 ipv6=[2a00:1ca8:a7::1bb]:993 -81.7.10.251:80 orport=443 id=8073670F8F852971298F8AF2C5B23AE012645901 ipv6=[2a02:180:1:1::517:afb]:993 -46.36.39.50:80 orport=443 id=ED4B0DBA79AEF5521564FA0231455DCFDDE73BB6 ipv6=[2a02:25b0:aaaa:aaaa:8d49:b692:4852:0]:995 -91.194.90.103:80 orport=443 id=75C4495F4D80522CA6F6A3FB349F1B009563F4B7 ipv6=[2a02:c205:3000:5449::1]:993 -163.172.25.118:80 orport=22 id=0CF8F3E6590F45D50B70F2F7DA6605ECA6CD408F -188.138.88.42:80 orport=443 id=70C55A114C0EF3DC5784A4FAEE64388434A3398F -81.7.13.84:80 orport=443 id=0C1E7DD9ED0676C788933F68A9985ED853CA5812 ipv6=[2a02:180:1:1::5b8f:538c]:993 -213.246.56.95:80 orport=443 id=27E6E8E19C46751E7312420723C6162FF3356A4C ipv6=[2a00:c70:1:213:246:56:95:1]:993 -94.198.100.18:80 orport=443 id=BAACCB29197DB833F107E410E2BFAE5009EE7583 -217.12.203.46:80 orport=443 id=6A29FD8C00D573E6C1D47852345B0E5275BA3307 -212.117.180.107:80 orport=443 id=0B454C7EBA58657B91133A587C1BDAEDC6E23142 -217.12.199.190:80 orport=443 id=A37C47B03FF31CA6937D3D68366B157997FE7BCD ipv6=[2a02:27a8:0:2::486]:993 -216.230.230.247:80 orport=443 id=4C7BF55B1BFF47993DFF995A2926C89C81E4F04A -69.30.215.42:80 orport=443 id=510176C07005D47B23E6796F02C93241A29AA0E9 ipv6=[2604:4300:a:2e::2]:993 -89.46.100.162:80 orport=443 id=6B7191639E179965FD694612C9B2C8FB4267B27D -107.181.174.22:80 orport=443 id=5A551BF2E46BF26CC50A983F7435CB749C752553 ipv6=[2607:f7a0:3:4::4e]:993 - -# Email sent directly to teor, verified using relay contact info -212.238.208.48:9030 orport=9001 id=F406219CDD339026D160E53FCA0EF6857C70F109 ipv6=[2001:984:a8fb:1:ba27:ebff:feac:c109]:9001 - -# Email sent directly to teor -176.158.236.102:9030 orport=9001 id=DC163DDEF4B6F0C6BC226F9F6656A5A30C5C5686 # Underworld - -# Email sent directly to teor, verified using relay contact info -91.229.20.27:9030 orport=9001 id=9A0D54D3A6D2E0767596BF1515E6162A75B3293F - -# Email sent directly to teor, verified using relay contact info -80.127.137.19:80 orport=443 id=6EF897645B79B6CB35E853B32506375014DE3621 ipv6=[2001:981:47c1:1::6]:443 - -# Email sent directly to teor -163.172.138.22:80 orport=443 id=16102E458460349EE45C0901DAA6C30094A9BBEA ipv6=[2001:bc8:4400:2100::1:3]:443 # mkultra - -# Email sent directly to teor, verified using relay contact info -97.74.237.196:9030 orport=9001 id=2F0F32AB1E5B943CA7D062C03F18960C86E70D94 - -# Email sent directly to teor, verified using relay contact info -192.187.124.98:9030 orport=9001 id=FD1871854BFC06D7B02F10742073069F0528B5CC - -# Email sent directly to teor, verified using relay contact info -178.62.98.160:9030 orport=9001 id=8B92044763E880996A988831B15B2B0E5AD1544A - -# Email sent directly to teor, verified using relay contact info -163.172.217.50:9030 orport=9001 id=02ECD99ECD596013A8134D46531560816ECC4BE6 - -# Email sent directly to teor, verified using relay contact info -185.100.86.100:80 orport=443 id=0E8C0C8315B66DB5F703804B3889A1DD66C67CE0 -185.100.84.82:80 orport=443 id=7D05A38E39FC5D29AFE6BE487B9B4DC9E635D09E - -# Email sent directly to teor, verified using relay contact info -78.24.75.53:9030 orport=9001 id=DEB73705B2929AE9BE87091607388939332EF123 - -# Email sent directly to teor, verified using relay contact info -46.101.237.246:9030 orport=9001 id=75F1992FD3F403E9C082A5815EB5D12934CDF46C ipv6=[2a03:b0c0:3:d0::208:5001]:9050 -178.62.86.96:9030 orport=9001 id=439D0447772CB107B886F7782DBC201FA26B92D1 ipv6=[2a03:b0c0:1:d0::3cf:7001]:9050 - -# Email sent directly to teor, verified using relay contact info -# Very low bandwidth, stale consensues, excluded to cut down on warnings -#91.233.106.121:80 orport=443 id=896364B7996F5DFBA0E15D1A2E06D0B98B555DD6 - -# Email sent directly to teor, verified using relay contact info -167.114.113.48:9030 orport=403 id=2EC0C66EA700C44670444280AABAB1EC78B722A0 - -# Email sent directly to teor, verified using relay contact info -# Assume details update is permanent -213.141.138.174:9030 orport=9001 id=BD552C165E2ED2887D3F1CCE9CFF155DDA2D86E6 # Schakalium - -# Email sent directly to teor, verified using relay contact info -95.128.43.164:80 orport=443 id=616081EC829593AF4232550DE6FFAA1D75B37A90 ipv6=[2a02:ec0:209:10::4]:443 - -# Email sent directly to teor, verified using relay contact info -166.82.21.200:9030 orport=9029 id=D5C33F3E203728EDF8361EA868B2939CCC43FAFB - -# Email sent directly to teor, verified using relay contact info -91.121.54.8:9030 orport=9001 id=CBEE0F3303C8C50462A12107CA2AE061831931BC - -# Email sent directly to teor, verified using relay contact info -178.217.184.32:8080 orport=443 id=8B7F47AE1A5D954A3E58ACDE0865D09DBA5B738D - -# Email sent directly to teor, verified using relay contact info -85.10.201.47:9030 orport=9001 id=D8B7A3A6542AA54D0946B9DC0257C53B6C376679 ipv6=[2a01:4f8:a0:43eb::beef]:9001 - -# Email sent directly to teor, verified using relay contact info -120.29.217.46:80 orport=443 id=5E853C94AB1F655E9C908924370A0A6707508C62 - -# Email sent directly to teor, verified using relay contact info -37.153.1.10:9030 orport=9001 id=9772EFB535397C942C3AB8804FB35CFFAD012438 - -# Email sent directly to teor, verified using relay contact info -92.222.4.102:9030 orport=9001 id=1A6B8B8272632D8AD38442027F822A367128405C - -# Email sent directly to teor, verified using relay contact info -31.31.78.49:80 orport=443 id=46791D156C9B6C255C2665D4D8393EC7DBAA7798 - -# Email sent directly to teor -192.160.102.169:80 orport=9001 id=C0192FF43E777250084175F4E59AC1BA2290CE38 ipv6=[2620:132:300c:c01d::9]:9002 # manipogo -192.160.102.166:80 orport=9001 id=547DA56F6B88B6C596B3E3086803CDA4F0EF8F21 ipv6=[2620:132:300c:c01d::6]:9002 # chaucer -192.160.102.170:80 orport=9001 id=557ACEC850F54EEE65839F83CACE2B0825BE811E ipv6=[2620:132:300c:c01d::a]:9002 # ogopogo -192.160.102.164:80 orport=9001 id=823AA81E277F366505545522CEDC2F529CE4DC3F ipv6=[2620:132:300c:c01d::4]:9002 # snowfall -192.160.102.165:80 orport=9001 id=C90CA3B7FE01A146B8268D56977DC4A2C024B9EA ipv6=[2620:132:300c:c01d::5]:9002 # cowcat -192.160.102.168:80 orport=9001 id=F6A358DD367B3282D6EF5824C9D45E1A19C7E815 ipv6=[2620:132:300c:c01d::8]:9002 # prawksi - -# Email sent directly to teor, verified using relay contact info -136.243.214.137:80 orport=443 id=B291D30517D23299AD7CEE3E60DFE60D0E3A4664 - -# Email sent directly to teor, verified using relay contact info -192.87.28.28:9030 orport=9001 id=ED2338CAC2711B3E331392E1ED2831219B794024 -192.87.28.82:9030 orport=9001 id=844AE9CAD04325E955E2BE1521563B79FE7094B7 - -# Email sent directly to teor, verified using relay contact info -192.87.28.28:9030 orport=9001 id=ED2338CAC2711B3E331392E1ED2831219B794024 -# same machine as ED2338CAC2711B3E331392E1ED2831219B794024 -192.87.28.82:9030 orport=9001 id=844AE9CAD04325E955E2BE1521563B79FE7094B7 - -# https://twitter.com/kosjoli/status/719507270904758272 -85.10.202.87:9030 orport=9001 id=971AFB23C168DCD8EDA17473C1C452B359DE3A5A -176.9.5.116:9030 orport=9001 id=A1EB8D8F1EE28DB98BBB1EAA3B4BEDD303BAB911 -46.4.111.124:9030 orport=9001 id=D9065F9E57899B3D272AA212317AF61A9B14D204 - -# Email sent directly to teor, verified using relay contact info -185.100.85.61:80 orport=443 id=025B66CEBC070FCB0519D206CF0CF4965C20C96E - -# Email sent directly to teor, verified using relay contact info -108.166.168.158:80 orport=443 id=CDAB3AE06A8C9C6BF817B3B0F1877A4B91465699 - -# Email sent directly to teor, verified using relay contact info -91.219.236.222:80 orport=443 id=20704E7DD51501DC303FA51B738D7B7E61397CF6 - -# Email sent directly to teor, verified using relay contact info -185.14.185.240:9030 orport=443 id=D62FB817B0288085FAC38A6DC8B36DCD85B70260 -192.34.63.137:9030 orport=443 id=ABCB4965F1FEE193602B50A365425105C889D3F8 -128.199.197.16:9030 orport=443 id=DEE5298B3BA18CDE651421CD2DCB34A4A69F224D - -# Email sent directly to teor, verified using relay contact info -185.13.38.75:9030 orport=9001 id=D2A1703758A0FBBA026988B92C2F88BAB59F9361 - -# Email sent directly to teor, verified using relay contact info -128.204.39.106:9030 orport=9001 id=6F0F3C09AF9580F7606B34A7678238B3AF7A57B7 - -# Email sent directly to teor, verified using relay contact info -198.50.191.95:80 orport=443 id=39F096961ED2576975C866D450373A9913AFDC92 - -# Email sent directly to teor, verified using relay contact info -167.114.66.61:9696 orport=443 id=DE6CD5F09DF26076F26321B0BDFBE78ACD935C65 ipv6=[2607:5300:100::78d]:443 - -# Email sent directly to teor, verified using relay contact info -66.111.2.20:9030 orport=9001 id=9A68B85A02318F4E7E87F2828039FBD5D75B0142 -66.111.2.16:9030 orport=9001 id=3F092986E9B87D3FDA09B71FA3A602378285C77A - -# Email sent directly to teor, verified using relay contact info -92.222.38.67:80 orport=443 id=DED6892FF89DBD737BA689698A171B2392EB3E82 - -# Email sent directly to teor, verified using relay contact info -212.47.228.115:9030 orport=443 id=BCA017ACDA48330D02BB70716639ED565493E36E - -# Email sent directly to teor, verified using relay contact info -185.100.84.175:80 orport=443 id=39B59AF4FE54FAD8C5085FA9C15FDF23087250DB - -# Email sent directly to teor, verified using relay contact info -166.70.207.2:9030 orport=9001 id=E3DB2E354B883B59E8DC56B3E7A353DDFD457812 - -# Emails sent directly to teor, verified using relay contact info -69.162.139.9:9030 orport=9001 id=4791FC0692EAB60DF2BCCAFF940B95B74E7654F6 ipv6=[2607:f128:40:1212::45a2:8b09]:9001 - -# Email sent directly to teor, verified using relay contact info -213.239.217.18:1338 orport=1337 id=C37BC191AC389179674578C3E6944E925FE186C2 ipv6=[2a01:4f8:a0:746a:101:1:1:1]:1337 - -# Email sent directly to teor, verified using relay contact info -# Assume details update is permanent -188.40.128.246:9030 orport=9001 id=AD19490C7DBB26D3A68EFC824F67E69B0A96E601 ipv6=[2a01:4f8:221:1ac1:dead:beef:7005:9001]:9001 # sputnik -129.13.131.140:80 orport=443 id=F2DFE5FA1E4CF54F8E761A6D304B9B4EC69BDAE8 ipv6=[2a00:1398:5:f604:cafe:cafe:cafe:9001]:443 # AlleKochenKaffee - -# Email sent directly to teor, verified using relay contact info -88.198.253.13:9030 orport=9001 id=DF924196D69AAE3C00C115A9CCDF7BB62A175310 ipv6=[2a01:4f8:11a:b1f::2]:9001 - -# Email sent directly to teor, verified using relay contact info -185.100.86.128:9030 orport=9001 id=9B31F1F1C1554F9FFB3455911F82E818EF7C7883 -46.36.36.127:9030 orport=9001 id=C80DF89B21FF932DEC0D7821F679B6C79E1449C3 - -# Email sent directly to teor, verified using relay contact info -176.10.104.240:80 orport=443 id=0111BA9B604669E636FFD5B503F382A4B7AD6E80 -176.10.104.240:8080 orport=8443 id=AD86CD1A49573D52A7B6F4A35750F161AAD89C88 -176.10.104.243:8080 orport=8443 id=95DA61AEF23A6C851028C1AA88AD8593F659E60F -94.230.208.147:80 orport=443 id=9AA3FF35E7A549D2337E962333D366E102FE4D50 ipv6=[2a02:418:6017::147]:443 - -# Email sent directly to teor, verified using relay contact info -107.170.101.39:9030 orport=443 id=30973217E70AF00EBE51797FF6D9AA720A902EAA - -# Email sent directly to teor -193.70.112.165:80 orport=443 id=F10BDE279AE71515DDCCCC61DC19AC8765F8A3CC # ParkBenchInd001 - -# Email sent directly to teor -185.220.101.6:10006 orport=20006 id=C08DE49658E5B3CFC6F2A952B453C4B608C9A16A # niftyvolcanorabbit -185.220.101.13:10013 orport=20013 id=71AB4726D830FAE776D74AEF790CF04D8E0151B4 # niftycottontail -185.220.101.5:10005 orport=20005 id=1084200B44021D308EA4253F256794671B1D099A # niftyhedgehog -185.220.101.9:10009 orport=20009 id=14877C6384A9E793F422C8D1DDA447CACA4F7C4B # niftywoodmouse -185.220.101.8:10008 orport=20008 id=24E91955D969AEA1D80413C64FE106FAE7FD2EA9 # niftymouse -185.220.101.1:10001 orport=20001 id=28F4F392F8F19E3FBDE09616D9DB8143A1E2DDD3 # niftycottonmouse -185.220.101.21:10021 orport=20021 id=348B89013EDDD99E4755951D1EC284D9FED71226 # niftysquirrel -185.220.101.10:10010 orport=20010 id=4031460683AE9E0512D3620C2758D98758AC6C93 # niftyeuropeanrabbit -185.220.101.34:10034 orport=20034 id=47C42E2094EE482E7C9B586B10BABFB67557030B # niftyquokka -185.220.101.18:10018 orport=20018 id=5D5006E4992F2F97DF4F8B926C3688870EB52BD8 # niftyplagiodontia -185.220.101.28:10028 orport=20028 id=609E598FB6A00BCF7872906B602B705B64541C50 # niftychipmunk -185.220.101.20:10020 orport=20020 id=619349D82424C601CAEB94161A4CF778993DAEE7 # niftytucotuco -185.220.101.17:10017 orport=20017 id=644DECC5A1879C0FE23DE927DD7049F58BBDF349 # niftyhutia -185.220.101.0:10000 orport=20000 id=6E94866ED8CA098BACDFD36D4E8E2B459B8A734E # niftybeaver -185.220.101.30:10030 orport=20030 id=71CFDEB4D9E00CCC3E31EC4E8A29E109BBC1FB36 # niftypedetidae -185.220.101.29:10029 orport=20029 id=7DC52AE6667A30536BA2383CD102CFC24F20AD71 # niftyllipika -185.220.101.41:10041 orport=20041 id=7E281CD2C315C4F7A84BC7C8721C3BC974DDBFA3 # niftyporcupine -185.220.101.25:10025 orport=20025 id=8EE0534532EA31AA5172B1892F53B2F25C76EB02 # niftyjerboa -185.220.101.33:10033 orport=20033 id=906DCB390F2BA987AE258D745E60BAAABAD31DE8 # niftyquokka -185.220.101.26:10026 orport=20026 id=92A6085EABAADD928B6F8E871540A1A41CBC08BA # niftypedetes -185.220.101.40:10040 orport=20040 id=9A857254F379194D1CD76F4A79A20D2051BEDA3F # niftynutria -185.220.101.42:10042 orport=20042 id=9B816A5B3EB20B8E4E9B9D1FBA299BD3F40F0320 # niftypygmyjerboa -185.220.101.2:10002 orport=20002 id=B740BCECC4A9569232CDD45C0E1330BA0D030D33 # niftybunny -185.220.101.32:10032 orport=20032 id=B771AA877687F88E6F1CA5354756DF6C8A7B6B24 # niftypika -185.220.101.12:10012 orport=20012 id=BC82F2190DE2E97DE65F49B4A95572374BDC0789 # niftycapybara -185.220.101.22:10022 orport=20022 id=CA37CD46799449D83B6B98B8C22C649906307888 # niftyjackrabbit -185.220.101.4:10004 orport=20004 id=CDA2EA326E2272C57ACB26773D7252C211795B78 # niftygerbil -185.220.101.14:10014 orport=20014 id=E7EBA5D8A4E09684D11A1DF24F75362817333768 # niftyhare -185.220.101.16:10016 orport=20016 id=EC1997D51892E4607C68E800549A1E7E4694005A # niftyguineapig -185.220.101.24:10024 orport=20024 id=FDA70EC93DB01E3CB418CB6943B0C68464B18B4C # niftyrat - -# Email sent directly to teor, verified using relay contact info -198.232.165.2:9030 orport=9001 id=30C19B81981F450C402306E2E7CFB6C3F79CB6B2 - -# Emails sent directly to teor, verified using relay contact info -51.254.101.242:9002 orport=9001 id=4CC9CC9195EC38645B699A33307058624F660CCF - -# Emails sent directly to teor, verified using relay contact info -# Updated IP https://trac.torproject.org/projects/tor/ticket/24805#comment:16 -94.130.186.5:80 orport=443 id=6A7551EEE18F78A9813096E82BF84F740D32B911 - -# Email sent directly to teor, verified using relay contact info -173.255.245.116:9030 orport=9001 id=91E4015E1F82DAF0121D62267E54A1F661AB6DC7 - -# Email sent directly to teor, verified using relay contact info -62.216.5.120:9030 orport=9001 id=D032D4D617140D6B828FC7C4334860E45E414FBE - -# Email sent directly to teor, verified using relay contact info -51.254.136.195:80 orport=443 id=7BB70F8585DFC27E75D692970C0EEB0F22983A63 - -# Email sent directly to teor, verified using relay contact info -5.196.88.122:9030 orport=9001 id=0C2C599AFCB26F5CFC2C7592435924C1D63D9484 ipv6=[2001:41d0:a:fb7a::1]:9001 - -# Email sent directly to teor, verified using relay contact info -5.9.158.75:80 orport=443 id=1AF72E8906E6C49481A791A6F8F84F8DFEBBB2BA ipv6=[2a01:4f8:190:514a::2]:443 -5.9.158.75:9030 orport=9001 id=D11D11877769B9E617537B4B46BFB92B443DE33D ipv6=[2a01:4f8:190:514a::2]:9001 - -# Email sent directly to teor, verified using relay contact info -46.101.169.151:9030 orport=9001 id=D760C5B436E42F93D77EF2D969157EEA14F9B39C ipv6=[2a03:b0c0:3:d0::74f:a001]:9001 - -# Email sent directly to teor, verified using relay contact info -199.249.223.81:80 orport=443 id=F7447E99EB5CBD4D5EB913EE0E35AC642B5C1EF3 -199.249.223.79:80 orport=443 id=D33292FEDE24DD40F2385283E55C87F85C0943B6 -199.249.223.78:80 orport=443 id=EC15DB62D9101481F364DE52EB8313C838BDDC29 -199.249.223.77:80 orport=443 id=CC4A3AE960E3617F49BF9887B79186C14CBA6813 -199.249.223.76:80 orport=443 id=43209F6D50C657A56FE79AF01CA69F9EF19BD338 -199.249.223.75:80 orport=443 id=60D3667F56AEC5C69CF7E8F557DB21DDF6C36060 -199.249.223.74:80 orport=443 id=5F4CD12099AF20FAF9ADFDCEC65316A376D0201C -199.249.223.73:80 orport=443 id=5649CB2158DA94FB747415F26628BEC07FA57616 -199.249.223.72:80 orport=443 id=B028707969D8ED84E6DEA597A884F78AAD471971 -199.249.223.71:80 orport=443 id=B6320E44A230302C7BF9319E67597A9B87882241 -199.249.223.60:80 orport=443 id=B7047FBDE9C53C39011CA84E5CB2A8E3543066D0 -199.249.223.61:80 orport=443 id=40E7D6CE5085E4CDDA31D51A29D1457EB53F12AD -199.249.223.62:80 orport=443 id=0077BCBA7244DB3E6A5ED2746E86170066684887 -199.249.223.63:80 orport=443 id=1DB25DF59DAA01B5BE3D3CEB8AFED115940EBE8B -199.249.223.64:80 orport=443 id=9F2856F6D2B89AD4EF6D5723FAB167DB5A53519A -199.249.223.65:80 orport=443 id=9D21F034C3BFF4E7737D08CF775DC1745706801F -199.249.223.66:80 orport=443 id=C5A53BCC174EF8FD0DCB223E4AA929FA557DEDB2 -199.249.223.67:80 orport=443 id=155D6F57425F16C0624D77777641E4EB1B47C6F0 -199.249.223.68:80 orport=443 id=DF20497E487A979995D851A5BCEC313DF7E5BC51 -199.249.223.69:80 orport=443 id=7FA8E7E44F1392A4E40FFC3B69DB3B00091B7FD3 - -# https://lists.torproject.org/pipermail/tor-relays/2016-December/011114.html -86.105.212.130:9030 orport=443 id=9C900A7F6F5DD034CFFD192DAEC9CCAA813DB022 - -# Email sent directly to teor, verified using relay contact info -178.33.183.251:80 orport=443 id=DD823AFB415380A802DCAEB9461AE637604107FB ipv6=[2001:41d0:2:a683::251]:443 - -# Email sent directly to teor, verified using relay contact info -31.185.104.19:80 orport=443 id=9EAD5B2D3DBD96DBC80DCE423B0C345E920A758D -# same machine as 9EAD5B2D3DBD96DBC80DCE423B0C345E920A758D -31.185.104.20:80 orport=443 id=ADB2C26629643DBB9F8FE0096E7D16F9414B4F8D -31.185.104.21:80 orport=443 id=C2AAB088555850FC434E68943F551072042B85F1 -31.185.104.22:80 orport=443 id=5BA3A52760A0EABF7E7C3ED3048A77328FF0F148 - -# Email sent directly to teor, verified using relay contact info -185.34.60.114:80 orport=443 id=7F7A695DF6F2B8640A70B6ADD01105BC2EBC5135 - -# https://lists.torproject.org/pipermail/tor-relays/2017-December/013939.html -94.142.242.84:80 orport=443 id=AA0D167E03E298F9A8CD50F448B81FBD7FA80D56 ipv6=[2a02:898:24:84::1]:443 # rejozenger - -# Email sent directly to teor, verified using relay contact info -185.129.62.62:9030 orport=9001 id=ACDD9E85A05B127BA010466C13C8C47212E8A38F ipv6=[2a06:d380:0:3700::62]:9001 - -# Email sent directly to teor, verified using relay contact info -# The e84 part of the IPv6 address does not have a leading 0 in the consensus -81.30.158.213:9030 orport=9001 id=789EA6C9AE9ADDD8760903171CFA9AC5741B0C70 ipv6=[2001:4ba0:cafe:e84::1]:9001 - -# https://lists.torproject.org/pipermail/tor-relays/2016-December/011209.html -5.9.159.14:9030 orport=9001 id=0F100F60C7A63BED90216052324D29B08CFCF797 - -# Email sent directly to teor, verified using relay contact info -45.62.255.25:80 orport=443 id=3473ED788D9E63361D1572B7E82EC54338953D2A - -# Email sent directly to teor, verified using relay contact info -217.79.179.177:9030 orport=9001 id=3E53D3979DB07EFD736661C934A1DED14127B684 ipv6=[2001:4ba0:fff9:131:6c4f::90d3]:9001 - -# Email sent directly to teor, verified using relay contact info -212.47.244.38:8080 orport=443 id=E81EF60A73B3809F8964F73766B01BAA0A171E20 -163.172.157.213:8080 orport=443 id=4623A9EC53BFD83155929E56D6F7B55B5E718C24 -163.172.139.104:8080 orport=443 id=68F175CCABE727AA2D2309BCD8789499CEE36ED7 - -# Email sent directly to teor, verified using relay contact info -163.172.223.200:80 orport=443 id=998BF3ED7F70E33D1C307247B9626D9E7573C438 -195.154.122.54:80 orport=443 id=64E99CB34C595A02A3165484BD1215E7389322C6 - -# Email sent directly to teor, verified using relay contact info -# Email sent directly to Phoul -185.100.86.128:9030 orport=9001 id=9B31F1F1C1554F9FFB3455911F82E818EF7C7883 -185.100.85.101:9030 orport=9001 id=4061C553CA88021B8302F0814365070AAE617270 - -# Email sent directly to teor, verified using relay contact info -89.163.247.43:9030 orport=9001 id=BC7ACFAC04854C77167C7D66B7E471314ED8C410 ipv6=[2001:4ba0:fff7:25::5]:9001 - -# Email sent directly to teor, verified using relay contact info -95.85.8.226:80 orport=443 id=1211AC1BBB8A1AF7CBA86BCE8689AA3146B86423 - -# Email sent directly to teor, verified using relay contact info -85.214.151.72:9030 orport=9001 id=722D365140C8C52DBB3C9FF6986E3CEFFE2BA812 - -# email sent directly to teor -72.52.75.27:9030 orport=9001 id=8567AD0A6369ED08527A8A8533A5162AC00F7678 # piecoopdotnet - -# Email sent directly to teor, verified using relay contact info -5.9.146.203:80 orport=443 id=1F45542A24A61BF9408F1C05E0DCE4E29F2CBA11 -5.9.159.14:9030 orport=9001 id=0F100F60C7A63BED90216052324D29B08CFCF797 - -# Email sent directly to teor, verified using relay contact info -# Assume details update is permanent -5.9.147.226:9030 orport=9001 id=B0553175AADB0501E5A61FC61CEA3970BE130FF2 ipv6=[2a01:4f8:190:30e1::2]:9001 # zwiubel - -# https://trac.torproject.org/projects/tor/ticket/22527#comment:1 -199.184.246.250:80 orport=443 id=1F6ABD086F40B890A33C93CC4606EE68B31C9556 ipv6=[2620:124:1009:1::171]:443 - -# https://trac.torproject.org/projects/tor/ticket/24695 -163.172.53.84:143 orport=21 id=1C90D3AEADFF3BCD079810632C8B85637924A58E ipv6=[2001:bc8:24f8::]:21 # Multivac - -# Email sent directly to teor -54.36.237.163:80 orport=443 id=DB2682153AC0CCAECD2BD1E9EBE99C6815807A1E # GermanCraft2 - -# Email sent directly to teor -62.138.7.171:9030 orport=9001 id=9844B981A80B3E4B50897098E2D65167E6AEF127 # 0x3d004 -62.138.7.171:8030 orport=8001 id=9285B22F7953D7874604EEE2B470609AD81C74E9 # 0x3d005 -91.121.23.100:9030 orport=9001 id=3711E80B5B04494C971FB0459D4209AB7F2EA799 # 0x3d002 -91.121.23.100:8030 orport=8001 id=CFBBA0D858F02E40B1432A65F6D13C9BDFE7A46B # 0x3d001 -51.15.13.245:9030 orport=9001 id=CED527EAC230E7B56E5B363F839671829C3BA01B # 0x3d006 -51.15.13.245:8030 orport=8001 id=8EBB8D1CF48FE2AB95C451DA8F10DB6235F40F8A # 0x3d007 - -# Email sent directly to teor -104.192.5.248:9030 orport=9001 id=BF735F669481EE1CCC348F0731551C933D1E2278 # Freeway11 - -# Email sent directly to teor -# https://lists.torproject.org/pipermail/tor-relays/2017-December/013961.html -178.17.174.14:9030 orport=9001 id=B06F093A3D4DFAD3E923F4F28A74901BD4F74EB1 # TorExitMoldova -178.17.170.156:9030 orport=9001 id=41C59606AFE1D1AA6EC6EF6719690B856F0B6587 # TorExitMoldova2 - -# Email sent directly to teor -163.172.221.44:59030 orport=59001 id=164604F5C86FC8CC9C0288BD9C02311958427597 # altego - -# Email sent directly to teor -46.38.237.221:9030 orport=9001 id=D30E9D4D639068611D6D96861C95C2099140B805 # mine - -# https://lists.torproject.org/pipermail/tor-relays/2017-December/013911.html -# https://lists.torproject.org/pipermail/tor-relays/2017-December/013912.html -199.249.223.62:80 orport=443 id=0077BCBA7244DB3E6A5ED2746E86170066684887 # Quintex13 -199.249.224.45:80 orport=443 id=041646640AB306EA74B001966E86169B04CC88D2 # QuintexAirVPN26 -199.249.223.67:80 orport=443 id=155D6F57425F16C0624D77777641E4EB1B47C6F0 # Quintex18 -199.249.223.45:80 orport=443 id=1AE949967F82BBE7534A3D6BA77A7EBE1CED4369 # Quintex36 -199.249.223.63:80 orport=443 id=1DB25DF59DAA01B5BE3D3CEB8AFED115940EBE8B # Quintex14 -199.249.224.63:80 orport=443 id=1E5136DDC52FAE1219208F0A6BADB0BA62587EE6 # Quintex43 -199.249.224.46:80 orport=443 id=2ED4D25766973713EB8C56A290BF07E06B85BF12 # QuintexAirVPN27 -199.249.223.42:80 orport=443 id=3687FEC7E73F61AC66F7AE251E7DEE6BBD8C0252 # Quintex33 -199.249.223.49:80 orport=443 id=36D68478366CB8627866757EBCE7FB3C17FC1CB8 # Quintex40 -199.249.224.49:80 orport=443 id=3CA0D15567024D2E0B557DC0CF3E962B37999A79 # QuintexAirVPN30 -199.249.223.61:80 orport=443 id=40E7D6CE5085E4CDDA31D51A29D1457EB53F12AD # Quintex12 -199.249.223.76:80 orport=443 id=43209F6D50C657A56FE79AF01CA69F9EF19BD338 # QuintexAirVPN5 -199.249.224.41:80 orport=443 id=54A4820B46E65509BF3E2B892E66930A41759DE9 # QuintexAirVPN22 -199.249.223.73:80 orport=443 id=5649CB2158DA94FB747415F26628BEC07FA57616 # QuintexAirVPN8 -199.249.223.74:80 orport=443 id=5F4CD12099AF20FAF9ADFDCEC65316A376D0201C # QuintexAirVPN7 -199.249.223.75:80 orport=443 id=60D3667F56AEC5C69CF7E8F557DB21DDF6C36060 # QuintexAirVPN6 -199.249.223.46:80 orport=443 id=66E19E8C4773086F669A1E06A3F8C23B6C079129 # Quintex37 -199.249.224.65:80 orport=443 id=764BF8A03868F84C8F323C1A676AA254B80DC3BF # Quintex45 -199.249.223.48:80 orport=443 id=7A3DD280EA4CD4DD16EF8C67B93D9BDE184D1A81 # Quintex39 -199.249.224.68:80 orport=443 id=7E6E9A6FDDB8DC7C92F0CFCC3CBE76C29F061799 # Quintex48 -199.249.223.69:80 orport=443 id=7FA8E7E44F1392A4E40FFC3B69DB3B00091B7FD3 # Quintex20 -199.249.223.44:80 orport=443 id=8B80169BEF71450FC4069A190853523B7AEA45E1 # Quintex35 -199.249.224.60:80 orport=443 id=9314BD9503B9014261A65C221D77E57389DBCCC1 # Quintex50 -199.249.224.40:80 orport=443 id=9C1E7D92115D431385B8CAEA6A7C15FB89CE236B # QuintexAirVPN21 -199.249.223.65:80 orport=443 id=9D21F034C3BFF4E7737D08CF775DC1745706801F # Quintex16 -199.249.224.67:80 orport=443 id=9E2D7C6981269404AA1970B53891701A20424EF8 # Quintex47 -199.249.223.64:80 orport=443 id=9F2856F6D2B89AD4EF6D5723FAB167DB5A53519A # Quintex15 -199.249.224.48:80 orport=443 id=A0DB820FEC87C0405F7BF05DEE5E4ADED2BB9904 # QuintexAirVPN29 -199.249.224.64:80 orport=443 id=A4A393FEF48640961AACE92D041934B55348CEF9 # Quintex44 -199.249.223.72:80 orport=443 id=B028707969D8ED84E6DEA597A884F78AAD471971 # QuintexAirVPN9 -199.249.223.40:80 orport=443 id=B0CD9F9B5B60651ADC5919C0F1EAA87DBA1D9249 # Quintex31 -199.249.224.61:80 orport=443 id=B2197C23A4FF5D1C49EE45BA7688BA8BCCD89A0B # Quintex41 -199.249.223.71:80 orport=443 id=B6320E44A230302C7BF9319E67597A9B87882241 # QuintexAirVPN10 -199.249.223.60:80 orport=443 id=B7047FBDE9C53C39011CA84E5CB2A8E3543066D0 # Quintex11 -199.249.224.66:80 orport=443 id=C78AFFEEE320EA0F860961763E613FD2FAC855F5 # Quintex46 -199.249.224.44:80 orport=443 id=CB7C0D841FE376EF43F7845FF201B0290C0A239E # QuintexAirVPN25 -199.249.223.47:80 orport=443 id=CC14C97F1D23EE97766828FC8ED8582E21E11665 # Quintex38 -199.249.223.77:80 orport=443 id=CC4A3AE960E3617F49BF9887B79186C14CBA6813 # QuintexAirVPN4 -199.249.223.41:80 orport=443 id=D25210CE07C49F2A4F2BC7A506EB0F5EA7F5E2C2 # Quintex32 -199.249.223.79:80 orport=443 id=D33292FEDE24DD40F2385283E55C87F85C0943B6 # QuintexAirVPN2 -199.249.224.47:80 orport=443 id=D6FF2697CEA5C0C7DA84797C2E71163814FC2466 # QuintexAirVPN28 -199.249.223.68:80 orport=443 id=DF20497E487A979995D851A5BCEC313DF7E5BC51 # Quintex19 -199.249.223.43:80 orport=443 id=E480D577F58E782A5BC4FA6F49A6650E9389302F # Quintex34 -199.249.224.69:80 orport=443 id=EABC2DD0D47B5DB11F2D37EB3C60C2A4D91C10F2 # Quintex49 -199.249.223.78:80 orport=443 id=EC15DB62D9101481F364DE52EB8313C838BDDC29 # QuintexAirVPN3 -199.249.224.42:80 orport=443 id=F21DE9C7DE31601D9716781E17E24380887883D1 # QuintexAirVPN23 -199.249.223.81:80 orport=443 id=F7447E99EB5CBD4D5EB913EE0E35AC642B5C1EF3 # QuintexAirVPN1 -199.249.224.43:80 orport=443 id=FDD700C791CC6BB0AC1C2099A82CBC367AD4B764 # QuintexAirVPN24 -199.249.224.62:80 orport=443 id=FE00A3A835680E67FBBC895A724E2657BB253E97 # Quintex42 -199.249.223.66:80 orport=443 id=C5A53BCC174EF8FD0DCB223E4AA929FA557DEDB2 # Quintex17 - -# https://lists.torproject.org/pipermail/tor-relays/2017-December/013914.html -# https://lists.torproject.org/pipermail/tor-relays/2018-January/014063.html -5.196.23.64:9030 orport=9001 id=775B0FAFDE71AADC23FFC8782B7BEB1D5A92733E # Aerodynamik01 -217.182.75.181:9030 orport=9001 id=EFEACD781604EB80FBC025EDEDEA2D523AEAAA2F # Aerodynamik02 -193.70.43.76:9030 orport=9001 id=484A10BA2B8D48A5F0216674C8DD50EF27BC32F3 # Aerodynamik03 -149.56.141.138:9030 orport=9001 id=1938EBACBB1A7BFA888D9623C90061130E63BB3F # Aerodynamik04 -54.37.73.111:9030 orport=9001 id=92412EA1B9AA887D462B51D816777002F4D58907 # Aerodynamik05 -54.37.17.235:9030 orport=9001 id=360CBA08D1E24F513162047BDB54A1015E531534 # Aerodynamik06 - -# https://lists.torproject.org/pipermail/tor-relays/2017-December/013917.html -104.200.20.46:80 orport=9001 id=78E2BE744A53631B4AAB781468E94C52AB73968B # bynumlawtor - -# https://lists.torproject.org/pipermail/tor-relays/2017-December/013929.html -139.99.130.178:80 orport=443 id=867B95CACD64653FEEC4D2CEFC5C49B4620307A7 # coffswifi2 - -# https://lists.torproject.org/pipermail/tor-relays/2017-December/013946.html -172.98.193.43:80 orport=443 id=5E56738E7F97AA81DEEF59AF28494293DFBFCCDF # Backplane - -# Email sent directly to teor -62.210.254.132:80 orport=443 id=8456DFA94161CDD99E480C2A2992C366C6564410 # turingmachine - -# https://lists.torproject.org/pipermail/tor-relays/2017-December/013960.html -51.15.205.214:9030 orport=9001 id=8B6556601612F1E2AFCE2A12FFFAF8482A76DD1F ipv6=[2001:bc8:4400:2500::5:b07]:9001 # titania1 -51.15.205.214:9031 orport=9002 id=5E363D72488276160D062DDD2DFA25CFEBAF5EA9 ipv6=[2001:bc8:4400:2500::5:b07]:9002 # titania2 - -# https://lists.torproject.org/pipermail/tor-relays/2017-December/014000.html -24.117.231.229:34175 orport=45117 id=CE24412AD69444954B4015E293AE53DDDAFEA3D6 # Anosognosia - -# https://lists.torproject.org/pipermail/tor-relays/2018-January/014012.html -128.31.0.13:80 orport=443 id=A53C46F5B157DD83366D45A8E99A244934A14C46 # csailmitexit - -# Email sent directly to teor -82.247.103.117:110 orport=995 id=C9B3C1661A9577BA24C1C2C6123918921A495509 # Casper01 -109.238.2.79:110 orport=995 id=7520892E3DD133D0B0464D01A158B54B8E2A8B75 # Casper02 -51.15.179.153:110 orport=995 id=BB60F5BA113A0B8B44B7B37DE3567FE561E92F78 # Casper04 - -# Email sent directly to teor -80.127.107.179:80 orport=443 id=BC6B2E2F62ACC5EDECBABE64DA1E48F84DD98B78 ipv6=[2001:981:4a22:c::6]:443 # TVISION02 - -# https://lists.torproject.org/pipermail/tor-relays/2018-January/014020.html -37.120.174.249:80 orport=443 id=11DF0017A43AF1F08825CD5D973297F81AB00FF3 ipv6=[2a03:4000:6:724c:df98:15f9:b34d:443]:443 # gGDHjdcC6zAlM8k08lX - -# These fallbacks opted-in in previous releases, then changed their details, -# and so we blacklisted them. Now we want to whitelist changes. -# Assume details update is permanent -85.230.184.93:9030 orport=443 id=855BC2DABE24C861CD887DB9B2E950424B49FC34 # Logforme -176.31.180.157:143 orport=22 id=E781F4EC69671B3F1864AE2753E0890351506329 ipv6=[2001:41d0:8:eb9d::1]:22 # armbrust - -# https://lists.torproject.org/pipermail/tor-relays/2018-January/014024.html -82.161.212.209:9030 orport=9001 id=4E8CE6F5651E7342C1E7E5ED031E82078134FB0D ipv6=[2001:980:d7ed:1:ff:b0ff:fe00:d0b]:9001 # ymkeo - -# https://lists.torproject.org/pipermail/tor-relays/2018-January/014055.html -37.157.255.35:9030 orport=9090 id=361D33C96D0F161275EE67E2C91EE10B276E778B # cxx4freedom - -# https://lists.torproject.org/pipermail/tor-relays/2018-January/014064.html -87.118.122.120:80 orport=443 id=A2A6616723B511D8E068BB71705191763191F6B2 # otheontelth - -# https://lists.torproject.org/pipermail/tor-relays/2018-January/014069.html -185.100.86.182:9030 orport=8080 id=E51620B90DCB310138ED89EDEDD0A5C361AAE24E # NormalCitizen - -# https://lists.torproject.org/pipermail/tor-relays/2018-January/014267.html -51.15.72.211:80 orport=9001 id=D122094E396DF8BA560843E7B983B0EA649B7DF9 ipv6=[2001:bc8:4700:2300::1b:f09]:9001 # gjtorrelay - -# Email sent directly to Phoul -185.34.33.2:9265 orport=31415 id=D71B1CA1C9DC7E8CA64158E106AD770A21160FEE # lqdn - -# Email sent directly to Phoul -78.156.110.135:9091 orport=9090 id=F48FD1AED068496D51D1384BC7497C04E4985DA6 # SkynetC2 - -# Email sent directly to Phoul -5.200.21.144:80 orport=443 id=0C039F35C2E40DCB71CD8A07E97C7FD7787D42D6 # libel -64.79.152.132:80 orport=443 id=375DCBB2DBD94E5263BC0C015F0C9E756669617E # ebola - -# https://lists.torproject.org/pipermail/tor-relays/2018-June/015524.html -132.248.241.5:9030 orport=9001 id=4661DE96D3F8E923994B05218F23760C8D7935A4 - -# https://lists.torproject.org/pipermail/tor-relays/2018-June/015522.html -96.253.78.108:80 orport=442 id=924B24AFA7F075D059E8EEB284CC400B33D3D036 - -# Email sent directly to Phoul -163.172.218.10:9030 orport=9001 id=78809B6C50CB6491DB3A72C60EC39DC85BF72D1F ipv6=[2001:bc8:3f23:1100::1]:9001 -163.172.218.10:9130 orport=9101 id=B247BA9E0AEA93E6D7BF4080CFBB964034AF2B28 ipv6=[2001:bc8:3f23:1100::1]:9101 - -# Email sent directly to Phoul -158.255.212.178:8080 orport=8443 id=D941D380E5228E7B4D372AF4D484629A96DC48B9 ipv6=[2a03:f80:ed15:158:255:212:178:2]:8443 - -# Email sent directly to Phoul -45.79.108.130:9030 orport=9001 id=AEDAC7081AE14B8D241ECF0FF17A2858AB4383D0 ipv6=[2600:3c01:e000:131::8000:0]:9001 - -# Email sent directly to Phoul -51.254.147.57:80 orport=443 id=EB80A8D52F07238B576C42CEAB98ADD084EE075E -217.182.51.248:80 orport=443 id=D6BA940D3255AB40DC5EE5B0B285FA143E1F9865 - -# https://lists.torproject.org/pipermail/tor-relays/2018-June/015541.html -195.191.81.7:9030 orport=9001 id=41A3C16269C7B63DB6EB741DBDDB4E1F586B1592 ipv6=[2a00:1908:fffc:ffff:c0a6:ccff:fe62:e1a1]:9001 -51.254.96.208:9030 orport=9001 id=8101421BEFCCF4C271D5483C5AABCAAD245BBB9D ipv6=[2001:41d0:401:3100::30dc]:9001 -163.172.154.162:9030 orport=9001 id=F741E5124CB12700DA946B78C9B2DD175D6CD2A1 ipv6=[2001:bc8:4400:2100::17:419]:9001 -51.15.78.0:9030 orport=9001 id=15BE17C99FACE24470D40AF782D6A9C692AB36D6 ipv6=[2001:bc8:4700:2300::16:c0b]:9001 -54.37.139.118:9030 orport=9001 id=90A5D1355C4B5840E950EB61E673863A6AE3ACA1 ipv6=[2001:41d0:601:1100::1b8]:9001 -51.38.65.160:9030 orport=9001 id=3CB4193EF4E239FCEDC4DC43468E0B0D6B67ACC3 ipv6=[2001:41d0:801:2000::f6e]:9001 - -# Email sent directly to Phoul -54.37.138.138:8080 orport=993 id=1576BE143D8727745BB2BCDDF183291B3C3EFEFC - -# Email sent directly to Phoul -67.215.255.140:9030 orport=9001 id=23917BB3F3994BC61F0C9D7AD19B069F9E150D26 - -# Email sent directly to Phoul -195.154.105.170:9030 orport=9001 id=E947C029087FA1C3499BEF5D4372947C51223D8F - -# Email sent directly to Phoul -23.129.64.101:80 orport=443 id=2EB20285FE55927B7AECC47BB94F22534FBC3941 ipv6=[2620:18c:0:1001::101]:443 -23.129.64.102:80 orport=443 id=CA9739E2805A3CD73CF75BBCB6785C32394240E3 ipv6=[2620:18c:0:1001::102]:443 -23.129.64.103:80 orport=443 id=8ED84B53BD9556CCBB036073A1AD508EC27CBE52 ipv6=[2620:18c:0:1001::103]:443 - -# Email sent directly to Phoul -37.139.8.104:9030 orport=9001 id=7088D485934E8A403B81531F8C90BDC75FA43C98 ipv6=[2a03:b0c0:0:1010::24c:1001]:9001 - -# Email sent directly to Phoul -178.254.7.88:9030 orpport=9001 id=85A885433E50B1874F11CEC9BE98451E24660976 - -# https://lists.torproject.org/pipermail/tor-relays/2018-August/015869.html -5.45.111.149:80 orport=443 id=D405FCCF06ADEDF898DF2F29C9348DCB623031BA ipv6=[2a03:4000:6:2388:df98:15f9:b34d:443]:443 - -# https://trac.torproject.org/projects/tor/ticket/27297 -37.252.185.182:9030 orport=8080 id=113143469021882C3A4B82F084F8125B08EE471E ipv6=[2a00:63c1:a:182::2]:8080 - -# Email sent directly to Phoul -139.99.130.178:80 orport=443 id=867B95CACD64653FEEC4D2CEFC5C49B4620307A7 - -# Email sent directly to Phoul -104.131.11.214:9030 orport=8080 id=32828476F4F84E15C42B4C360A5CD8DE4C3C2BE7 - -# Email sent directly to Phoul / Teor -178.175.139.122:80 orport=443 id=490FB3FAAF8837407D94CA7E1DEF025DEF0F3516 ipv6=[2a00:1dc0:3002::3]:443 - -# Email sent directly to Phoul -192.42.116.16:80 orport=443 id=81B75D534F91BFB7C57AB67DA10BCEF622582AE8 - -# https://lists.torproject.org/pipermail/tor-relays/2018-November/016610.html -24.117.194.80:80 orport=443 id=B6C4C9A43658F686F8892CA5666717532F72979C diff --git a/scripts/maint/generateFallbackDirLine.py b/scripts/maint/generateFallbackDirLine.py deleted file mode 100755 index b856c938bf..0000000000 --- a/scripts/maint/generateFallbackDirLine.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python - -# Generate a fallback directory whitelist/blacklist line for every fingerprint -# passed as an argument. -# -# Usage: -# generateFallbackDirLine.py fingerprint ... - -import sys -import urllib2 - -import stem.descriptor.remote -import stem.util.tor_tools - -if len(sys.argv) <= 1: - print('Usage: %s fingerprint ...' % sys.argv[0]) - sys.exit(1) - -for fingerprint in sys.argv[1:]: - if not stem.util.tor_tools.is_valid_fingerprint(fingerprint): - print("'%s' isn't a valid relay fingerprint" % fingerprint) - sys.exit(1) - - try: - desc = stem.descriptor.remote.get_server_descriptors(fingerprint).run()[0] - except urllib2.HTTPError as exc: - if exc.code == 404: - print('# %s not found in recent descriptors' % fingerprint) - continue - else: - raise - - if not desc.dir_port: - print("# %s needs a DirPort" % fingerprint) - else: - ipv6_addresses = [(address, port) for address, port, is_ipv6 in desc.or_addresses if is_ipv6] - ipv6_field = ' ipv6=[%s]:%s' % ipv6_addresses[0] if ipv6_addresses else '' - print('%s:%s orport=%s id=%s%s # %s' % (desc.address, desc.dir_port, desc.or_port, fingerprint, ipv6_field, desc.nickname)) diff --git a/scripts/maint/lookupFallbackDirContact.py b/scripts/maint/lookupFallbackDirContact.py deleted file mode 100755 index 14c53d1282..0000000000 --- a/scripts/maint/lookupFallbackDirContact.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python - -# Lookup fallback directory contact lines for every fingerprint passed as an -# argument. -# -# Usage: -# lookupFallbackDirContact.py fingerprint ... - -import sys - -import stem.descriptor.remote as remote - -if len(sys.argv) <= 1: - print "Usage: {} fingerprint ...".format(sys.argv[0]) - sys.exit(-1) - -# we need descriptors, because the consensus does not have contact infos -descriptor_list = remote.get_server_descriptors(fingerprints=sys.argv[1:]).run() - -descriptor_list_fingerprints = [] -for d in descriptor_list: - assert d.fingerprint in sys.argv[1:] - descriptor_list_fingerprints.append(d.fingerprint) - print "{} {}".format(d.fingerprint, d.contact) - -for fingerprint in sys.argv[1:]: - if fingerprint not in descriptor_list_fingerprints: - print "{} not found in current descriptors".format(fingerprint) diff --git a/scripts/maint/updateFallbackDirs.py b/scripts/maint/updateFallbackDirs.py deleted file mode 100755 index 930a0a7275..0000000000 --- a/scripts/maint/updateFallbackDirs.py +++ /dev/null @@ -1,2383 +0,0 @@ -#!/usr/bin/env python - -# Usage: -# -# Regenerate the list: -# scripts/maint/updateFallbackDirs.py > src/app/config/fallback_dirs.inc 2> fallback_dirs.log -# -# Check the existing list: -# scripts/maint/updateFallbackDirs.py check_existing > fallback_dirs.inc.ok 2> fallback_dirs.log -# mv fallback_dirs.inc.ok src/app/config/fallback_dirs.inc -# -# This script should be run from a stable, reliable network connection, -# with no other network activity (and not over tor). -# If this is not possible, please disable: -# PERFORM_IPV4_DIRPORT_CHECKS and PERFORM_IPV6_DIRPORT_CHECKS -# -# Needs dateutil, stem, and potentially other python packages. -# Optionally uses ipaddress (python 3 builtin) or py2-ipaddress (package) -# for netblock analysis. -# -# After running this script, read the logs to make sure the fallbacks aren't -# dominated by a single netblock or port. - -# Script by weasel, April 2015 -# Portions by gsathya & karsten, 2013 -# https://trac.torproject.org/projects/tor/attachment/ticket/8374/dir_list.2.py -# Modifications by teor, 2015 - -import StringIO -import string -import re -import datetime -import gzip -import os.path -import json -import math -import sys -import urllib -import urllib2 -import hashlib -import dateutil.parser -import copy -import re - -from stem.descriptor import DocumentHandler -from stem.descriptor.remote import get_consensus, get_server_descriptors, MAX_FINGERPRINTS - -import logging -logging.root.name = '' - -HAVE_IPADDRESS = False -try: - # python 3 builtin, or install package py2-ipaddress - # there are several ipaddress implementations for python 2 - # with slightly different semantics with str typed text - # fortunately, all our IP addresses are in unicode - import ipaddress - HAVE_IPADDRESS = True -except ImportError: - # if this happens, we avoid doing netblock analysis - logging.warning('Unable to import ipaddress, please install py2-ipaddress.' + - ' A fallback list will be created, but optional netblock' + - ' analysis will not be performed.') - -## Top-Level Configuration - -# We use semantic versioning: https://semver.org -# In particular: -# * major changes include removing a mandatory field, or anything else that -# would break an appropriately tolerant parser, -# * minor changes include adding a field, -# * patch changes include changing header comments or other unstructured -# content -FALLBACK_FORMAT_VERSION = '2.0.0' -SECTION_SEPARATOR_BASE = '=====' -SECTION_SEPARATOR_COMMENT = '/* ' + SECTION_SEPARATOR_BASE + ' */' - -# Output all candidate fallbacks, or only output selected fallbacks? -OUTPUT_CANDIDATES = False - -# Perform DirPort checks over IPv4? -# Change this to False if IPv4 doesn't work for you, or if you don't want to -# download a consensus for each fallback -# Don't check ~1000 candidates when OUTPUT_CANDIDATES is True -PERFORM_IPV4_DIRPORT_CHECKS = False if OUTPUT_CANDIDATES else True - -# Perform DirPort checks over IPv6? -# If you know IPv6 works for you, set this to True -# This will exclude IPv6 relays without an IPv6 DirPort configured -# So it's best left at False until #18394 is implemented -# Don't check ~1000 candidates when OUTPUT_CANDIDATES is True -PERFORM_IPV6_DIRPORT_CHECKS = False if OUTPUT_CANDIDATES else False - -# Must relays be running now? -MUST_BE_RUNNING_NOW = (PERFORM_IPV4_DIRPORT_CHECKS - or PERFORM_IPV6_DIRPORT_CHECKS) - -# Clients have been using microdesc consensuses by default for a while now -DOWNLOAD_MICRODESC_CONSENSUS = True - -# If a relay delivers an invalid consensus, if it will become valid less than -# this many seconds in the future, or expired less than this many seconds ago, -# accept the relay as a fallback. For the consensus expiry check to be -# accurate, the machine running this script needs an accurate clock. -# -# Relays on 0.3.0 and later return a 404 when they are about to serve a -# consensus that expired more than 24 hours ago. 0.2.9 and earlier relays -# will serve consensuses that are very old. -# -# Relays on 0.3.5.6-rc? and later return a 404 when they are about to serve a -# consensus that will become valid more than 24 hours in the future. Older -# relays don't serve future consensuses. -# -# A 404 makes relays fail the download check. We use a tolerance of 24 hours, -# so that 0.2.9 relays also fail the download check if they serve a consensus -# that is not reasonably live. -# -# REASONABLY_LIVE_TIME should never be more than Tor's REASONABLY_LIVE_TIME, -# (24 hours), because clients reject consensuses that are older than that. -# Clients on 0.3.5.5-alpha? and earlier also won't select guards from -# consensuses that have expired, but can bootstrap if they already have guards -# in their state file. -REASONABLY_LIVE_TIME = 24*60*60 - -# Output fallback name, flags, bandwidth, and ContactInfo in a C comment? -OUTPUT_COMMENTS = True if OUTPUT_CANDIDATES else False - -# Output matching ContactInfo in fallbacks list? -# Useful if you're trying to contact operators -CONTACT_COUNT = True if OUTPUT_CANDIDATES else False - -# How the list should be sorted: -# fingerprint: is useful for stable diffs of fallback lists -# measured_bandwidth: is useful when pruning the list based on bandwidth -# contact: is useful for contacting operators once the list has been pruned -OUTPUT_SORT_FIELD = 'contact' if OUTPUT_CANDIDATES else 'fingerprint' - -## OnionOO Settings - -ONIONOO = 'https://onionoo.torproject.org/' -#ONIONOO = 'https://onionoo.thecthulhu.com/' - -# Don't bother going out to the Internet, just use the files available locally, -# even if they're very old -LOCAL_FILES_ONLY = False - -## Whitelist / Blacklist Filter Settings - -# The whitelist contains entries that are included if all attributes match -# (IPv4, dirport, orport, id, and optionally IPv6 and IPv6 orport) - -# What happens to entries not in whitelist? -# When True, they are included, when False, they are excluded -INCLUDE_UNLISTED_ENTRIES = True if OUTPUT_CANDIDATES else False - -WHITELIST_FILE_NAME = 'scripts/maint/fallback.whitelist' -FALLBACK_FILE_NAME = 'src/app/config/fallback_dirs.inc' - -# The number of bytes we'll read from a filter file before giving up -MAX_LIST_FILE_SIZE = 1024 * 1024 - -## Eligibility Settings - -# Require fallbacks to have the same address and port for a set amount of time -# We used to have this at 1 week, but that caused many fallback failures, which -# meant that we had to rebuild the list more often. We want fallbacks to be -# stable for 2 years, so we set it to a few months. -# -# If a relay changes address or port, that's it, it's not useful any more, -# because clients can't find it -ADDRESS_AND_PORT_STABLE_DAYS = 90 -# We ignore relays that have been down for more than this period -MAX_DOWNTIME_DAYS = 0 if MUST_BE_RUNNING_NOW else 7 -# FallbackDirs must have a time-weighted-fraction that is greater than or -# equal to: -# Mirrors that are down half the time are still useful half the time -CUTOFF_RUNNING = .50 -CUTOFF_V2DIR = .50 -# Guard flags are removed for some time after a relay restarts, so we ignore -# the guard flag. -CUTOFF_GUARD = .00 -# FallbackDirs must have a time-weighted-fraction that is less than or equal -# to: -# .00 means no bad exits -PERMITTED_BADEXIT = .00 - -# older entries' weights are adjusted with ALPHA^(age in days) -AGE_ALPHA = 0.99 - -# this factor is used to scale OnionOO entries to [0,1] -ONIONOO_SCALE_ONE = 999. - -## Fallback Count Limits - -# The target for these parameters is 20% of the guards in the network -# This is around 200 as of October 2015 -_FB_POG = 0.2 -FALLBACK_PROPORTION_OF_GUARDS = None if OUTPUT_CANDIDATES else _FB_POG - -# Limit the number of fallbacks (eliminating lowest by advertised bandwidth) -MAX_FALLBACK_COUNT = None if OUTPUT_CANDIDATES else 200 -# Emit a C #error if the number of fallbacks is less than expected -MIN_FALLBACK_COUNT = 0 if OUTPUT_CANDIDATES else MAX_FALLBACK_COUNT*0.5 - -# The maximum number of fallbacks on the same address, contact, or family -# -# With 150 fallbacks, this means each operator sees 5% of client bootstraps. -# For comparison: -# - We try to limit guard and exit operators to 5% of the network -# - The directory authorities used to see 11% of client bootstraps each -# -# We also don't want too much of the list to go down if a single operator -# has to move all their relays. -MAX_FALLBACKS_PER_IP = 1 -MAX_FALLBACKS_PER_IPV4 = MAX_FALLBACKS_PER_IP -MAX_FALLBACKS_PER_IPV6 = MAX_FALLBACKS_PER_IP -MAX_FALLBACKS_PER_CONTACT = 7 -MAX_FALLBACKS_PER_FAMILY = 7 - -## Fallback Bandwidth Requirements - -# Any fallback with the Exit flag has its bandwidth multiplied by this fraction -# to make sure we aren't further overloading exits -# (Set to 1.0, because we asked that only lightly loaded exits opt-in, -# and the extra load really isn't that much for large relays.) -EXIT_BANDWIDTH_FRACTION = 1.0 - -# If a single fallback's bandwidth is too low, it's pointless adding it -# We expect fallbacks to handle an extra 10 kilobytes per second of traffic -# Make sure they can support fifty times the expected extra load -# -# We convert this to a consensus weight before applying the filter, -# because all the bandwidth amounts are specified by the relay -MIN_BANDWIDTH = 50.0 * 10.0 * 1024.0 - -# Clients will time out after 30 seconds trying to download a consensus -# So allow fallback directories half that to deliver a consensus -# The exact download times might change based on the network connection -# running this script, but only by a few seconds -# There is also about a second of python overhead -CONSENSUS_DOWNLOAD_SPEED_MAX = 15.0 -# If the relay fails a consensus check, retry the download -# This avoids delisting a relay due to transient network conditions -CONSENSUS_DOWNLOAD_RETRY = True - -## Parsing Functions - -def parse_ts(t): - return datetime.datetime.strptime(t, "%Y-%m-%d %H:%M:%S") - -def remove_bad_chars(raw_string, bad_char_list): - # Remove each character in the bad_char_list - cleansed_string = raw_string - for c in bad_char_list: - cleansed_string = cleansed_string.replace(c, '') - return cleansed_string - -def cleanse_unprintable(raw_string): - # Remove all unprintable characters - cleansed_string = '' - for c in raw_string: - if c in string.printable: - cleansed_string += c - return cleansed_string - -def cleanse_whitespace(raw_string): - # Replace all whitespace characters with a space - cleansed_string = raw_string - for c in string.whitespace: - cleansed_string = cleansed_string.replace(c, ' ') - return cleansed_string - -def cleanse_c_multiline_comment(raw_string): - cleansed_string = raw_string - # Embedded newlines should be removed by tor/onionoo, but let's be paranoid - cleansed_string = cleanse_whitespace(cleansed_string) - # ContactInfo and Version can be arbitrary binary data - cleansed_string = cleanse_unprintable(cleansed_string) - # Prevent a malicious / unanticipated string from breaking out - # of a C-style multiline comment - # This removes '/*' and '*/' and '//' - bad_char_list = '*/' - # Prevent a malicious string from using C nulls - bad_char_list += '\0' - # Avoid confusing parsers by making sure there is only one comma per fallback - bad_char_list += ',' - # Avoid confusing parsers by making sure there is only one equals per field - bad_char_list += '=' - # Be safer by removing bad characters entirely - cleansed_string = remove_bad_chars(cleansed_string, bad_char_list) - # Some compilers may further process the content of comments - # There isn't much we can do to cover every possible case - # But comment-based directives are typically only advisory - return cleansed_string - -def cleanse_c_string(raw_string): - cleansed_string = raw_string - # Embedded newlines should be removed by tor/onionoo, but let's be paranoid - cleansed_string = cleanse_whitespace(cleansed_string) - # ContactInfo and Version can be arbitrary binary data - cleansed_string = cleanse_unprintable(cleansed_string) - # Prevent a malicious address/fingerprint string from breaking out - # of a C-style string - bad_char_list = '"' - # Prevent a malicious string from using escapes - bad_char_list += '\\' - # Prevent a malicious string from using C nulls - bad_char_list += '\0' - # Avoid confusing parsers by making sure there is only one comma per fallback - bad_char_list += ',' - # Avoid confusing parsers by making sure there is only one equals per field - bad_char_list += '=' - # Be safer by removing bad characters entirely - cleansed_string = remove_bad_chars(cleansed_string, bad_char_list) - # Some compilers may further process the content of strings - # There isn't much we can do to cover every possible case - # But this typically only results in changes to the string data - return cleansed_string - -## OnionOO Source Functions - -# a dictionary of source metadata for each onionoo query we've made -fetch_source = {} - -# register source metadata for 'what' -# assumes we only retrieve one document for each 'what' -def register_fetch_source(what, url, relays_published, version): - fetch_source[what] = {} - fetch_source[what]['url'] = url - fetch_source[what]['relays_published'] = relays_published - fetch_source[what]['version'] = version - -# list each registered source's 'what' -def fetch_source_list(): - return sorted(fetch_source.keys()) - -# given 'what', provide a multiline C comment describing the source -def describe_fetch_source(what): - desc = '/*' - desc += '\n' - desc += 'Onionoo Source: ' - desc += cleanse_c_multiline_comment(what) - desc += ' Date: ' - desc += cleanse_c_multiline_comment(fetch_source[what]['relays_published']) - desc += ' Version: ' - desc += cleanse_c_multiline_comment(fetch_source[what]['version']) - desc += '\n' - desc += 'URL: ' - desc += cleanse_c_multiline_comment(fetch_source[what]['url']) - desc += '\n' - desc += '*/' - return desc - -## File Processing Functions - -def write_to_file(str, file_name, max_len): - try: - with open(file_name, 'w') as f: - f.write(str[0:max_len]) - except EnvironmentError, error: - logging.error('Writing file %s failed: %d: %s'% - (file_name, - error.errno, - error.strerror) - ) - -def read_from_file(file_name, max_len): - try: - if os.path.isfile(file_name): - with open(file_name, 'r') as f: - return f.read(max_len) - except EnvironmentError, error: - logging.info('Loading file %s failed: %d: %s'% - (file_name, - error.errno, - error.strerror) - ) - return None - -def parse_fallback_file(file_name): - file_data = read_from_file(file_name, MAX_LIST_FILE_SIZE) - file_data = cleanse_unprintable(file_data) - file_data = remove_bad_chars(file_data, '\n"\0') - file_data = re.sub('/\*.*?\*/', '', file_data) - file_data = file_data.replace(',', '\n') - file_data = file_data.replace(' weight=10', '') - return file_data - -def load_possibly_compressed_response_json(response): - if response.info().get('Content-Encoding') == 'gzip': - buf = StringIO.StringIO( response.read() ) - f = gzip.GzipFile(fileobj=buf) - return json.load(f) - else: - return json.load(response) - -def load_json_from_file(json_file_name): - # An exception here may be resolved by deleting the .last_modified - # and .json files, and re-running the script - try: - with open(json_file_name, 'r') as f: - return json.load(f) - except EnvironmentError, error: - raise Exception('Reading not-modified json file %s failed: %d: %s'% - (json_file_name, - error.errno, - error.strerror) - ) - -## OnionOO Functions - -def datestr_to_datetime(datestr): - # Parse datetimes like: Fri, 02 Oct 2015 13:34:14 GMT - if datestr is not None: - dt = dateutil.parser.parse(datestr) - else: - # Never modified - use start of epoch - dt = datetime.datetime.utcfromtimestamp(0) - # strip any timezone out (in case they're supported in future) - dt = dt.replace(tzinfo=None) - return dt - -def onionoo_fetch(what, **kwargs): - params = kwargs - params['type'] = 'relay' - #params['limit'] = 10 - params['first_seen_days'] = '%d-'%(ADDRESS_AND_PORT_STABLE_DAYS) - params['last_seen_days'] = '-%d'%(MAX_DOWNTIME_DAYS) - params['flag'] = 'V2Dir' - url = ONIONOO + what + '?' + urllib.urlencode(params) - - # Unfortunately, the URL is too long for some OS filenames, - # but we still don't want to get files from different URLs mixed up - base_file_name = what + '-' + hashlib.sha1(url).hexdigest() - - full_url_file_name = base_file_name + '.full_url' - MAX_FULL_URL_LENGTH = 1024 - - last_modified_file_name = base_file_name + '.last_modified' - MAX_LAST_MODIFIED_LENGTH = 64 - - json_file_name = base_file_name + '.json' - - if LOCAL_FILES_ONLY: - # Read from the local file, don't write to anything - response_json = load_json_from_file(json_file_name) - else: - # store the full URL to a file for debugging - # no need to compare as long as you trust SHA-1 - write_to_file(url, full_url_file_name, MAX_FULL_URL_LENGTH) - - request = urllib2.Request(url) - request.add_header('Accept-encoding', 'gzip') - - # load the last modified date from the file, if it exists - last_mod_date = read_from_file(last_modified_file_name, - MAX_LAST_MODIFIED_LENGTH) - if last_mod_date is not None: - request.add_header('If-modified-since', last_mod_date) - - # Parse last modified date - last_mod = datestr_to_datetime(last_mod_date) - - # Not Modified and still recent enough to be useful - # Onionoo / Globe used to use 6 hours, but we can afford a day - required_freshness = datetime.datetime.utcnow() - # strip any timezone out (to match dateutil.parser) - required_freshness = required_freshness.replace(tzinfo=None) - required_freshness -= datetime.timedelta(hours=24) - - # Make the OnionOO request - response_code = 0 - try: - response = urllib2.urlopen(request) - response_code = response.getcode() - except urllib2.HTTPError, error: - response_code = error.code - if response_code == 304: # not modified - pass - else: - raise Exception("Could not get " + url + ": " - + str(error.code) + ": " + error.reason) - - if response_code == 200: # OK - last_mod = datestr_to_datetime(response.info().get('Last-Modified')) - - # Check for freshness - if last_mod < required_freshness: - if last_mod_date is not None: - # This check sometimes fails transiently, retry the script if it does - date_message = "Outdated data: last updated " + last_mod_date - else: - date_message = "No data: never downloaded " - raise Exception(date_message + " from " + url) - - # Process the data - if response_code == 200: # OK - - response_json = load_possibly_compressed_response_json(response) - - with open(json_file_name, 'w') as f: - # use the most compact json representation to save space - json.dump(response_json, f, separators=(',',':')) - - # store the last modified date in its own file - if response.info().get('Last-modified') is not None: - write_to_file(response.info().get('Last-Modified'), - last_modified_file_name, - MAX_LAST_MODIFIED_LENGTH) - - elif response_code == 304: # Not Modified - - response_json = load_json_from_file(json_file_name) - - else: # Unexpected HTTP response code not covered in the HTTPError above - raise Exception("Unexpected HTTP response code to " + url + ": " - + str(response_code)) - - register_fetch_source(what, - url, - response_json['relays_published'], - response_json['version']) - - return response_json - -def fetch(what, **kwargs): - #x = onionoo_fetch(what, **kwargs) - # don't use sort_keys, as the order of or_addresses is significant - #print json.dumps(x, indent=4, separators=(',', ': ')) - #sys.exit(0) - - return onionoo_fetch(what, **kwargs) - -## Fallback Candidate Class - -class Candidate(object): - CUTOFF_ADDRESS_AND_PORT_STABLE = (datetime.datetime.utcnow() - - datetime.timedelta(ADDRESS_AND_PORT_STABLE_DAYS)) - - def __init__(self, details): - for f in ['fingerprint', 'nickname', 'last_changed_address_or_port', - 'consensus_weight', 'or_addresses', 'dir_address']: - if not f in details: raise Exception("Document has no %s field."%(f,)) - - if not 'contact' in details: - details['contact'] = None - if not 'flags' in details or details['flags'] is None: - details['flags'] = [] - if (not 'advertised_bandwidth' in details - or details['advertised_bandwidth'] is None): - # relays without advertised bandwidth have it calculated from their - # consensus weight - details['advertised_bandwidth'] = 0 - if (not 'effective_family' in details - or details['effective_family'] is None): - details['effective_family'] = [] - if not 'platform' in details: - details['platform'] = None - details['last_changed_address_or_port'] = parse_ts( - details['last_changed_address_or_port']) - self._data = details - self._stable_sort_or_addresses() - - self._fpr = self._data['fingerprint'] - self._running = self._guard = self._v2dir = 0. - self._split_dirport() - self._compute_orport() - if self.orport is None: - raise Exception("Failed to get an orport for %s."%(self._fpr,)) - self._compute_ipv6addr() - if not self.has_ipv6(): - logging.debug("Failed to get an ipv6 address for %s."%(self._fpr,)) - self._compute_version() - self._extra_info_cache = None - - def _stable_sort_or_addresses(self): - # replace self._data['or_addresses'] with a stable ordering, - # sorting the secondary addresses in string order - # leave the received order in self._data['or_addresses_raw'] - self._data['or_addresses_raw'] = self._data['or_addresses'] - or_address_primary = self._data['or_addresses'][:1] - # subsequent entries in the or_addresses array are in an arbitrary order - # so we stabilise the addresses by sorting them in string order - or_addresses_secondaries_stable = sorted(self._data['or_addresses'][1:]) - or_addresses_stable = or_address_primary + or_addresses_secondaries_stable - self._data['or_addresses'] = or_addresses_stable - - def get_fingerprint(self): - return self._fpr - - # is_valid_ipv[46]_address by gsathya, karsten, 2013 - @staticmethod - def is_valid_ipv4_address(address): - if not isinstance(address, (str, unicode)): - return False - - # check if there are four period separated values - if address.count(".") != 3: - return False - - # checks that each value in the octet are decimal values between 0-255 - for entry in address.split("."): - if not entry.isdigit() or int(entry) < 0 or int(entry) > 255: - return False - elif entry[0] == "0" and len(entry) > 1: - return False # leading zeros, for instance in "1.2.3.001" - - return True - - @staticmethod - def is_valid_ipv6_address(address): - if not isinstance(address, (str, unicode)): - return False - - # remove brackets - address = address[1:-1] - - # addresses are made up of eight colon separated groups of four hex digits - # with leading zeros being optional - # https://en.wikipedia.org/wiki/IPv6#Address_format - - colon_count = address.count(":") - - if colon_count > 7: - return False # too many groups - elif colon_count != 7 and not "::" in address: - return False # not enough groups and none are collapsed - elif address.count("::") > 1 or ":::" in address: - return False # multiple groupings of zeros can't be collapsed - - found_ipv4_on_previous_entry = False - for entry in address.split(":"): - # If an IPv6 address has an embedded IPv4 address, - # it must be the last entry - if found_ipv4_on_previous_entry: - return False - if not re.match("^[0-9a-fA-f]{0,4}$", entry): - if not Candidate.is_valid_ipv4_address(entry): - return False - else: - found_ipv4_on_previous_entry = True - - return True - - def _split_dirport(self): - # Split the dir_address into dirip and dirport - (self.dirip, _dirport) = self._data['dir_address'].split(':', 2) - self.dirport = int(_dirport) - - def _compute_orport(self): - # Choose the first ORPort that's on the same IPv4 address as the DirPort. - # In rare circumstances, this might not be the primary ORPort address. - # However, _stable_sort_or_addresses() ensures we choose the same one - # every time, even if onionoo changes the order of the secondaries. - self._split_dirport() - self.orport = None - for i in self._data['or_addresses']: - if i != self._data['or_addresses'][0]: - logging.debug('Secondary IPv4 Address Used for %s: %s'%(self._fpr, i)) - (ipaddr, port) = i.rsplit(':', 1) - if (ipaddr == self.dirip) and Candidate.is_valid_ipv4_address(ipaddr): - self.orport = int(port) - return - - def _compute_ipv6addr(self): - # Choose the first IPv6 address that uses the same port as the ORPort - # Or, choose the first IPv6 address in the list - # _stable_sort_or_addresses() ensures we choose the same IPv6 address - # every time, even if onionoo changes the order of the secondaries. - self.ipv6addr = None - self.ipv6orport = None - # Choose the first IPv6 address that uses the same port as the ORPort - for i in self._data['or_addresses']: - (ipaddr, port) = i.rsplit(':', 1) - if (port == self.orport) and Candidate.is_valid_ipv6_address(ipaddr): - self.ipv6addr = ipaddr - self.ipv6orport = int(port) - return - # Choose the first IPv6 address in the list - for i in self._data['or_addresses']: - (ipaddr, port) = i.rsplit(':', 1) - if Candidate.is_valid_ipv6_address(ipaddr): - self.ipv6addr = ipaddr - self.ipv6orport = int(port) - return - - def _compute_version(self): - # parse the version out of the platform string - # The platform looks like: "Tor 0.2.7.6 on Linux" - self._data['version'] = None - if self._data['platform'] is None: - return - # be tolerant of weird whitespacing, use a whitespace split - tokens = self._data['platform'].split() - for token in tokens: - vnums = token.split('.') - # if it's at least a.b.c.d, with potentially an -alpha-dev, -alpha, -rc - if (len(vnums) >= 4 and vnums[0].isdigit() and vnums[1].isdigit() and - vnums[2].isdigit()): - self._data['version'] = token - return - - # From #20509 - # bug #20499 affects versions from 0.2.9.1-alpha-dev to 0.2.9.4-alpha-dev - # and version 0.3.0.0-alpha-dev - # Exhaustive lists are hard to get wrong - STALE_CONSENSUS_VERSIONS = ['0.2.9.1-alpha-dev', - '0.2.9.2-alpha', - '0.2.9.2-alpha-dev', - '0.2.9.3-alpha', - '0.2.9.3-alpha-dev', - '0.2.9.4-alpha', - '0.2.9.4-alpha-dev', - '0.3.0.0-alpha-dev' - ] - - def is_valid_version(self): - # call _compute_version before calling this - # is the version of the relay a version we want as a fallback? - # checks both recommended versions and bug #20499 / #20509 - # - # if the relay doesn't have a recommended version field, exclude the relay - if not self._data.has_key('recommended_version'): - log_excluded('%s not a candidate: no recommended_version field', - self._fpr) - return False - if not self._data['recommended_version']: - log_excluded('%s not a candidate: version not recommended', self._fpr) - return False - # if the relay doesn't have version field, exclude the relay - if not self._data.has_key('version'): - log_excluded('%s not a candidate: no version field', self._fpr) - return False - if self._data['version'] in Candidate.STALE_CONSENSUS_VERSIONS: - logging.warning('%s not a candidate: version delivers stale consensuses', - self._fpr) - return False - return True - - @staticmethod - def _extract_generic_history(history, which='unknown'): - # given a tree like this: - # { - # "1_month": { - # "count": 187, - # "factor": 0.001001001001001001, - # "first": "2015-02-27 06:00:00", - # "interval": 14400, - # "last": "2015-03-30 06:00:00", - # "values": [ - # 999, - # 999 - # ] - # }, - # "1_week": { - # "count": 169, - # "factor": 0.001001001001001001, - # "first": "2015-03-23 07:30:00", - # "interval": 3600, - # "last": "2015-03-30 07:30:00", - # "values": [ ...] - # }, - # "1_year": { - # "count": 177, - # "factor": 0.001001001001001001, - # "first": "2014-04-11 00:00:00", - # "interval": 172800, - # "last": "2015-03-29 00:00:00", - # "values": [ ...] - # }, - # "3_months": { - # "count": 185, - # "factor": 0.001001001001001001, - # "first": "2014-12-28 06:00:00", - # "interval": 43200, - # "last": "2015-03-30 06:00:00", - # "values": [ ...] - # } - # }, - # extract exactly one piece of data per time interval, - # using smaller intervals where available. - # - # returns list of (age, length, value) dictionaries. - - generic_history = [] - - periods = history.keys() - periods.sort(key = lambda x: history[x]['interval']) - now = datetime.datetime.utcnow() - newest = now - for p in periods: - h = history[p] - interval = datetime.timedelta(seconds = h['interval']) - this_ts = parse_ts(h['last']) - - if (len(h['values']) != h['count']): - logging.warning('Inconsistent value count in %s document for %s' - %(p, which)) - for v in reversed(h['values']): - if (this_ts <= newest): - agt1 = now - this_ts - agt2 = interval - agetmp1 = (agt1.microseconds + (agt1.seconds + agt1.days * 24 * 3600) - * 10**6) / 10**6 - agetmp2 = (agt2.microseconds + (agt2.seconds + agt2.days * 24 * 3600) - * 10**6) / 10**6 - generic_history.append( - { 'age': agetmp1, - 'length': agetmp2, - 'value': v - }) - newest = this_ts - this_ts -= interval - - if (this_ts + interval != parse_ts(h['first'])): - logging.warning('Inconsistent time information in %s document for %s' - %(p, which)) - - #print json.dumps(generic_history, sort_keys=True, - # indent=4, separators=(',', ': ')) - return generic_history - - @staticmethod - def _avg_generic_history(generic_history): - a = [] - for i in generic_history: - if i['age'] > (ADDRESS_AND_PORT_STABLE_DAYS * 24 * 3600): - continue - if (i['length'] is not None - and i['age'] is not None - and i['value'] is not None): - w = i['length'] * math.pow(AGE_ALPHA, i['age']/(3600*24)) - a.append( (i['value'] * w, w) ) - - sv = math.fsum(map(lambda x: x[0], a)) - sw = math.fsum(map(lambda x: x[1], a)) - - if sw == 0.0: - svw = 0.0 - else: - svw = sv/sw - return svw - - def _add_generic_history(self, history): - periods = r['read_history'].keys() - periods.sort(key = lambda x: r['read_history'][x]['interval'] ) - - print periods - - def add_running_history(self, history): - pass - - def add_uptime(self, uptime): - logging.debug('Adding uptime %s.'%(self._fpr,)) - - # flags we care about: Running, V2Dir, Guard - if not 'flags' in uptime: - logging.debug('No flags in document for %s.'%(self._fpr,)) - return - - for f in ['Running', 'Guard', 'V2Dir']: - if not f in uptime['flags']: - logging.debug('No %s in flags for %s.'%(f, self._fpr,)) - return - - running = self._extract_generic_history(uptime['flags']['Running'], - '%s-Running'%(self._fpr)) - guard = self._extract_generic_history(uptime['flags']['Guard'], - '%s-Guard'%(self._fpr)) - v2dir = self._extract_generic_history(uptime['flags']['V2Dir'], - '%s-V2Dir'%(self._fpr)) - if 'BadExit' in uptime['flags']: - badexit = self._extract_generic_history(uptime['flags']['BadExit'], - '%s-BadExit'%(self._fpr)) - - self._running = self._avg_generic_history(running) / ONIONOO_SCALE_ONE - self._guard = self._avg_generic_history(guard) / ONIONOO_SCALE_ONE - self._v2dir = self._avg_generic_history(v2dir) / ONIONOO_SCALE_ONE - self._badexit = None - if 'BadExit' in uptime['flags']: - self._badexit = self._avg_generic_history(badexit) / ONIONOO_SCALE_ONE - - def is_candidate(self): - try: - if (MUST_BE_RUNNING_NOW and not self.is_running()): - log_excluded('%s not a candidate: not running now, unable to check ' + - 'DirPort consensus download', self._fpr) - return False - if (self._data['last_changed_address_or_port'] > - self.CUTOFF_ADDRESS_AND_PORT_STABLE): - log_excluded('%s not a candidate: changed address/port recently (%s)', - self._fpr, self._data['last_changed_address_or_port']) - return False - if self._running < CUTOFF_RUNNING: - log_excluded('%s not a candidate: running avg too low (%lf)', - self._fpr, self._running) - return False - if self._v2dir < CUTOFF_V2DIR: - log_excluded('%s not a candidate: v2dir avg too low (%lf)', - self._fpr, self._v2dir) - return False - if self._badexit is not None and self._badexit > PERMITTED_BADEXIT: - log_excluded('%s not a candidate: badexit avg too high (%lf)', - self._fpr, self._badexit) - return False - # this function logs a message depending on which check fails - if not self.is_valid_version(): - return False - if self._guard < CUTOFF_GUARD: - log_excluded('%s not a candidate: guard avg too low (%lf)', - self._fpr, self._guard) - return False - if (not self._data.has_key('consensus_weight') - or self._data['consensus_weight'] < 1): - log_excluded('%s not a candidate: consensus weight invalid', self._fpr) - return False - except BaseException as e: - logging.warning("Exception %s when checking if fallback is a candidate", - str(e)) - return False - return True - - def id_matches(self, id, exact=False): - """ Does this fallback's id match id? - exact is ignored. """ - return self._fpr == id - - def ipv4_addr_matches(self, ipv4_addr, exact=False): - """ Does this fallback's IPv4 address match ipv4_addr? - exact is ignored. """ - return self.dirip == ipv4_addr - - def ipv4_dirport_matches(self, ipv4_dirport, exact=False): - """ Does this fallback's IPv4 dirport match ipv4_dirport? - If exact is False, always return True. """ - if exact: - return self.dirport == int(ipv4_dirport) - else: - return True - - def ipv4_and_dirport_matches(self, ipv4_addr, ipv4_dirport, exact=False): - """ Does this fallback's IPv4 address match ipv4_addr? - If exact is True, also check ipv4_dirport. """ - ipv4_match = self.ipv4_addr_matches(ipv4_addr, exact=exact) - if exact: - return ipv4_match and self.ipv4_dirport_matches(ipv4_dirport, - exact=exact) - else: - return ipv4_match - - def ipv4_orport_matches(self, ipv4_orport, exact=False): - """ Does this fallback's IPv4 orport match ipv4_orport? - If exact is False, always return True. """ - if exact: - return self.orport == int(ipv4_orport) - else: - return True - - def ipv4_and_orport_matches(self, ipv4_addr, ipv4_orport, exact=False): - """ Does this fallback's IPv4 address match ipv4_addr? - If exact is True, also check ipv4_orport. """ - ipv4_match = self.ipv4_addr_matches(ipv4_addr, exact=exact) - if exact: - return ipv4_match and self.ipv4_orport_matches(ipv4_orport, - exact=exact) - else: - return ipv4_match - - def ipv6_addr_matches(self, ipv6_addr, exact=False): - """ Does this fallback's IPv6 address match ipv6_addr? - Both addresses must be present to match. - exact is ignored. """ - if self.has_ipv6() and ipv6_addr is not None: - # Check that we have a bracketed IPv6 address without a port - assert(ipv6_addr.startswith('[') and ipv6_addr.endswith(']')) - return self.ipv6addr == ipv6_addr - else: - return False - - def ipv6_orport_matches(self, ipv6_orport, exact=False): - """ Does this fallback's IPv6 orport match ipv6_orport? - Both ports must be present to match. - If exact is False, always return True. """ - if exact: - return (self.has_ipv6() and ipv6_orport is not None and - self.ipv6orport == int(ipv6_orport)) - else: - return True - - def ipv6_and_orport_matches(self, ipv6_addr, ipv6_orport, exact=False): - """ Does this fallback's IPv6 address match ipv6_addr? - If exact is True, also check ipv6_orport. """ - ipv6_match = self.ipv6_addr_matches(ipv6_addr, exact=exact) - if exact: - return ipv6_match and self.ipv6_orport_matches(ipv6_orport, - exact=exact) - else: - return ipv6_match - - def entry_matches_exact(self, entry): - """ Is entry an exact match for this fallback? - A fallback is an exact match for entry if each key in entry matches: - ipv4 - dirport - orport - id - ipv6 address and port (if present in the fallback or the whitelist) - If the fallback has an ipv6 key, the whitelist line must also have - it, otherwise they don't match. - - Logs a warning-level message if the fallback would be an exact match, - but one of the id, ipv4, ipv4 orport, ipv4 dirport, or ipv6 orport - have changed. """ - if not self.id_matches(entry['id'], exact=True): - # can't log here unless we match an IP and port, because every relay's - # fingerprint is compared to every entry's fingerprint - if self.ipv4_and_orport_matches(entry['ipv4'], - entry['orport'], - exact=True): - logging.warning('%s excluded: has OR %s:%d changed fingerprint to ' + - '%s?', entry['id'], self.dirip, self.orport, - self._fpr) - if self.ipv6_and_orport_matches(entry.get('ipv6_addr'), - entry.get('ipv6_orport'), - exact=True): - logging.warning('%s excluded: has OR %s changed fingerprint to ' + - '%s?', entry['id'], entry['ipv6'], self._fpr) - return False - if not self.ipv4_addr_matches(entry['ipv4'], exact=True): - logging.warning('%s excluded: has it changed IPv4 from %s to %s?', - self._fpr, entry['ipv4'], self.dirip) - return False - if not self.ipv4_dirport_matches(entry['dirport'], exact=True): - logging.warning('%s excluded: has it changed DirPort from %s:%d to ' + - '%s:%d?', self._fpr, self.dirip, int(entry['dirport']), - self.dirip, self.dirport) - return False - if not self.ipv4_orport_matches(entry['orport'], exact=True): - logging.warning('%s excluded: has it changed ORPort from %s:%d to ' + - '%s:%d?', self._fpr, self.dirip, int(entry['orport']), - self.dirip, self.orport) - return False - if entry.has_key('ipv6') and self.has_ipv6(): - # if both entry and fallback have an ipv6 address, compare them - if not self.ipv6_and_orport_matches(entry['ipv6_addr'], - entry['ipv6_orport'], - exact=True): - logging.warning('%s excluded: has it changed IPv6 ORPort from %s ' + - 'to %s:%d?', self._fpr, entry['ipv6'], - self.ipv6addr, self.ipv6orport) - return False - # if the fallback has an IPv6 address but the whitelist entry - # doesn't, or vice versa, the whitelist entry doesn't match - elif entry.has_key('ipv6') and not self.has_ipv6(): - logging.warning('%s excluded: has it lost its former IPv6 address %s?', - self._fpr, entry['ipv6']) - return False - elif not entry.has_key('ipv6') and self.has_ipv6(): - logging.warning('%s excluded: has it gained an IPv6 address %s:%d?', - self._fpr, self.ipv6addr, self.ipv6orport) - return False - return True - - def entry_matches_fuzzy(self, entry): - """ Is entry a fuzzy match for this fallback? - A fallback is a fuzzy match for entry if at least one of these keys - in entry matches: - id - ipv4 - ipv6 (if present in both the fallback and whitelist) - The ports and nickname are ignored. Missing or extra ipv6 addresses - are ignored. - - Doesn't log any warning messages. """ - if self.id_matches(entry['id'], exact=False): - return True - if self.ipv4_addr_matches(entry['ipv4'], exact=False): - return True - if entry.has_key('ipv6') and self.has_ipv6(): - # if both entry and fallback have an ipv6 address, compare them - if self.ipv6_addr_matches(entry['ipv6_addr'], exact=False): - return True - return False - - def is_in_whitelist(self, relaylist, exact=False): - """ If exact is True (existing fallback list), check if this fallback is - an exact match for any whitelist entry, using entry_matches_exact(). - - If exact is False (new fallback whitelist), check if this fallback is - a fuzzy match for any whitelist entry, using entry_matches_fuzzy(). """ - for entry in relaylist: - if exact: - if self.entry_matches_exact(entry): - return True - else: - if self.entry_matches_fuzzy(entry): - return True - return False - - def cw_to_bw_factor(self): - # any relays with a missing or zero consensus weight are not candidates - # any relays with a missing advertised bandwidth have it set to zero - return self._data['advertised_bandwidth'] / self._data['consensus_weight'] - - # since advertised_bandwidth is reported by the relay, it can be gamed - # to avoid this, use the median consensus weight to bandwidth factor to - # estimate this relay's measured bandwidth, and make that the upper limit - def measured_bandwidth(self, median_cw_to_bw_factor): - cw_to_bw= median_cw_to_bw_factor - # Reduce exit bandwidth to make sure we're not overloading them - if self.is_exit(): - cw_to_bw *= EXIT_BANDWIDTH_FRACTION - measured_bandwidth = self._data['consensus_weight'] * cw_to_bw - if self._data['advertised_bandwidth'] != 0: - # limit advertised bandwidth (if available) to measured bandwidth - return min(measured_bandwidth, self._data['advertised_bandwidth']) - else: - return measured_bandwidth - - def set_measured_bandwidth(self, median_cw_to_bw_factor): - self._data['measured_bandwidth'] = self.measured_bandwidth( - median_cw_to_bw_factor) - - def is_exit(self): - return 'Exit' in self._data['flags'] - - def is_guard(self): - return 'Guard' in self._data['flags'] - - def is_running(self): - return 'Running' in self._data['flags'] - - # does this fallback have an IPv6 address and orport? - def has_ipv6(self): - return self.ipv6addr is not None and self.ipv6orport is not None - - # strip leading and trailing brackets from an IPv6 address - # safe to use on non-bracketed IPv6 and on IPv4 addresses - # also convert to unicode, and make None appear as '' - @staticmethod - def strip_ipv6_brackets(ip): - if ip is None: - return unicode('') - if len(ip) < 2: - return unicode(ip) - if ip[0] == '[' and ip[-1] == ']': - return unicode(ip[1:-1]) - return unicode(ip) - - # are ip_a and ip_b in the same netblock? - # mask_bits is the size of the netblock - # takes both IPv4 and IPv6 addresses - # the versions of ip_a and ip_b must be the same - # the mask must be valid for the IP version - @staticmethod - def netblocks_equal(ip_a, ip_b, mask_bits): - if ip_a is None or ip_b is None: - return False - ip_a = Candidate.strip_ipv6_brackets(ip_a) - ip_b = Candidate.strip_ipv6_brackets(ip_b) - a = ipaddress.ip_address(ip_a) - b = ipaddress.ip_address(ip_b) - if a.version != b.version: - raise Exception('Mismatching IP versions in %s and %s'%(ip_a, ip_b)) - if mask_bits > a.max_prefixlen: - logging.error('Bad IP mask %d for %s and %s'%(mask_bits, ip_a, ip_b)) - mask_bits = a.max_prefixlen - if mask_bits < 0: - logging.error('Bad IP mask %d for %s and %s'%(mask_bits, ip_a, ip_b)) - mask_bits = 0 - a_net = ipaddress.ip_network('%s/%d'%(ip_a, mask_bits), strict=False) - return b in a_net - - # is this fallback's IPv4 address (dirip) in the same netblock as other's - # IPv4 address? - # mask_bits is the size of the netblock - def ipv4_netblocks_equal(self, other, mask_bits): - return Candidate.netblocks_equal(self.dirip, other.dirip, mask_bits) - - # is this fallback's IPv6 address (ipv6addr) in the same netblock as - # other's IPv6 address? - # Returns False if either fallback has no IPv6 address - # mask_bits is the size of the netblock - def ipv6_netblocks_equal(self, other, mask_bits): - if not self.has_ipv6() or not other.has_ipv6(): - return False - return Candidate.netblocks_equal(self.ipv6addr, other.ipv6addr, mask_bits) - - # is this fallback's IPv4 DirPort the same as other's IPv4 DirPort? - def dirport_equal(self, other): - return self.dirport == other.dirport - - # is this fallback's IPv4 ORPort the same as other's IPv4 ORPort? - def ipv4_orport_equal(self, other): - return self.orport == other.orport - - # is this fallback's IPv6 ORPort the same as other's IPv6 ORPort? - # Returns False if either fallback has no IPv6 address - def ipv6_orport_equal(self, other): - if not self.has_ipv6() or not other.has_ipv6(): - return False - return self.ipv6orport == other.ipv6orport - - # does this fallback have the same DirPort, IPv4 ORPort, or - # IPv6 ORPort as other? - # Ignores IPv6 ORPort if either fallback has no IPv6 address - def port_equal(self, other): - return (self.dirport_equal(other) or self.ipv4_orport_equal(other) - or self.ipv6_orport_equal(other)) - - # return a list containing IPv4 ORPort, DirPort, and IPv6 ORPort (if present) - def port_list(self): - ports = [self.dirport, self.orport] - if self.has_ipv6() and not self.ipv6orport in ports: - ports.append(self.ipv6orport) - return ports - - # does this fallback share a port with other, regardless of whether the - # port types match? - # For example, if self's IPv4 ORPort is 80 and other's DirPort is 80, - # return True - def port_shared(self, other): - for p in self.port_list(): - if p in other.port_list(): - return True - return False - - # log how long it takes to download a consensus from dirip:dirport - # returns True if the download failed, False if it succeeded within max_time - @staticmethod - def fallback_consensus_download_speed(dirip, dirport, nickname, fingerprint, - max_time): - download_failed = False - # some directory mirrors respond to requests in ways that hang python - # sockets, which is why we log this line here - logging.info('Initiating %sconsensus download from %s (%s:%d) %s.', - 'microdesc ' if DOWNLOAD_MICRODESC_CONSENSUS else '', - nickname, dirip, dirport, fingerprint) - # there appears to be about 1 second of overhead when comparing stem's - # internal trace time and the elapsed time calculated here - TIMEOUT_SLOP = 1.0 - start = datetime.datetime.utcnow() - try: - consensus = get_consensus( - endpoints = [(dirip, dirport)], - timeout = (max_time + TIMEOUT_SLOP), - validate = True, - retries = 0, - fall_back_to_authority = False, - document_handler = DocumentHandler.BARE_DOCUMENT, - microdescriptor = DOWNLOAD_MICRODESC_CONSENSUS - ).run()[0] - end = datetime.datetime.utcnow() - time_since_expiry = (end - consensus.valid_until).total_seconds() - time_until_valid = (consensus.valid_after - end).total_seconds() - except Exception, stem_error: - end = datetime.datetime.utcnow() - log_excluded('Unable to retrieve a consensus from %s: %s', nickname, - stem_error) - status = 'error: "%s"' % (stem_error) - level = logging.WARNING - download_failed = True - elapsed = (end - start).total_seconds() - if download_failed: - # keep the error failure status, and avoid using the variables - pass - elif elapsed > max_time: - status = 'too slow' - level = logging.WARNING - download_failed = True - elif (time_since_expiry > 0): - status = 'outdated consensus, expired %ds ago'%(int(time_since_expiry)) - if time_since_expiry <= REASONABLY_LIVE_TIME: - status += ', tolerating up to %ds'%(REASONABLY_LIVE_TIME) - level = logging.INFO - else: - status += ', invalid' - level = logging.WARNING - download_failed = True - elif (time_until_valid > 0): - status = 'future consensus, valid in %ds'%(int(time_until_valid)) - if time_until_valid <= REASONABLY_LIVE_TIME: - status += ', tolerating up to %ds'%(REASONABLY_LIVE_TIME) - level = logging.INFO - else: - status += ', invalid' - level = logging.WARNING - download_failed = True - else: - status = 'ok' - level = logging.DEBUG - logging.log(level, 'Consensus download: %0.1fs %s from %s (%s:%d) %s, ' + - 'max download time %0.1fs.', elapsed, status, nickname, - dirip, dirport, fingerprint, max_time) - return download_failed - - # does this fallback download the consensus fast enough? - def check_fallback_download_consensus(self): - # include the relay if we're not doing a check, or we can't check (IPv6) - ipv4_failed = False - ipv6_failed = False - if PERFORM_IPV4_DIRPORT_CHECKS: - ipv4_failed = Candidate.fallback_consensus_download_speed(self.dirip, - self.dirport, - self._data['nickname'], - self._fpr, - CONSENSUS_DOWNLOAD_SPEED_MAX) - if self.has_ipv6() and PERFORM_IPV6_DIRPORT_CHECKS: - # Clients assume the IPv6 DirPort is the same as the IPv4 DirPort - ipv6_failed = Candidate.fallback_consensus_download_speed(self.ipv6addr, - self.dirport, - self._data['nickname'], - self._fpr, - CONSENSUS_DOWNLOAD_SPEED_MAX) - return ((not ipv4_failed) and (not ipv6_failed)) - - # if this fallback has not passed a download check, try it again, - # and record the result, available in get_fallback_download_consensus - def try_fallback_download_consensus(self): - if not self.get_fallback_download_consensus(): - self._data['download_check'] = self.check_fallback_download_consensus() - - # did this fallback pass the download check? - def get_fallback_download_consensus(self): - # if we're not performing checks, return True - if not PERFORM_IPV4_DIRPORT_CHECKS and not PERFORM_IPV6_DIRPORT_CHECKS: - return True - # if we are performing checks, but haven't done one, return False - if not self._data.has_key('download_check'): - return False - return self._data['download_check'] - - # output an optional header comment and info for this fallback - # try_fallback_download_consensus before calling this - def fallbackdir_line(self, fallbacks, prefilter_fallbacks): - s = '' - if OUTPUT_COMMENTS: - s += self.fallbackdir_comment(fallbacks, prefilter_fallbacks) - # if the download speed is ok, output a C string - # if it's not, but we OUTPUT_COMMENTS, output a commented-out C string - if self.get_fallback_download_consensus() or OUTPUT_COMMENTS: - s += self.fallbackdir_info(self.get_fallback_download_consensus()) - return s - - # output a header comment for this fallback - def fallbackdir_comment(self, fallbacks, prefilter_fallbacks): - # /* - # nickname - # flags - # adjusted bandwidth, consensus weight - # [contact] - # [identical contact counts] - # */ - # Multiline C comment - s = '/*' - s += '\n' - s += cleanse_c_multiline_comment(self._data['nickname']) - s += '\n' - s += 'Flags: ' - s += cleanse_c_multiline_comment(' '.join(sorted(self._data['flags']))) - s += '\n' - # this is an adjusted bandwidth, see calculate_measured_bandwidth() - bandwidth = self._data['measured_bandwidth'] - weight = self._data['consensus_weight'] - s += 'Bandwidth: %.1f MByte/s, Consensus Weight: %d'%( - bandwidth/(1024.0*1024.0), - weight) - s += '\n' - if self._data['contact'] is not None: - s += cleanse_c_multiline_comment(self._data['contact']) - if CONTACT_COUNT: - fallback_count = len([f for f in fallbacks - if f._data['contact'] == self._data['contact']]) - if fallback_count > 1: - s += '\n' - s += '%d identical contacts listed' % (fallback_count) - - # output the fallback info C string for this fallback - # this is the text that would go after FallbackDir in a torrc - # if this relay failed the download test and we OUTPUT_COMMENTS, - # comment-out the returned string - def fallbackdir_info(self, dl_speed_ok): - # "address:dirport orport=port id=fingerprint" - # (insert additional madatory fields here) - # "[ipv6=addr:orport]" - # (insert additional optional fields here) - # /* nickname=name */ - # /* extrainfo={0,1} */ - # (insert additional comment fields here) - # /* ===== */ - # , - # - # Do we want a C string, or a commented-out string? - c_string = dl_speed_ok - comment_string = not dl_speed_ok and OUTPUT_COMMENTS - # If we don't want either kind of string, bail - if not c_string and not comment_string: - return '' - s = '' - # Comment out the fallback directory entry if it's too slow - # See the debug output for which address and port is failing - if comment_string: - s += '/* Consensus download failed or was too slow:\n' - # Multi-Line C string with trailing comma (part of a string list) - # This makes it easier to diff the file, and remove IPv6 lines using grep - # Integers don't need escaping - s += '"%s orport=%d id=%s"'%( - cleanse_c_string(self._data['dir_address']), - self.orport, - cleanse_c_string(self._fpr)) - s += '\n' - # (insert additional madatory fields here) - if self.has_ipv6(): - s += '" ipv6=%s:%d"'%(cleanse_c_string(self.ipv6addr), self.ipv6orport) - s += '\n' - # (insert additional optional fields here) - if not comment_string: - s += '/* ' - s += 'nickname=%s'%(cleanse_c_string(self._data['nickname'])) - if not comment_string: - s += ' */' - s += '\n' - # if we know that the fallback is an extrainfo cache, flag it - # and if we don't know, assume it is not - if not comment_string: - s += '/* ' - s += 'extrainfo=%d'%(1 if self._extra_info_cache else 0) - if not comment_string: - s += ' */' - s += '\n' - # (insert additional comment fields here) - # The terminator and comma must be the last line in each fallback entry - if not comment_string: - s += '/* ' - s += SECTION_SEPARATOR_BASE - if not comment_string: - s += ' */' - s += '\n' - s += ',' - if comment_string: - s += '\n' - s += '*/' - return s - -## Fallback Candidate List Class - -class CandidateList(dict): - def __init__(self): - pass - - def _add_relay(self, details): - if not 'dir_address' in details: return - c = Candidate(details) - self[ c.get_fingerprint() ] = c - - def _add_uptime(self, uptime): - try: - fpr = uptime['fingerprint'] - except KeyError: - raise Exception("Document has no fingerprint field.") - - try: - c = self[fpr] - except KeyError: - logging.debug('Got unknown relay %s in uptime document.'%(fpr,)) - return - - c.add_uptime(uptime) - - def _add_details(self): - logging.debug('Loading details document.') - d = fetch('details', - fields=('fingerprint,nickname,contact,last_changed_address_or_port,' + - 'consensus_weight,advertised_bandwidth,or_addresses,' + - 'dir_address,recommended_version,flags,effective_family,' + - 'platform')) - logging.debug('Loading details document done.') - - if not 'relays' in d: raise Exception("No relays found in document.") - - for r in d['relays']: self._add_relay(r) - - def _add_uptimes(self): - logging.debug('Loading uptime document.') - d = fetch('uptime') - logging.debug('Loading uptime document done.') - - if not 'relays' in d: raise Exception("No relays found in document.") - for r in d['relays']: self._add_uptime(r) - - def add_relays(self): - self._add_details() - self._add_uptimes() - - def count_guards(self): - guard_count = 0 - for fpr in self.keys(): - if self[fpr].is_guard(): - guard_count += 1 - return guard_count - - # Find fallbacks that fit the uptime, stability, and flags criteria, - # and make an array of them in self.fallbacks - def compute_fallbacks(self): - self.fallbacks = map(lambda x: self[x], - filter(lambda x: self[x].is_candidate(), - self.keys())) - - # sort fallbacks by their consensus weight to advertised bandwidth factor, - # lowest to highest - # used to find the median cw_to_bw_factor() - def sort_fallbacks_by_cw_to_bw_factor(self): - self.fallbacks.sort(key=lambda f: f.cw_to_bw_factor()) - - # sort fallbacks by their measured bandwidth, highest to lowest - # calculate_measured_bandwidth before calling this - # this is useful for reviewing candidates in priority order - def sort_fallbacks_by_measured_bandwidth(self): - self.fallbacks.sort(key=lambda f: f._data['measured_bandwidth'], - reverse=True) - - # sort fallbacks by the data field data_field, lowest to highest - def sort_fallbacks_by(self, data_field): - self.fallbacks.sort(key=lambda f: f._data[data_field]) - - @staticmethod - def load_relaylist(file_obj): - """ Read each line in the file, and parse it like a FallbackDir line: - an IPv4 address and optional port: - : - which are parsed into dictionary entries: - ipv4= - dirport= - followed by a series of key=value entries: - orport= - id= - ipv6=: - each line's key/value pairs are placed in a dictonary, - (of string -> string key/value pairs), - and these dictionaries are placed in an array. - comments start with # and are ignored. """ - file_data = file_obj['data'] - file_name = file_obj['name'] - relaylist = [] - if file_data is None: - return relaylist - for line in file_data.split('\n'): - relay_entry = {} - # ignore comments - line_comment_split = line.split('#') - line = line_comment_split[0] - # cleanup whitespace - line = cleanse_whitespace(line) - line = line.strip() - if len(line) == 0: - continue - for item in line.split(' '): - item = item.strip() - if len(item) == 0: - continue - key_value_split = item.split('=') - kvl = len(key_value_split) - if kvl < 1 or kvl > 2: - print '#error Bad %s item: %s, format is key=value.'%( - file_name, item) - if kvl == 1: - # assume that entries without a key are the ipv4 address, - # perhaps with a dirport - ipv4_maybe_dirport = key_value_split[0] - ipv4_maybe_dirport_split = ipv4_maybe_dirport.split(':') - dirl = len(ipv4_maybe_dirport_split) - if dirl < 1 or dirl > 2: - print '#error Bad %s IPv4 item: %s, format is ipv4:port.'%( - file_name, item) - if dirl >= 1: - relay_entry['ipv4'] = ipv4_maybe_dirport_split[0] - if dirl == 2: - relay_entry['dirport'] = ipv4_maybe_dirport_split[1] - elif kvl == 2: - relay_entry[key_value_split[0]] = key_value_split[1] - # split ipv6 addresses and orports - if key_value_split[0] == 'ipv6': - ipv6_orport_split = key_value_split[1].rsplit(':', 1) - ipv6l = len(ipv6_orport_split) - if ipv6l != 2: - print '#error Bad %s IPv6 item: %s, format is [ipv6]:orport.'%( - file_name, item) - relay_entry['ipv6_addr'] = ipv6_orport_split[0] - relay_entry['ipv6_orport'] = ipv6_orport_split[1] - relaylist.append(relay_entry) - return relaylist - - def apply_filter_lists(self, whitelist_obj, exact=False): - """ Apply the fallback whitelist_obj to this fallback list, - passing exact to is_in_whitelist(). """ - excluded_count = 0 - list_type = 'whitelist' - if whitelist_obj['check_existing']: - list_type = 'fallback list' - - logging.debug('Applying {}'.format(list_type)) - # parse the whitelist - whitelist = self.load_relaylist(whitelist_obj) - filtered_fallbacks = [] - for f in self.fallbacks: - in_whitelist = f.is_in_whitelist(whitelist, exact=exact) - if in_whitelist: - # include - filtered_fallbacks.append(f) - elif INCLUDE_UNLISTED_ENTRIES: - # include - filtered_fallbacks.append(f) - else: - # exclude - excluded_count += 1 - log_excluded('Excluding %s: not in %s.', - f._fpr, list_type) - self.fallbacks = filtered_fallbacks - return excluded_count - - @staticmethod - def summarise_filters(initial_count, excluded_count, check_existing): - list_type = 'Whitelist' - if check_existing: - list_type = 'Fallback list' - - return '/* %s excluded %d of %d candidates. */'%(list_type, - excluded_count, initial_count) - - # calculate each fallback's measured bandwidth based on the median - # consensus weight to advertised bandwidth ratio - def calculate_measured_bandwidth(self): - self.sort_fallbacks_by_cw_to_bw_factor() - median_fallback = self.fallback_median(True) - if median_fallback is not None: - median_cw_to_bw_factor = median_fallback.cw_to_bw_factor() - else: - # this will never be used, because there are no fallbacks - median_cw_to_bw_factor = None - for f in self.fallbacks: - f.set_measured_bandwidth(median_cw_to_bw_factor) - - # remove relays with low measured bandwidth from the fallback list - # calculate_measured_bandwidth for each relay before calling this - def remove_low_bandwidth_relays(self): - if MIN_BANDWIDTH is None: - return - above_min_bw_fallbacks = [] - for f in self.fallbacks: - if f._data['measured_bandwidth'] >= MIN_BANDWIDTH: - above_min_bw_fallbacks.append(f) - else: - # the bandwidth we log here is limited by the relay's consensus weight - # as well as its adverttised bandwidth. See set_measured_bandwidth - # for details - log_excluded('%s not a candidate: bandwidth %.1fMByte/s too low, ' + - 'must be at least %.1fMByte/s', f._fpr, - f._data['measured_bandwidth']/(1024.0*1024.0), - MIN_BANDWIDTH/(1024.0*1024.0)) - self.fallbacks = above_min_bw_fallbacks - - # the minimum fallback in the list - # call one of the sort_fallbacks_* functions before calling this - def fallback_min(self): - if len(self.fallbacks) > 0: - return self.fallbacks[-1] - else: - return None - - # the median fallback in the list - # call one of the sort_fallbacks_* functions before calling this - def fallback_median(self, require_advertised_bandwidth): - # use the low-median when there are an evan number of fallbacks, - # for consistency with the bandwidth authorities - if len(self.fallbacks) > 0: - median_position = (len(self.fallbacks) - 1) / 2 - if not require_advertised_bandwidth: - return self.fallbacks[median_position] - # if we need advertised_bandwidth but this relay doesn't have it, - # move to a fallback with greater consensus weight until we find one - while not self.fallbacks[median_position]._data['advertised_bandwidth']: - median_position += 1 - if median_position >= len(self.fallbacks): - return None - return self.fallbacks[median_position] - else: - return None - - # the maximum fallback in the list - # call one of the sort_fallbacks_* functions before calling this - def fallback_max(self): - if len(self.fallbacks) > 0: - return self.fallbacks[0] - else: - return None - - # return a new bag suitable for storing attributes - @staticmethod - def attribute_new(): - return dict() - - # get the count of attribute in attribute_bag - # if attribute is None or the empty string, return 0 - @staticmethod - def attribute_count(attribute, attribute_bag): - if attribute is None or attribute == '': - return 0 - if attribute not in attribute_bag: - return 0 - return attribute_bag[attribute] - - # does attribute_bag contain more than max_count instances of attribute? - # if so, return False - # if not, return True - # if attribute is None or the empty string, or max_count is invalid, - # always return True - @staticmethod - def attribute_allow(attribute, attribute_bag, max_count=1): - if attribute is None or attribute == '' or max_count <= 0: - return True - elif CandidateList.attribute_count(attribute, attribute_bag) >= max_count: - return False - else: - return True - - # add attribute to attribute_bag, incrementing the count if it is already - # present - # if attribute is None or the empty string, or count is invalid, - # do nothing - @staticmethod - def attribute_add(attribute, attribute_bag, count=1): - if attribute is None or attribute == '' or count <= 0: - pass - attribute_bag.setdefault(attribute, 0) - attribute_bag[attribute] += count - - # make sure there are only MAX_FALLBACKS_PER_IP fallbacks per IPv4 address, - # and per IPv6 address - # there is only one IPv4 address on each fallback: the IPv4 DirPort address - # (we choose the IPv4 ORPort which is on the same IPv4 as the DirPort) - # there is at most one IPv6 address on each fallback: the IPv6 ORPort address - # we try to match the IPv4 ORPort, but will use any IPv6 address if needed - # (clients only use the IPv6 ORPort) - # if there is no IPv6 address, only the IPv4 address is checked - # return the number of candidates we excluded - def limit_fallbacks_same_ip(self): - ip_limit_fallbacks = [] - ip_list = CandidateList.attribute_new() - for f in self.fallbacks: - if (CandidateList.attribute_allow(f.dirip, ip_list, - MAX_FALLBACKS_PER_IPV4) - and CandidateList.attribute_allow(f.ipv6addr, ip_list, - MAX_FALLBACKS_PER_IPV6)): - ip_limit_fallbacks.append(f) - CandidateList.attribute_add(f.dirip, ip_list) - if f.has_ipv6(): - CandidateList.attribute_add(f.ipv6addr, ip_list) - elif not CandidateList.attribute_allow(f.dirip, ip_list, - MAX_FALLBACKS_PER_IPV4): - log_excluded('Eliminated %s: already have %d fallback(s) on IPv4 %s' - %(f._fpr, CandidateList.attribute_count(f.dirip, ip_list), - f.dirip)) - elif (f.has_ipv6() and - not CandidateList.attribute_allow(f.ipv6addr, ip_list, - MAX_FALLBACKS_PER_IPV6)): - log_excluded('Eliminated %s: already have %d fallback(s) on IPv6 %s' - %(f._fpr, CandidateList.attribute_count(f.ipv6addr, - ip_list), - f.ipv6addr)) - original_count = len(self.fallbacks) - self.fallbacks = ip_limit_fallbacks - return original_count - len(self.fallbacks) - - # make sure there are only MAX_FALLBACKS_PER_CONTACT fallbacks for each - # ContactInfo - # if there is no ContactInfo, allow the fallback - # this check can be gamed by providing no ContactInfo, or by setting the - # ContactInfo to match another fallback - # However, given the likelihood that relays with the same ContactInfo will - # go down at similar times, its usefulness outweighs the risk - def limit_fallbacks_same_contact(self): - contact_limit_fallbacks = [] - contact_list = CandidateList.attribute_new() - for f in self.fallbacks: - if CandidateList.attribute_allow(f._data['contact'], contact_list, - MAX_FALLBACKS_PER_CONTACT): - contact_limit_fallbacks.append(f) - CandidateList.attribute_add(f._data['contact'], contact_list) - else: - log_excluded( - 'Eliminated %s: already have %d fallback(s) on ContactInfo %s' - %(f._fpr, CandidateList.attribute_count(f._data['contact'], - contact_list), - f._data['contact'])) - original_count = len(self.fallbacks) - self.fallbacks = contact_limit_fallbacks - return original_count - len(self.fallbacks) - - # make sure there are only MAX_FALLBACKS_PER_FAMILY fallbacks per effective - # family - # if there is no family, allow the fallback - # we use effective family, which ensures mutual family declarations - # but the check can be gamed by not declaring a family at all - # if any indirect families exist, the result depends on the order in which - # fallbacks are sorted in the list - def limit_fallbacks_same_family(self): - family_limit_fallbacks = [] - fingerprint_list = CandidateList.attribute_new() - for f in self.fallbacks: - if CandidateList.attribute_allow(f._fpr, fingerprint_list, - MAX_FALLBACKS_PER_FAMILY): - family_limit_fallbacks.append(f) - CandidateList.attribute_add(f._fpr, fingerprint_list) - for family_fingerprint in f._data['effective_family']: - CandidateList.attribute_add(family_fingerprint, fingerprint_list) - else: - # we already have a fallback with this fallback in its effective - # family - log_excluded( - 'Eliminated %s: already have %d fallback(s) in effective family' - %(f._fpr, CandidateList.attribute_count(f._fpr, fingerprint_list))) - original_count = len(self.fallbacks) - self.fallbacks = family_limit_fallbacks - return original_count - len(self.fallbacks) - - # try once to get the descriptors for fingerprint_list using stem - # returns an empty list on exception - @staticmethod - def get_fallback_descriptors_once(fingerprint_list): - desc_list = get_server_descriptors(fingerprints=fingerprint_list).run(suppress=True) - return desc_list - - # try up to max_retries times to get the descriptors for fingerprint_list - # using stem. Stops retrying when all descriptors have been retrieved. - # returns a list containing the descriptors that were retrieved - @staticmethod - def get_fallback_descriptors(fingerprint_list, max_retries=5): - # we can't use stem's retries=, because we want to support more than 96 - # descriptors - # - # add an attempt for every MAX_FINGERPRINTS (or part thereof) in the list - max_retries += (len(fingerprint_list) + MAX_FINGERPRINTS - 1) / MAX_FINGERPRINTS - remaining_list = fingerprint_list - desc_list = [] - for _ in xrange(max_retries): - if len(remaining_list) == 0: - break - new_desc_list = CandidateList.get_fallback_descriptors_once(remaining_list[0:MAX_FINGERPRINTS]) - for d in new_desc_list: - try: - remaining_list.remove(d.fingerprint) - except ValueError: - # warn and ignore if a directory mirror returned a bad descriptor - logging.warning("Directory mirror returned unwanted descriptor %s, ignoring", - d.fingerprint) - continue - desc_list.append(d) - return desc_list - - # find the fallbacks that cache extra-info documents - # Onionoo doesn't know this, so we have to use stem - def mark_extra_info_caches(self): - fingerprint_list = [ f._fpr for f in self.fallbacks ] - logging.info("Downloading fallback descriptors to find extra-info caches") - desc_list = CandidateList.get_fallback_descriptors(fingerprint_list) - for d in desc_list: - self[d.fingerprint]._extra_info_cache = d.extra_info_cache - missing_descriptor_list = [ f._fpr for f in self.fallbacks - if f._extra_info_cache is None ] - for f in missing_descriptor_list: - logging.warning("No descriptor for {}. Assuming extrainfo=0.".format(f)) - - # try a download check on each fallback candidate in order - # stop after max_count successful downloads - # but don't remove any candidates from the array - def try_download_consensus_checks(self, max_count): - dl_ok_count = 0 - for f in self.fallbacks: - f.try_fallback_download_consensus() - if f.get_fallback_download_consensus(): - # this fallback downloaded a consensus ok - dl_ok_count += 1 - if dl_ok_count >= max_count: - # we have enough fallbacks - return - - # put max_count successful candidates in the fallbacks array: - # - perform download checks on each fallback candidate - # - retry failed candidates if CONSENSUS_DOWNLOAD_RETRY is set - # - eliminate failed candidates - # - if there are more than max_count candidates, eliminate lowest bandwidth - # - if there are fewer than max_count candidates, leave only successful - # Return the number of fallbacks that failed the consensus check - def perform_download_consensus_checks(self, max_count): - self.sort_fallbacks_by_measured_bandwidth() - self.try_download_consensus_checks(max_count) - if CONSENSUS_DOWNLOAD_RETRY: - # try unsuccessful candidates again - # we could end up with more than max_count successful candidates here - self.try_download_consensus_checks(max_count) - # now we have at least max_count successful candidates, - # or we've tried them all - original_count = len(self.fallbacks) - self.fallbacks = filter(lambda x: x.get_fallback_download_consensus(), - self.fallbacks) - # some of these failed the check, others skipped the check, - # if we already had enough successful downloads - failed_count = original_count - len(self.fallbacks) - self.fallbacks = self.fallbacks[:max_count] - return failed_count - - # return a string that describes a/b as a percentage - @staticmethod - def describe_percentage(a, b): - if b != 0: - return '%d/%d = %.0f%%'%(a, b, (a*100.0)/b) - else: - # technically, 0/0 is undefined, but 0.0% is a sensible result - return '%d/%d = %.0f%%'%(a, b, 0.0) - - # return a dictionary of lists of fallbacks by IPv4 netblock - # the dictionary is keyed by the fingerprint of an arbitrary fallback - # in each netblock - # mask_bits is the size of the netblock - def fallbacks_by_ipv4_netblock(self, mask_bits): - netblocks = {} - for f in self.fallbacks: - found_netblock = False - for b in netblocks.keys(): - # we found an existing netblock containing this fallback - if f.ipv4_netblocks_equal(self[b], mask_bits): - # add it to the list - netblocks[b].append(f) - found_netblock = True - break - # make a new netblock based on this fallback's fingerprint - if not found_netblock: - netblocks[f._fpr] = [f] - return netblocks - - # return a dictionary of lists of fallbacks by IPv6 netblock - # where mask_bits is the size of the netblock - def fallbacks_by_ipv6_netblock(self, mask_bits): - netblocks = {} - for f in self.fallbacks: - # skip fallbacks without IPv6 addresses - if not f.has_ipv6(): - continue - found_netblock = False - for b in netblocks.keys(): - # we found an existing netblock containing this fallback - if f.ipv6_netblocks_equal(self[b], mask_bits): - # add it to the list - netblocks[b].append(f) - found_netblock = True - break - # make a new netblock based on this fallback's fingerprint - if not found_netblock: - netblocks[f._fpr] = [f] - return netblocks - - # log a message about the proportion of fallbacks in each IPv4 netblock, - # where mask_bits is the size of the netblock - def describe_fallback_ipv4_netblock_mask(self, mask_bits): - fallback_count = len(self.fallbacks) - shared_netblock_fallback_count = 0 - most_frequent_netblock = None - netblocks = self.fallbacks_by_ipv4_netblock(mask_bits) - for b in netblocks.keys(): - if len(netblocks[b]) > 1: - # how many fallbacks are in a netblock with other fallbacks? - shared_netblock_fallback_count += len(netblocks[b]) - # what's the netblock with the most fallbacks? - if (most_frequent_netblock is None - or len(netblocks[b]) > len(netblocks[most_frequent_netblock])): - most_frequent_netblock = b - logging.debug('Fallback IPv4 addresses in the same /%d:'%(mask_bits)) - for f in netblocks[b]: - logging.debug('%s - %s', f.dirip, f._fpr) - if most_frequent_netblock is not None: - logging.warning('There are %s fallbacks in the IPv4 /%d containing %s'%( - CandidateList.describe_percentage( - len(netblocks[most_frequent_netblock]), - fallback_count), - mask_bits, - self[most_frequent_netblock].dirip)) - if shared_netblock_fallback_count > 0: - logging.warning(('%s of fallbacks are in an IPv4 /%d with other ' + - 'fallbacks')%(CandidateList.describe_percentage( - shared_netblock_fallback_count, - fallback_count), - mask_bits)) - - # log a message about the proportion of fallbacks in each IPv6 netblock, - # where mask_bits is the size of the netblock - def describe_fallback_ipv6_netblock_mask(self, mask_bits): - fallback_count = len(self.fallbacks_with_ipv6()) - shared_netblock_fallback_count = 0 - most_frequent_netblock = None - netblocks = self.fallbacks_by_ipv6_netblock(mask_bits) - for b in netblocks.keys(): - if len(netblocks[b]) > 1: - # how many fallbacks are in a netblock with other fallbacks? - shared_netblock_fallback_count += len(netblocks[b]) - # what's the netblock with the most fallbacks? - if (most_frequent_netblock is None - or len(netblocks[b]) > len(netblocks[most_frequent_netblock])): - most_frequent_netblock = b - logging.debug('Fallback IPv6 addresses in the same /%d:'%(mask_bits)) - for f in netblocks[b]: - logging.debug('%s - %s', f.ipv6addr, f._fpr) - if most_frequent_netblock is not None: - logging.warning('There are %s fallbacks in the IPv6 /%d containing %s'%( - CandidateList.describe_percentage( - len(netblocks[most_frequent_netblock]), - fallback_count), - mask_bits, - self[most_frequent_netblock].ipv6addr)) - if shared_netblock_fallback_count > 0: - logging.warning(('%s of fallbacks are in an IPv6 /%d with other ' + - 'fallbacks')%(CandidateList.describe_percentage( - shared_netblock_fallback_count, - fallback_count), - mask_bits)) - - # log a message about the proportion of fallbacks in each IPv4 /8, /16, - # and /24 - def describe_fallback_ipv4_netblocks(self): - # this doesn't actually tell us anything useful - #self.describe_fallback_ipv4_netblock_mask(8) - self.describe_fallback_ipv4_netblock_mask(16) - #self.describe_fallback_ipv4_netblock_mask(24) - - # log a message about the proportion of fallbacks in each IPv6 /12 (RIR), - # /23 (smaller RIR blocks), /32 (LIR), /48 (Customer), and /64 (Host) - # https://www.iana.org/assignments/ipv6-unicast-address-assignments/ - def describe_fallback_ipv6_netblocks(self): - # these don't actually tell us anything useful - #self.describe_fallback_ipv6_netblock_mask(12) - #self.describe_fallback_ipv6_netblock_mask(23) - self.describe_fallback_ipv6_netblock_mask(32) - #self.describe_fallback_ipv6_netblock_mask(48) - self.describe_fallback_ipv6_netblock_mask(64) - - # log a message about the proportion of fallbacks in each IPv4 and IPv6 - # netblock - def describe_fallback_netblocks(self): - self.describe_fallback_ipv4_netblocks() - self.describe_fallback_ipv6_netblocks() - - # return a list of fallbacks which are on the IPv4 ORPort port - def fallbacks_on_ipv4_orport(self, port): - return filter(lambda x: x.orport == port, self.fallbacks) - - # return a list of fallbacks which are on the IPv6 ORPort port - def fallbacks_on_ipv6_orport(self, port): - return filter(lambda x: x.ipv6orport == port, self.fallbacks_with_ipv6()) - - # return a list of fallbacks which are on the DirPort port - def fallbacks_on_dirport(self, port): - return filter(lambda x: x.dirport == port, self.fallbacks) - - # log a message about the proportion of fallbacks on IPv4 ORPort port - # and return that count - def describe_fallback_ipv4_orport(self, port): - port_count = len(self.fallbacks_on_ipv4_orport(port)) - fallback_count = len(self.fallbacks) - logging.warning('%s of fallbacks are on IPv4 ORPort %d'%( - CandidateList.describe_percentage(port_count, - fallback_count), - port)) - return port_count - - # log a message about the proportion of IPv6 fallbacks on IPv6 ORPort port - # and return that count - def describe_fallback_ipv6_orport(self, port): - port_count = len(self.fallbacks_on_ipv6_orport(port)) - fallback_count = len(self.fallbacks_with_ipv6()) - logging.warning('%s of IPv6 fallbacks are on IPv6 ORPort %d'%( - CandidateList.describe_percentage(port_count, - fallback_count), - port)) - return port_count - - # log a message about the proportion of fallbacks on DirPort port - # and return that count - def describe_fallback_dirport(self, port): - port_count = len(self.fallbacks_on_dirport(port)) - fallback_count = len(self.fallbacks) - logging.warning('%s of fallbacks are on DirPort %d'%( - CandidateList.describe_percentage(port_count, - fallback_count), - port)) - return port_count - - # log a message about the proportion of fallbacks on each dirport, - # each IPv4 orport, and each IPv6 orport - def describe_fallback_ports(self): - fallback_count = len(self.fallbacks) - ipv4_or_count = fallback_count - ipv4_or_count -= self.describe_fallback_ipv4_orport(443) - ipv4_or_count -= self.describe_fallback_ipv4_orport(9001) - logging.warning('%s of fallbacks are on other IPv4 ORPorts'%( - CandidateList.describe_percentage(ipv4_or_count, - fallback_count))) - ipv6_fallback_count = len(self.fallbacks_with_ipv6()) - ipv6_or_count = ipv6_fallback_count - ipv6_or_count -= self.describe_fallback_ipv6_orport(443) - ipv6_or_count -= self.describe_fallback_ipv6_orport(9001) - logging.warning('%s of IPv6 fallbacks are on other IPv6 ORPorts'%( - CandidateList.describe_percentage(ipv6_or_count, - ipv6_fallback_count))) - dir_count = fallback_count - dir_count -= self.describe_fallback_dirport(80) - dir_count -= self.describe_fallback_dirport(9030) - logging.warning('%s of fallbacks are on other DirPorts'%( - CandidateList.describe_percentage(dir_count, - fallback_count))) - - # return a list of fallbacks which cache extra-info documents - def fallbacks_with_extra_info_cache(self): - return filter(lambda x: x._extra_info_cache, self.fallbacks) - - # log a message about the proportion of fallbacks that cache extra-info docs - def describe_fallback_extra_info_caches(self): - extra_info_falback_count = len(self.fallbacks_with_extra_info_cache()) - fallback_count = len(self.fallbacks) - logging.warning('%s of fallbacks cache extra-info documents'%( - CandidateList.describe_percentage(extra_info_falback_count, - fallback_count))) - - # return a list of fallbacks which have the Exit flag - def fallbacks_with_exit(self): - return filter(lambda x: x.is_exit(), self.fallbacks) - - # log a message about the proportion of fallbacks with an Exit flag - def describe_fallback_exit_flag(self): - exit_falback_count = len(self.fallbacks_with_exit()) - fallback_count = len(self.fallbacks) - logging.warning('%s of fallbacks have the Exit flag'%( - CandidateList.describe_percentage(exit_falback_count, - fallback_count))) - - # return a list of fallbacks which have an IPv6 address - def fallbacks_with_ipv6(self): - return filter(lambda x: x.has_ipv6(), self.fallbacks) - - # log a message about the proportion of fallbacks on IPv6 - def describe_fallback_ip_family(self): - ipv6_falback_count = len(self.fallbacks_with_ipv6()) - fallback_count = len(self.fallbacks) - logging.warning('%s of fallbacks are on IPv6'%( - CandidateList.describe_percentage(ipv6_falback_count, - fallback_count))) - - def summarise_fallbacks(self, eligible_count, operator_count, failed_count, - guard_count, target_count, check_existing): - s = '' - # Report: - # whether we checked consensus download times - # the number of fallback directories (and limits/exclusions, if relevant) - # min & max fallback bandwidths - # #error if below minimum count - if PERFORM_IPV4_DIRPORT_CHECKS or PERFORM_IPV6_DIRPORT_CHECKS: - s += '/* Checked %s%s%s DirPorts served a consensus within %.1fs. */'%( - 'IPv4' if PERFORM_IPV4_DIRPORT_CHECKS else '', - ' and ' if (PERFORM_IPV4_DIRPORT_CHECKS - and PERFORM_IPV6_DIRPORT_CHECKS) else '', - 'IPv6' if PERFORM_IPV6_DIRPORT_CHECKS else '', - CONSENSUS_DOWNLOAD_SPEED_MAX) - else: - s += '/* Did not check IPv4 or IPv6 DirPort consensus downloads. */' - s += '\n' - # Multiline C comment with #error if things go bad - s += '/*' - s += '\n' - # Integers don't need escaping in C comments - fallback_count = len(self.fallbacks) - if FALLBACK_PROPORTION_OF_GUARDS is None: - fallback_proportion = '' - else: - fallback_proportion = ', Target %d (%d * %.2f)'%(target_count, - guard_count, - FALLBACK_PROPORTION_OF_GUARDS) - s += 'Final Count: %d (Eligible %d%s'%(fallback_count, eligible_count, - fallback_proportion) - if MAX_FALLBACK_COUNT is not None: - s += ', Max %d'%(MAX_FALLBACK_COUNT) - s += ')\n' - if eligible_count != fallback_count: - removed_count = eligible_count - fallback_count - excess_to_target_or_max = (eligible_count - operator_count - failed_count - - fallback_count) - # some 'Failed' failed the check, others 'Skipped' the check, - # if we already had enough successful downloads - s += ('Excluded: %d (Same Operator %d, Failed/Skipped Download %d, ' + - 'Excess %d)')%(removed_count, operator_count, failed_count, - excess_to_target_or_max) - s += '\n' - min_fb = self.fallback_min() - min_bw = min_fb._data['measured_bandwidth'] - max_fb = self.fallback_max() - max_bw = max_fb._data['measured_bandwidth'] - s += 'Bandwidth Range: %.1f - %.1f MByte/s'%(min_bw/(1024.0*1024.0), - max_bw/(1024.0*1024.0)) - s += '\n' - s += '*/' - if fallback_count < MIN_FALLBACK_COUNT: - list_type = 'whitelist' - if check_existing: - list_type = 'fallback list' - # We must have a minimum number of fallbacks so they are always - # reachable, and are in diverse locations - s += '\n' - s += '#error Fallback Count %d is too low. '%(fallback_count) - s += 'Must be at least %d for diversity. '%(MIN_FALLBACK_COUNT) - s += 'Try adding entries to %s, '%(list_type) - s += 'or setting INCLUDE_UNLISTED_ENTRIES = True.' - return s - -def process_existing(): - logging.basicConfig(level=logging.INFO) - logging.getLogger('stem').setLevel(logging.INFO) - whitelist = {'data': parse_fallback_file(FALLBACK_FILE_NAME), - 'name': FALLBACK_FILE_NAME, - 'check_existing' : True} - list_fallbacks(whitelist, exact=True) - -def process_default(): - logging.basicConfig(level=logging.WARNING) - logging.getLogger('stem').setLevel(logging.WARNING) - whitelist = {'data': read_from_file(WHITELIST_FILE_NAME, MAX_LIST_FILE_SIZE), - 'name': WHITELIST_FILE_NAME, - 'check_existing': False} - list_fallbacks(whitelist, exact=False) - -## Main Function -def main(): - if get_command() == 'check_existing': - process_existing() - else: - process_default() - -def get_command(): - if len(sys.argv) == 2: - return sys.argv[1] - else: - return None - -def log_excluded(msg, *args): - if get_command() == 'check_existing': - logging.warning(msg, *args) - else: - logging.info(msg, *args) - -def list_fallbacks(whitelist, exact=False): - """ Fetches required onionoo documents and evaluates the - fallback directory criteria for each of the relays, - passing exact to apply_filter_lists(). """ - if whitelist['check_existing']: - print "/* type=fallback */" - else: - print "/* type=whitelist */" - - print ("/* version={} */" - .format(cleanse_c_multiline_comment(FALLBACK_FORMAT_VERSION))) - now = datetime.datetime.utcnow() - timestamp = now.strftime('%Y%m%d%H%M%S') - print ("/* timestamp={} */" - .format(cleanse_c_multiline_comment(timestamp))) - # end the header with a separator, to make it easier for parsers - print SECTION_SEPARATOR_COMMENT - - logging.warning('Downloading and parsing Onionoo data. ' + - 'This may take some time.') - # find relays that could be fallbacks - candidates = CandidateList() - candidates.add_relays() - - # work out how many fallbacks we want - guard_count = candidates.count_guards() - if FALLBACK_PROPORTION_OF_GUARDS is None: - target_count = guard_count - else: - target_count = int(guard_count * FALLBACK_PROPORTION_OF_GUARDS) - # the maximum number of fallbacks is the least of: - # - the target fallback count (FALLBACK_PROPORTION_OF_GUARDS * guard count) - # - the maximum fallback count (MAX_FALLBACK_COUNT) - if MAX_FALLBACK_COUNT is None: - max_count = target_count - else: - max_count = min(target_count, MAX_FALLBACK_COUNT) - - candidates.compute_fallbacks() - prefilter_fallbacks = copy.copy(candidates.fallbacks) - - # filter with the whitelist - # if a relay has changed IPv4 address or ports recently, it will be excluded - # as ineligible before we call apply_filter_lists, and so there will be no - # warning that the details have changed from those in the whitelist. - # instead, there will be an info-level log during the eligibility check. - initial_count = len(candidates.fallbacks) - excluded_count = candidates.apply_filter_lists(whitelist, exact=exact) - print candidates.summarise_filters(initial_count, excluded_count, - whitelist['check_existing']) - eligible_count = len(candidates.fallbacks) - - # calculate the measured bandwidth of each relay, - # then remove low-bandwidth relays - candidates.calculate_measured_bandwidth() - candidates.remove_low_bandwidth_relays() - - # print the raw fallback list - #for x in candidates.fallbacks: - # print x.fallbackdir_line(True) - # print json.dumps(candidates[x]._data, sort_keys=True, indent=4, - # separators=(',', ': '), default=json_util.default) - - # impose mandatory conditions here, like one per contact, family, IP - # in measured bandwidth order - candidates.sort_fallbacks_by_measured_bandwidth() - operator_count = 0 - # only impose these limits on the final list - operators can nominate - # multiple candidate fallbacks, and then we choose the best set - if not OUTPUT_CANDIDATES: - operator_count += candidates.limit_fallbacks_same_ip() - operator_count += candidates.limit_fallbacks_same_contact() - operator_count += candidates.limit_fallbacks_same_family() - - # check if each candidate can serve a consensus - # there's a small risk we've eliminated relays from the same operator that - # can serve a consensus, in favour of one that can't - # but given it takes up to 15 seconds to check each consensus download, - # the risk is worth it - if PERFORM_IPV4_DIRPORT_CHECKS or PERFORM_IPV6_DIRPORT_CHECKS: - logging.warning('Checking consensus download speeds. ' + - 'This may take some time.') - failed_count = candidates.perform_download_consensus_checks(max_count) - - # work out which fallbacks cache extra-infos - candidates.mark_extra_info_caches() - - # analyse and log interesting diversity metrics - # like netblock, ports, exit, IPv4-only - # (we can't easily analyse AS, and it's hard to accurately analyse country) - candidates.describe_fallback_ip_family() - # if we can't import the ipaddress module, we can't do netblock analysis - if HAVE_IPADDRESS: - candidates.describe_fallback_netblocks() - candidates.describe_fallback_ports() - candidates.describe_fallback_extra_info_caches() - candidates.describe_fallback_exit_flag() - - # output C comments summarising the fallback selection process - if len(candidates.fallbacks) > 0: - print candidates.summarise_fallbacks(eligible_count, operator_count, - failed_count, guard_count, - target_count, - whitelist['check_existing']) - else: - print '/* No Fallbacks met criteria */' - - # output C comments specifying the OnionOO data used to create the list - for s in fetch_source_list(): - print describe_fetch_source(s) - - # start the list with a separator, to make it easy for parsers - print SECTION_SEPARATOR_COMMENT - - # sort the list differently depending on why we've created it: - # if we're outputting the final fallback list, sort by fingerprint - # this makes diffs much more stable - # otherwise, if we're trying to find a bandwidth cutoff, or we want to - # contact operators in priority order, sort by bandwidth (not yet - # implemented) - # otherwise, if we're contacting operators, sort by contact - candidates.sort_fallbacks_by(OUTPUT_SORT_FIELD) - - for x in candidates.fallbacks: - print x.fallbackdir_line(candidates.fallbacks, prefilter_fallbacks) - -if __name__ == "__main__": - main() -- cgit v1.2.3-54-g00ecf From 139202174bc1df5ba1a9437bb47c7624651e7068 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 16 Jan 2019 08:20:12 -0500 Subject: Remove changes entries that appeared in 0.3.5.7 --- changes/geoip-2019-01-03 | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 changes/geoip-2019-01-03 (limited to 'changes') diff --git a/changes/geoip-2019-01-03 b/changes/geoip-2019-01-03 deleted file mode 100644 index 27ffb7f460..0000000000 --- a/changes/geoip-2019-01-03 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (geoip): - - Update geoip and geoip6 to the January 3 2019 Maxmind GeoLite2 - Country database. Closes ticket 29012. - -- cgit v1.2.3-54-g00ecf From 49062d72b5c022957bcb3bbdd116ec32550794fe Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 16 Jan 2019 08:28:07 -0500 Subject: Start on 0.4.0.1-alpha changelog --- ChangeLog | 319 +++++++++++++++++++++++++++++++++++++++++++++++ changes/bug21900 | 4 - changes/bug23082 | 4 - changes/bug24393 | 6 - changes/bug24661 | 3 - changes/bug24953 | 4 - changes/bug25885 | 7 -- changes/bug27707 | 3 - changes/bug27929 | 5 - changes/bug28518 | 4 - changes/bug28569 | 3 - changes/bug28591 | 4 - changes/bug28654 | 3 - changes/bug28895 | 5 - changes/bug28920 | 6 - changes/bug28938 | 4 - changes/bug28989 | 5 - changes/bug28995 | 5 - changes/doc28560 | 3 - changes/doc28805 | 4 - changes/document_version | 2 - changes/feature27244 | 5 - changes/feature27367 | 4 - changes/prop297 | 7 -- changes/subsystems | 6 - changes/ticket24805 | 3 - changes/ticket24838 | 6 - changes/ticket26360 | 4 - changes/ticket26770 | 8 -- changes/ticket27167 | 11 -- changes/ticket27225 | 5 - changes/ticket27325 | 4 - changes/ticket27359 | 3 - changes/ticket27402 | 10 -- changes/ticket27490 | 6 - changes/ticket27549 | 3 - changes/ticket27620 | 3 - changes/ticket27625 | 4 - changes/ticket27914 | 4 - changes/ticket27993 | 3 - changes/ticket28006 | 3 - changes/ticket28007 | 3 - changes/ticket28008 | 3 - changes/ticket28009 | 3 - changes/ticket28010 | 3 - changes/ticket28011 | 3 - changes/ticket28012 | 3 - changes/ticket28058 | 2 - changes/ticket28077 | 3 - changes/ticket28100 | 3 - changes/ticket28142 | 10 -- changes/ticket28179 | 5 - changes/ticket28180 | 3 - changes/ticket28266 | 10 -- changes/ticket28335 | 7 -- changes/ticket28362 | 6 - changes/ticket28551 | 3 - changes/ticket28624 | 5 - changes/ticket28669 | 6 - changes/ticket28757 | 5 - changes/ticket28768 | 4 - changes/ticket28839 | 3 - changes/ticket28840 | 3 - changes/ticket28843 | 3 - changes/ticket28846 | 3 - changes/ticket28847 | 3 - changes/ticket28852 | 4 - changes/ticket28853 | 3 - changes/ticket28856 | 3 - 69 files changed, 319 insertions(+), 301 deletions(-) delete mode 100644 changes/bug21900 delete mode 100644 changes/bug23082 delete mode 100644 changes/bug24393 delete mode 100644 changes/bug24661 delete mode 100644 changes/bug24953 delete mode 100644 changes/bug25885 delete mode 100644 changes/bug27707 delete mode 100644 changes/bug27929 delete mode 100644 changes/bug28518 delete mode 100644 changes/bug28569 delete mode 100644 changes/bug28591 delete mode 100644 changes/bug28654 delete mode 100644 changes/bug28895 delete mode 100644 changes/bug28920 delete mode 100644 changes/bug28938 delete mode 100644 changes/bug28989 delete mode 100644 changes/bug28995 delete mode 100644 changes/doc28560 delete mode 100644 changes/doc28805 delete mode 100644 changes/document_version delete mode 100644 changes/feature27244 delete mode 100644 changes/feature27367 delete mode 100644 changes/prop297 delete mode 100644 changes/subsystems delete mode 100644 changes/ticket24805 delete mode 100644 changes/ticket24838 delete mode 100644 changes/ticket26360 delete mode 100644 changes/ticket26770 delete mode 100644 changes/ticket27167 delete mode 100644 changes/ticket27225 delete mode 100644 changes/ticket27325 delete mode 100644 changes/ticket27359 delete mode 100644 changes/ticket27402 delete mode 100644 changes/ticket27490 delete mode 100644 changes/ticket27549 delete mode 100644 changes/ticket27620 delete mode 100644 changes/ticket27625 delete mode 100644 changes/ticket27914 delete mode 100644 changes/ticket27993 delete mode 100644 changes/ticket28006 delete mode 100644 changes/ticket28007 delete mode 100644 changes/ticket28008 delete mode 100644 changes/ticket28009 delete mode 100644 changes/ticket28010 delete mode 100644 changes/ticket28011 delete mode 100644 changes/ticket28012 delete mode 100644 changes/ticket28058 delete mode 100644 changes/ticket28077 delete mode 100644 changes/ticket28100 delete mode 100644 changes/ticket28142 delete mode 100644 changes/ticket28179 delete mode 100644 changes/ticket28180 delete mode 100644 changes/ticket28266 delete mode 100644 changes/ticket28335 delete mode 100644 changes/ticket28362 delete mode 100644 changes/ticket28551 delete mode 100644 changes/ticket28624 delete mode 100644 changes/ticket28669 delete mode 100644 changes/ticket28757 delete mode 100644 changes/ticket28768 delete mode 100644 changes/ticket28839 delete mode 100644 changes/ticket28840 delete mode 100644 changes/ticket28843 delete mode 100644 changes/ticket28846 delete mode 100644 changes/ticket28847 delete mode 100644 changes/ticket28852 delete mode 100644 changes/ticket28853 delete mode 100644 changes/ticket28856 (limited to 'changes') diff --git a/ChangeLog b/ChangeLog index 090498c859..d6a72e2efd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,322 @@ +Changes in version 0.4.0.1-alpha - 2019-01-18 + blurb blurb blurb + + o Major features (battery management, client, dormant mode): + - When Tor is running as a client, and it is unused for a long time, + it can now enter a "dormant" state. When Tor is dormant, it avoids + network activity and CPU wakeups until it is reawoken either by a + user request or by a controller command. For more information, see + the configuration options starting with "Dormant". Implements + tickets 2149 and 28335. + - The client's memory of whether it is "dormant", and how long it + has spend idle, persists across invocations. Implements + ticket 28624. + - There is a DormantOnFirstStartup option that integrators can use + if they expect that in many cases, Tor will be installed but + not used. + + o Major features (bootstrap): + - Report the first connection to a relay as the earliest phases of + bootstrap progress, regardless of whether it's a connection for + building application circuits. This allows finer-grained reporting + of early progress than previously possible with the improvements + of ticket 27169. Closes tickets 27167 and 27103. Addresses + ticket 27308. + - Separately report the intermediate stage of having connected to a + proxy or pluggable transport, versus succesfully using that proxy + or pluggable transport to connect to a relay. Closes tickets 27100 + and 28884. + + o Major features (circuit padding): + - Implement preliminary support for the circuit padding portion of + Proposal 254. The implementation supports Adaptive Padding (aka + WTF-PAD) state machines for use between experimental clients and + relays. Support is also provided for APE-style state machines that + use probability distributions instead of histograms to specify + inter-packet delay. At the moment, Tor does not provide any + padding state machines that are used in normal operation -- this + feature exists solely for experimentation in this release. Closes + ticket 28142. + + o Major features (refactoring): + - Tor now uses an explicit list of its own subsystems when + initializing and shutting down. Previously, these systems were + managed implicitly though various places throughout the codebase. + (There still some subsystems using the old system.) Closes + ticket 28330. + + o Minor feature (bootstrap): + - When reporting bootstrap progress, stop distinguishing between + situations where it seems that only internal paths are available + and situations where it seems that external paths are available. + Previously, tor would often erroneously report that it had only + internal paths. Closes ticket 27402. + + o Minor features (Continuous Integration): + - Log Python version during each Travis CI job. Resolves + issue 28551. + + o Minor features (controller): + - Add a DROPOWNERSHIP command to undo the effects of TAKEOWNERSHIP. + Implements ticket 28843. + + o Minor features (developer tooling): + - Provide a git hook script to prevent "fixup!" and "squash!" + commits from ending up in master. Closes ticket 27993. + + o Minor features (directory authority): + - Directory authorities support a new consensus algorithm, under + which microdescriptor entries are encoded in a canonical form. + This improves their compressibility in transit and on the client. + Closes ticket 28266; implements proposal 298. + + o Minor features (directory authority, relay): + - Authorities now vote on a "StaleDesc" flag to indicate that a + relay's descriptor is so old that the relay should upload again + soon. Relays understand this flag, and treat it as a signal to + upload a new descriptor. This flag will eventually let us remove + the 'published' date from routerstatus entries, and save a great + deal of space in our consensus diffs. Closes ticket 26770; + implements proposal 293. + + o Minor features (fallback directory mirrors): + - Update the fallback whitelist based on operator opt-ins and opt- + outs. Closes ticket 24805, patch by Phoul. + - Accept fallbacks that deliver reasonably live consensuses. + (Consensuses that will become valid less than 24 hours in the + future, or that expired less than 24 hours ago.) Closes + ticket 28768. + - Accept relays that are a fuzzy match to a fallback whitelist + entry. If a relay matches at least one fingerprint, IPv4 address, + or IPv6 address in the fallback whitelist, it can become a + fallback. This reduces the work required to keep the list up to + date. Closes ticket 24838. + + o Minor features (FreeBSD): + - Warn relay operators if the "net.inet.ip.random_id" sysctl (IP ID + randomization) is disabled on their relay if it is running on + FreeBSD based operating systems. Closes ticket 28518. + + o Minor features (HTTP standards compliance): + - Don't send Content-Type: application/octet-stream for transparently + compressed documents, which confused browsers. Closes ticket 28100. + + o Minor features (ipv6): + - We add an option ClientAutoIPv6ORPort which makes clients randomly + prefer a node's IPv4 or IPv6 ORPort. The random preference is set + every time a node is loaded from a new consensus or bridge config. + Closes ticket 27490. Patch by Neel Chauhan. + - When using addrs_in_same_network_family(), check IPv6 subnets as + well as IPv4 ones where possible when a client chooses circuit + paths. Previously, we used this function only for IPv4 subnets. + Closes ticket 24393. Patch by Neel Chauhan. + + o Minor features (log messages): + - Improve log message in HSv3 service that could print out negative + revision counters. Closes ticket 27707. Patch by "ffmancera". + + o Minor features (memory usage): + - Store microdescriptor family lists with a more compact + representation to save memory. Closes ticket 27359. + - Tor clients no longer need to keep the full text of a consensus in + memory in order to parse it, or apply a diff to it. Instead, they + use mmap() to read the consensus files from disk. Closes + ticket 27244. + + o Minor features (parsing): + - Directory authorities now validate that router descriptors and + ExtraInfo documents are in a valid subset of UTF-8, and reject + them if not. Closes ticket 27367. + + o Minor features (performance): + - Avoid parsing the same protocol-versions string over and over in + summarize_protover_flags(). This should save us a huge number of + malloc calls on startup, and may reduce memory fragmentation with + some allocators. Closes ticket 27225. + - Remove a needless memset() call from get_token_arguments, thereby + speeding up the tokenization of directory objects by about 20%. + Closes ticket 28852. + - Replace parse_short_policy() with a faster implementation, to + improve microdescriptor parsing time. Closes ticket 28853. + - Speed up directory parsing a little by avoiding use of the non- + inlined strcmp_len() function. Closes ticket 28856. + - Speed up microdesriptor parsing by about 30%, to help improve + startup time. Closes ticket 28839. + + o Minor features (pluggable transports): + - Add support for emitting STATUS updates to Tor's control port from + a pluggable transport process. Closes ticket 28846. + - Add support for logging to Tor's logging subsystem from a + pluggable transport process. Closes ticket 28180 + + o Minor features (process management): + - Add new Process API for handling child processes. This new API + allows Tor to have bi-directional communication with child + processes on both Unix and Windows. Closes ticket 28179. + - Use the subsystem module to initialize and shut down the process + module. Closes ticket 28847. + + o Minor features (relay): + - When listing relay families, list them in canonical form including + the relay's own identity, and try to give a more useful set of + warnings. Part of ticket 28266 and proposal 298. + + o Minor features (required protocols): + - Tor no longer exits if it is missing a required protocol, if the + consensus that requires the protocol predates the release date of + the version of Tor. This change prevents Tor releases from exiting + because of an old cached consensus, on the theory that a newer + cached consensus might not require the protocol. Implements + proposal 297; closes ticket 27735. + + o Minor features (testing): + - Allow HeartbeatPeriod of less than 30 minutes in testing Tor + networks. Closes ticket 28840, patch by robgjansen + + o Minor bugfixes (client, bootstrap): + - When Tor's clock is behind the clocks on the authorities, allow + Tor to bootstrap successfully. Fixes bug 28591; bugfix + on 0.2.0.9-alpha. + + o Minor bugfixes (client, guard selection): + - When Tor's consensus has expired, but is still reasonably live, + use it to select guards. Fixes bug 24661; bugfix on 0.3.0.1-alpha. + + o Minor bugfixes (compilation): + - Fix missing headers required for proper detection of OpenBSD. Fixes + bug 28938; bugfix on 0.3.5.1-alpha. Patch from Kris Katterjohn. + + o Minor bugfixes (directory clients): + - Mark outdated dirservers when Tor only has a reasonably live + consensus. Fixes bug 28569; bugfix on 0.3.2.5-alpha. + + o Minor bugfixes (directory mirror): + - When Tor's clock is behind the clocks on the authorities, allow + Tor to serve future consensuses. Fixes bug 28654; bugfix + on 0.3.0.1-alpha. + + o Minor bugfixes (DNS): + - Gracefully handle empty or absent resolve.conf file by falling + back to using localhost DNS service and hoping it works. Fixes bug + 21900; bugfix on 0.2.1.10-alpha. + + o Minor bugfixes (fallback scripts): + - In updateFallbackDirs.py, call the filter file a "fallback list" + instead of a "whitelist" in check_existing mode. Fixes bug 24953; + bugfix on 0.3.0.3-alpha. + + o Minor bugfixes (guards): + - In count_acceptable_nodes(), check if we have at least one bridge + or guard node, and two non-guard nodes for a circuit. Previously, + we have added up the sum of all nodes with a descriptor, but that + could cause us to build circuits that fail if we had either too + many bridges, or not enough guard nodes. Fixes bug 25885; bugfix + on 0.3.6.1-alpha. Patch by Neel Chauhan. + + o Minor bugfixes (IPv6): + - Fix tor_ersatz_socketpair on IPv6-only systems. Previously, the + IPv6 socket was bound using an address family of AF_INET instead + of AF_INET6. Fixes bug 28995; bugfix on 0.3.5.1-alpha. Patch from + Kris Katterjohn. + + o Minor bugfixes (logging): + - Rework rep_hist_log_link_protocol_counts() to iterate through all + link protocol versions when logging incoming/outgoing connection + counts. Tor no longer skips version 5 and we don't have to + remember to update this function when new link protocol version is + developed. Fixes bug 28920; bugfix on 0.2.6.10. + + o Minor bugfixes (networking): + - Introduce additional checks into tor_addr_parse() to reject + certain incorrect inputs that previously were not detected. Fixes + bug 23082; bugfix on 0.2.0.10-alpha. + + o Minor bugfixes (onion service v3, client): + - Avoid a BUG() stacktrace in case a SOCKS connection is found + waiting for the descriptor while we do have it in the cache. There + is a rare case when this can happen. Now, tor will recover and + retry the descriptor. Fixes bug 28669; bugfix on 0.3.2.4-alpha. + + o Minor bugfixes (periodic events): + - Refrain from calling routerlist_remove_old_routers() from + check_descriptor_callback(). Instead, create a new periodic event + that will run once every hour even if Tor is not configured as + onion router. Fixes bug 27929; bugfix on 0.2.8.1-alpha. + + o Minor bugfixes (pluggable transports): + - Make sure that data is continously read from standard out and + error of the PT child-process to avoid deadlocking when the pipes' + buffer is full. Fixes bug 26360; bugfix on 0.2.3.6-alpha. + + o Minor bugfixes (unit tests): + - Instead of relying on hs_free_all() to clean up all onion service + objects we created in test_build_descriptors(), deallocate them + one by one. This lets Coverity know that we are not leaking memory + here and fixes CID 1442277. Fixes bug 28989; bugfix + on 0.3.5.1-alpha. + + o Minor bugfixes (usability): + - Stop saying "Your Guard ..." in pathbias_measure_{use,close}_rate() + as that confusingly suggests that mentioned guard node is under + control and responsibility of end user, which it is not. Fixes bug + 28895; bugfix on Tor 0.3.0.1-alpha. + + o Code simplification and refactoring: + - Reimplement NETINFO cell parsing and generation to rely on + trunnel-generated wire format handling code. Closes ticket 27325. + - Remove unnecessarily unsafe code from the rust macro cstr!. Closes + ticket 28077. + - Rework SOCKS wire format handling to rely on trunnel-generated + parsing/generation code. Resolves ticket 27620. + - Split out bootstrap progress reporting from control.c into a + separate file. Part of ticket 27402. + - The .may_include files that we use to describe our directory-by- + directory dependency structure now describe a noncircular + dependency graph over the directories that they cover. Our + checkIncludes.py tool now enforces this. Closes ticket 28362. + + o Documentation: + - Mention that you cannot add new Onion Service if Tor is already + running with Sandbox enabled. Closes ticket 28560. + - Improve ControlPort description in tor manpage to mention that it + accepts address/port pair, and can be used multiple times. Closes + ticket 28805. + - Document the exact output of "tor --version". Closes ticket 28889. + + o Removed features: + - Stop responding to 'GETINFO status/version/num-concurring' and + 'GETINFO status/version/num-versioning' control port commands, as + those were deprecated back in 0.2.0.30. Also stop listing them in + output of 'GETINFO info/names'. Resolves ticket 28757. + - The scripts used to generate and maintain the list of fallback + directories have been extracted into a new "fallback-scripts" + repository. Closes ticket 27914. + + o Testing: + - Run shellcheck for stuff in scripts/ directory. Closes + ticket 28058. + - Write some unit tests for tokenize_string() and get_next_token() + functions. Resolves ticket 27625. + + o Code simplification and refactoring (onion service v3): + - Consolidate the authorized client descriptor cookie computation + code from client and service into one function. Closes + ticket 27549. + + o Code simplification and refactoring (shell scripts): + - Cleanup scan-build.sh to silence shellcheck warnings. Closes + ticket 28007. + - Fix issues that shellcheck found in chutney-git-bisect.sh. + Resolves ticket 28006. + - Fix issues that shellcheck found in updateRustDependencies.sh. + Resolves ticket 28012. + - Fix shellcheck warnings in cov-diff script. Resolves issue 28009. + - Fix shellcheck warnings in run_calltool.sh. Resolves ticket 28011. + - Fix shellcheck warnings in run_trunnel.sh. Resolves issue 28010. + - Fix shellcheck warnings in scripts/test/coverage. Resolves + issue 28008. + + Changes in version 0.3.3.11 - 2018-01-07 Tor 0.3.3.11 backports numerous fixes from later versions of Tor. numerous fixes, including an important fix for anyone using OpenSSL diff --git a/changes/bug21900 b/changes/bug21900 deleted file mode 100644 index 686cb6c584..0000000000 --- a/changes/bug21900 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (DNS): - - Gracefully handle empty or absent resolve.conf file by falling - back to using localhost DNS service and hoping it works. Fixes - bug 21900; bugfix on 0.2.1.10-alpha. diff --git a/changes/bug23082 b/changes/bug23082 deleted file mode 100644 index fc4b52c364..0000000000 --- a/changes/bug23082 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (networking): - - Introduce additional checks into tor_addr_parse() to - reject certain incorrect inputs that previously were - not detected. Fixes bug 23082; bugfix on 0.2.0.10-alpha. diff --git a/changes/bug24393 b/changes/bug24393 deleted file mode 100644 index e190192319..0000000000 --- a/changes/bug24393 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor features (ipv6): - - When using addrs_in_same_network_family(), check IPv6 subnets as well as - IPv4 ones where possible when a client chooses circuit paths. Previously, - we used this function only for IPv4 subnets. Closes ticket 24393. Patch - by Neel Chauhan. - diff --git a/changes/bug24661 b/changes/bug24661 deleted file mode 100644 index a915a93e0e..0000000000 --- a/changes/bug24661 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (client, guard selection): - - When Tor's consensus has expired, but is still reasonably live, use it - to select guards. Fixes bug 24661; bugfix on 0.3.0.1-alpha. diff --git a/changes/bug24953 b/changes/bug24953 deleted file mode 100644 index d142dfd6cc..0000000000 --- a/changes/bug24953 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (fallback scripts): - - In updateFallbackDirs.py, call the filter file a "fallback list" - instead of a "whitelist" in check_existing mode. - Fixes bug 24953; bugfix on 0.3.0.3-alpha. diff --git a/changes/bug25885 b/changes/bug25885 deleted file mode 100644 index 1b89acfe06..0000000000 --- a/changes/bug25885 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor bugfixes (guards): - - In count_acceptable_nodes(), check if we have at least one bridge - or guard node, and two non-guard nodes for a circuit. Previously, - we have added up the sum of all nodes with a descriptor, but that - could cause us to build circuits that fail if we had either too - many bridges, or not enough guard nodes. Fixes bug 25885; bugfix - on 0.3.6.1-alpha. Patch by Neel Chauhan. diff --git a/changes/bug27707 b/changes/bug27707 deleted file mode 100644 index e114222741..0000000000 --- a/changes/bug27707 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (log messages): - - Improve log message in HSv3 service that could print out negative - revision counters. Closes ticket 27707. Patch by "ffmancera". \ No newline at end of file diff --git a/changes/bug27929 b/changes/bug27929 deleted file mode 100644 index dab57a2eca..0000000000 --- a/changes/bug27929 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (periodic events): - - Refrain from calling routerlist_remove_old_routers() from - check_descriptor_callback(). Instead, create a new periodic - event that will run once every hour even if Tor is not configured - as onion router. Fixes bug 27929; bugfix on 0.2.8.1-alpha. diff --git a/changes/bug28518 b/changes/bug28518 deleted file mode 100644 index d7ebab29bb..0000000000 --- a/changes/bug28518 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (FreeBSD): - - Warn relay operators if the "net.inet.ip.random_id" sysctl (IP ID - randomization) is disabled on their relay if it is running on FreeBSD - based operating systems. Closes ticket 28518. diff --git a/changes/bug28569 b/changes/bug28569 deleted file mode 100644 index 45a57a80ae..0000000000 --- a/changes/bug28569 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (unit tests, directory clients): - - Mark outdated dirservers when Tor only has a reasonably live consensus. - Fixes bug 28569; bugfix on 0.3.2.5-alpha. diff --git a/changes/bug28591 b/changes/bug28591 deleted file mode 100644 index 3a1c96ac16..0000000000 --- a/changes/bug28591 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (client, bootstrap): - - When Tor's clock is behind the clocks on the authorities, allow Tor to - bootstrap successfully. Fixes bug 28591; bugfix on 0.2.0.9-alpha. - diff --git a/changes/bug28654 b/changes/bug28654 deleted file mode 100644 index 4ca843309f..0000000000 --- a/changes/bug28654 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (directory mirror): - - When Tor's clock is behind the clocks on the authorities, allow Tor to - serve future consensuses. Fixes bug 28654; bugfix on 0.3.0.1-alpha. diff --git a/changes/bug28895 b/changes/bug28895 deleted file mode 100644 index 25fb167b2e..0000000000 --- a/changes/bug28895 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (usability): - - Stop saying "Your Guard ..." in pathbias_measure_{use,close}_rate() - as that confusingly suggests that mentioned guard node is under control - and responsibility of end user, which it is not. Fixes bug 28895; - bugfix on Tor 0.3.0.1-alpha. diff --git a/changes/bug28920 b/changes/bug28920 deleted file mode 100644 index e698686a6d..0000000000 --- a/changes/bug28920 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (logging): - - Rework rep_hist_log_link_protocol_counts() to iterate through all link - protocol versions when logging incoming/outgoing connection counts. Tor - no longer skips version 5 and we don't have to remember to update this - function when new link protocol version is developed. Fixes bug 28920; - bugfix on 0.2.6.10. diff --git a/changes/bug28938 b/changes/bug28938 deleted file mode 100644 index de6c5f7b79..0000000000 --- a/changes/bug28938 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (compilation): - - Fix missing headers required for proper detection of - OpenBSD. Fixes bug 28938; bugfix on 0.3.5.1-alpha. - Patch from Kris Katterjohn. diff --git a/changes/bug28989 b/changes/bug28989 deleted file mode 100644 index 3e3ccccaf3..0000000000 --- a/changes/bug28989 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (unit tests): - - Instead of relying on hs_free_all() to clean up all onion service - objects we created in test_build_descriptors(), deallocate - them one by one. This lets Coverity know that we are not leaking memory - here and fixes CID 1442277. Fixes bug 28989; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug28995 b/changes/bug28995 deleted file mode 100644 index f76b6a085a..0000000000 --- a/changes/bug28995 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfix (IPv6): - Fix tor_ersatz_socketpair on IPv6-only systems. Previously, - the IPv6 socket was bound using an address family of AF_INET - instead of AF_INET6. Fixes bug 28995; bugfix on 0.3.5.1-alpha. - Patch from Kris Katterjohn. diff --git a/changes/doc28560 b/changes/doc28560 deleted file mode 100644 index c3356bda0a..0000000000 --- a/changes/doc28560 +++ /dev/null @@ -1,3 +0,0 @@ - o Documentation (hidden service manpage, sandbox): - - Mention that you cannot add new Onion Service if Tor is already - running with Sandbox enabled. Closes ticket 28560. diff --git a/changes/doc28805 b/changes/doc28805 deleted file mode 100644 index 6c9fea44fa..0000000000 --- a/changes/doc28805 +++ /dev/null @@ -1,4 +0,0 @@ - o Documentation (manpage): - - Improve ControlPort description in tor manpage to mention that it - accepts address/port pair, and can be used multiple times. Closes ticket - 28805. diff --git a/changes/document_version b/changes/document_version deleted file mode 100644 index a45992b6b5..0000000000 --- a/changes/document_version +++ /dev/null @@ -1,2 +0,0 @@ - o Documentation: - - Document the exact output of "tor --version". Closes ticket 28889. diff --git a/changes/feature27244 b/changes/feature27244 deleted file mode 100644 index a4debbbe53..0000000000 --- a/changes/feature27244 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (memory usage): - - Tor clients no longer need to keep the full text of a consensus in - memory in order to parse it, or apply a diff to it. Instead, they - use mmap() to read the consensus files from disk. Closes ticket - 27244. diff --git a/changes/feature27367 b/changes/feature27367 deleted file mode 100644 index 99c0839621..0000000000 --- a/changes/feature27367 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (parsing): - - Directory authorities now validate that router descriptors and ExtraInfo - documents are in a valid subset of UTF-8, and reject them if not. - Closes ticket 27367. diff --git a/changes/prop297 b/changes/prop297 deleted file mode 100644 index 4f93b232d2..0000000000 --- a/changes/prop297 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (required protocols): - - Tor no longer exits if it is missing a required protocol, if the - consensus that requires the protocol predates the release date of the - version of Tor. This change prevents Tor releases from exiting because - of an old cached consensus, on the theory that a newer cached - consensus might not require the protocol. Implements proposal 297; - closes ticket 27735. diff --git a/changes/subsystems b/changes/subsystems deleted file mode 100644 index a51fb8e2b1..0000000000 --- a/changes/subsystems +++ /dev/null @@ -1,6 +0,0 @@ - o Major features (refactoring): - - Tor now uses an explicit list of its own subsystems when initializing - and shutting down. Previously, these systems were managed implicitly - though various places throughout the codebase. (There still some - subsystems using the old system.) - Closes ticket 28330. diff --git a/changes/ticket24805 b/changes/ticket24805 deleted file mode 100644 index 4ba6f6ecd4..0000000000 --- a/changes/ticket24805 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (fallback directory list): - - Update the fallback whitelist based on operator opt-ins and opt-outs. - Closes ticket 24805, patch by Phoul. diff --git a/changes/ticket24838 b/changes/ticket24838 deleted file mode 100644 index d068e31b91..0000000000 --- a/changes/ticket24838 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor features (fallback directory mirrors): - - Accept relays that are a fuzzy match to a fallback whitelist entry. - If a relay matches at least one fingerprint, IPv4 address, or IPv6 - address in the fallback whitelist, it can become a fallback. This - reduces the work required to keep the list up to date. - Closes ticket 24838. diff --git a/changes/ticket26360 b/changes/ticket26360 deleted file mode 100644 index 80afbd1c17..0000000000 --- a/changes/ticket26360 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (pluggable transports): - - Make sure that data is continously read from standard out and error of the - PT child-process to avoid deadlocking when the pipes' buffer is full. - Fixes bug 26360; bugfix on 0.2.3.6-alpha. diff --git a/changes/ticket26770 b/changes/ticket26770 deleted file mode 100644 index 7f3e92e9dd..0000000000 --- a/changes/ticket26770 +++ /dev/null @@ -1,8 +0,0 @@ - o Minor features (directory authority, relay): - - Authorities now vote on a "StaleDesc" flag to indicate that a relay's - descriptor is so old that the relay should upload again soon. Relays - understand this flag, and treat it as a signal to upload a new - descriptor. This flag will eventually let us remove the 'published' - date from routerstatus entries, and save a great deal of space in our - consensus diffs. Closes ticket 26770; implements proposal 293. - diff --git a/changes/ticket27167 b/changes/ticket27167 deleted file mode 100644 index 81c66630c8..0000000000 --- a/changes/ticket27167 +++ /dev/null @@ -1,11 +0,0 @@ - o Major features (bootstrap): - - Report the first connection to a relay as the earliest phases of - bootstrap progress, regardless of whether it's a connection for - building application circuits. This allows finer-grained - reporting of early progress than previously possible with the - improvements of ticket 27169. Closes tickets 27167 and 27103. - Addresses ticket 27308. - - Separately report the intermediate stage of having connected to - a proxy or pluggable transport, versus succesfully using that - proxy or pluggable transport to connect to a relay. Closes - tickets 27100 and 28884. diff --git a/changes/ticket27225 b/changes/ticket27225 deleted file mode 100644 index 4c05a269d6..0000000000 --- a/changes/ticket27225 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (performance): - - Avoid parsing the same protocol-versions string over and over - in summarize_protover_flags(). This should save us a huge number - of malloc calls on startup, and may reduce memory fragmentation with - some allocators. Closes ticket 27225. diff --git a/changes/ticket27325 b/changes/ticket27325 deleted file mode 100644 index 2cf2bb7d69..0000000000 --- a/changes/ticket27325 +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring: - - Reimplement NETINFO cell parsing and generation to rely on - trunnel-generated wire format handling code. Closes ticket - 27325. diff --git a/changes/ticket27359 b/changes/ticket27359 deleted file mode 100644 index bddc90634d..0000000000 --- a/changes/ticket27359 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (memory usage): - - Store microdescriptor family lists with a more compact representation - to save memory. Closes ticket 27359. diff --git a/changes/ticket27402 b/changes/ticket27402 deleted file mode 100644 index b79fb56760..0000000000 --- a/changes/ticket27402 +++ /dev/null @@ -1,10 +0,0 @@ - o Minor feature (bootstrap): - - When reporting bootstrap progress, stop distinguishing between - situations where it seems that only internal paths are available - and situations where it seems that external paths are available. - Previously, tor would often erroneously report that it had only - internal paths. Closes ticket 27402. - - o Code simplification and refactoring: - - Split out bootstrap progress reporting from control.c into a - separate file. Part of ticket 27402. diff --git a/changes/ticket27490 b/changes/ticket27490 deleted file mode 100644 index 523477dfea..0000000000 --- a/changes/ticket27490 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor features (ipv6): - - We add an option ClientAutoIPv6ORPort which makes clients randomly - prefer a node's IPv4 or IPv6 ORPort. The random preference is set - every time a node is loaded from a new consensus or bridge config. - Closes ticket 27490. Patch by Neel Chauhan. - diff --git a/changes/ticket27549 b/changes/ticket27549 deleted file mode 100644 index 51d0f24757..0000000000 --- a/changes/ticket27549 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring (hidden service v3): - - Consolidate the authorized client descriptor cookie computation code - from client and service into one function. Closes ticket 27549. diff --git a/changes/ticket27620 b/changes/ticket27620 deleted file mode 100644 index 6c491696d0..0000000000 --- a/changes/ticket27620 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Rework SOCKS wire format handling to rely on trunnel-generated - parsing/generation code. Resolves ticket 27620. diff --git a/changes/ticket27625 b/changes/ticket27625 deleted file mode 100644 index 33d40adf34..0000000000 --- a/changes/ticket27625 +++ /dev/null @@ -1,4 +0,0 @@ - o Testing: - - Write some unit tests for tokenize_string() and - get_next_token() functions. Resolves ticket 27625. - diff --git a/changes/ticket27914 b/changes/ticket27914 deleted file mode 100644 index 433e9657af..0000000000 --- a/changes/ticket27914 +++ /dev/null @@ -1,4 +0,0 @@ - o Removed features: - - The scripts used to generate and maintain the list of fallback - directories have been extracted into a new "fallback-scripts" - repository. Closes ticket 27914. diff --git a/changes/ticket27993 b/changes/ticket27993 deleted file mode 100644 index 78ee7c2054..0000000000 --- a/changes/ticket27993 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (developer tooling): - - Provide git hook script to prevent "fixup!" and "squash!" commits from - ending up in master. Closes ticket 27993. diff --git a/changes/ticket28006 b/changes/ticket28006 deleted file mode 100644 index 95a4b2cae4..0000000000 --- a/changes/ticket28006 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Fix issues that shellcheck found in chutney-git-bisect.sh. - Resolves ticket 28006. diff --git a/changes/ticket28007 b/changes/ticket28007 deleted file mode 100644 index 1ac87862eb..0000000000 --- a/changes/ticket28007 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Cleanup scan-build.sh to silence shellcheck warnings. - Closes ticket 28007. diff --git a/changes/ticket28008 b/changes/ticket28008 deleted file mode 100644 index 1f0de1a14d..0000000000 --- a/changes/ticket28008 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Fix shellcheck warnings in scripts/test/coverage. Resolves issue - 28008. diff --git a/changes/ticket28009 b/changes/ticket28009 deleted file mode 100644 index 1d986d4211..0000000000 --- a/changes/ticket28009 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Fix shellcheck warnings in cov-diff script. Resolves issue - 28009. diff --git a/changes/ticket28010 b/changes/ticket28010 deleted file mode 100644 index 4fca17d022..0000000000 --- a/changes/ticket28010 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Fix shellcheck warnings in run_trunnel.sh. Resolves issue - 28010. diff --git a/changes/ticket28011 b/changes/ticket28011 deleted file mode 100644 index 5efc3c917b..0000000000 --- a/changes/ticket28011 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Fix shellcheck warnings in run_calltool.sh. Resolves - ticket 28011. diff --git a/changes/ticket28012 b/changes/ticket28012 deleted file mode 100644 index b2fe83e02a..0000000000 --- a/changes/ticket28012 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Fix issues that shellcheck found in updateRustDependencies.sh. - Resolves ticket 28012. diff --git a/changes/ticket28058 b/changes/ticket28058 deleted file mode 100644 index 00ac595864..0000000000 --- a/changes/ticket28058 +++ /dev/null @@ -1,2 +0,0 @@ - o Testing: - - Run shellcheck for stuff in scripts/ directory. Closes ticket 28058. diff --git a/changes/ticket28077 b/changes/ticket28077 deleted file mode 100644 index 2b5afb1678..0000000000 --- a/changes/ticket28077 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Remove unnecessarily unsafe code from the rust macro cstr!. Closes - ticket 28077. diff --git a/changes/ticket28100 b/changes/ticket28100 deleted file mode 100644 index b8e3271013..0000000000 --- a/changes/ticket28100 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (HTTP standards compliance): - - Don't send Content-Type: application/octet-stream for transparently - compressed documents, which confused browsers. Closes ticket 28100. diff --git a/changes/ticket28142 b/changes/ticket28142 deleted file mode 100644 index b74b2bd47e..0000000000 --- a/changes/ticket28142 +++ /dev/null @@ -1,10 +0,0 @@ - o Major features (circuit padding): - - Implement preliminary support for the circuit padding portion of - Proposal 254. The implementation supports Adaptive Padding (aka - WTF-PAD) state machines for use between experimental clients and - relays. Support is also provided for APE-style state machines that - use probability distributions instead of histograms to specify - inter-packet delay. At the moment, Tor does not provide any padding - state machines that are used in normal operation -- this feature - exists solely for experimentation in this release. Closes - ticket 28142. diff --git a/changes/ticket28179 b/changes/ticket28179 deleted file mode 100644 index f548c4a79a..0000000000 --- a/changes/ticket28179 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (process): - - Add new Process API for handling child processes. This - new API allows Tor to have bi-directional - communication with child processes on both Unix and Windows. - Closes ticket 28179. diff --git a/changes/ticket28180 b/changes/ticket28180 deleted file mode 100644 index 59de1c6251..0000000000 --- a/changes/ticket28180 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (pluggable transports): - - Add support for logging to Tor's logging subsystem from a pluggable - transport process. Closes ticket 28180 diff --git a/changes/ticket28266 b/changes/ticket28266 deleted file mode 100644 index e0bc171080..0000000000 --- a/changes/ticket28266 +++ /dev/null @@ -1,10 +0,0 @@ - o Minor features (directory authority): - - Directory authorities support a new consensus algorithm, - under which microdescriptor entries are encoded in a canonical - form. This improves their compressibility in transit and on the client. - Closes ticket 28266; implements proposal 298. - - o Minor features (relay): - - When listing relay families, list them in canonical form including the - relay's own identity, and try to give a more useful set of warnings. - Part of ticket 28266 and proposal 298. diff --git a/changes/ticket28335 b/changes/ticket28335 deleted file mode 100644 index eecf7c7fd9..0000000000 --- a/changes/ticket28335 +++ /dev/null @@ -1,7 +0,0 @@ - o Major features (client): - - When Tor is running as a client, and it is unused for a long time, it - can now enter a "dormant" state. When Tor is dormant, it avoids - network activity and CPU wakeups until it is reawoken either by a user - request or by a controller command. For more information, see - the configuration options starting with "Dormant". Implements tickets - 2149 and 28335. diff --git a/changes/ticket28362 b/changes/ticket28362 deleted file mode 100644 index 4ac22d50f2..0000000000 --- a/changes/ticket28362 +++ /dev/null @@ -1,6 +0,0 @@ - o Code simplification and refactoring: - - The .may_include files that we use to describe our - directory-by-directory dependency structure now describe a noncircular - dependency graph over the directories that they cover. - Our checkIncludes.py tool now enforces this. - Closes ticket 28362. diff --git a/changes/ticket28551 b/changes/ticket28551 deleted file mode 100644 index 46ba9d713b..0000000000 --- a/changes/ticket28551 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (Continuous Integration): - - Log Python version during each Travis CI job. Resolves issue - 28551. diff --git a/changes/ticket28624 b/changes/ticket28624 deleted file mode 100644 index 353f962be9..0000000000 --- a/changes/ticket28624 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (battery management, client, dormant mode): - - The client's memory of whether it is "dormant", and how long it has - spend idle, persists across invocations. Implements ticket 28624. - - There is a DormantOnFirstStartup option that integrators can use if - they expect that in many cases, Tor will be installed but not used. diff --git a/changes/ticket28669 b/changes/ticket28669 deleted file mode 100644 index 32c6114ffc..0000000000 --- a/changes/ticket28669 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfix (hidden service v3, client): - - Avoid a BUG() stacktrace in case a SOCKS connection is found waiting for - the descriptor while we do have it in the cache. There is a rare case - when this can happen. Now, tor will recover and retry the descriptor. - Fixes bug 28669; bugfix on 0.3.2.4-alpha. - diff --git a/changes/ticket28757 b/changes/ticket28757 deleted file mode 100644 index 62c6d099ff..0000000000 --- a/changes/ticket28757 +++ /dev/null @@ -1,5 +0,0 @@ - o Removed features: - - Stop responding to 'GETINFO status/version/num-concurring' and - 'GETINFO status/version/num-versioning' control port commands, as those - were deprecated back in 0.2.0.30. Also stop listing them in output of - 'GETINFO info/names'. Resolves ticket 28757. diff --git a/changes/ticket28768 b/changes/ticket28768 deleted file mode 100644 index 27d90febc8..0000000000 --- a/changes/ticket28768 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (fallback directory mirrors): - - Accept fallbacks that deliver reasonably live consensuses. - (Consensuses that will become valid less than 24 hours in the future, - or that expired less than 24 hours ago.) Closes ticket 28768. diff --git a/changes/ticket28839 b/changes/ticket28839 deleted file mode 100644 index e9f81dc405..0000000000 --- a/changes/ticket28839 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (performance): - - Speed up microdesriptor parsing by about 30%, to help - improve startup time. Closes ticket 28839. diff --git a/changes/ticket28840 b/changes/ticket28840 deleted file mode 100644 index 05d3fbb94c..0000000000 --- a/changes/ticket28840 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (testing): - - Allow HeartbeatPeriod of less than 30 minutes in testing Tor networks. - Closes ticket 28840, patch by robgjansen diff --git a/changes/ticket28843 b/changes/ticket28843 deleted file mode 100644 index 00905293c4..0000000000 --- a/changes/ticket28843 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (controller): - - Add a DROPOWNERSHIP command to undo the effects of TAKEOWNERSHIP. - Implements ticket 28843. diff --git a/changes/ticket28846 b/changes/ticket28846 deleted file mode 100644 index efb5b9938e..0000000000 --- a/changes/ticket28846 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (pluggable transports): - - Add support for emitting STATUS updates to Tor's control port from a - pluggable transport process. Closes ticket 28846. diff --git a/changes/ticket28847 b/changes/ticket28847 deleted file mode 100644 index 63100c5813..0000000000 --- a/changes/ticket28847 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (process): - - Use the subsystem module to initialize and shut down the process module. - Closes ticket 28847. diff --git a/changes/ticket28852 b/changes/ticket28852 deleted file mode 100644 index a58cc3ba0e..0000000000 --- a/changes/ticket28852 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (performance): - - Remove a needless memset() call from get_token_arguments, - thereby speeding up the tokenization of directory objects by about - 20%. Closes ticket 28852. diff --git a/changes/ticket28853 b/changes/ticket28853 deleted file mode 100644 index e76f6bd8c9..0000000000 --- a/changes/ticket28853 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (performance): - - Replace parse_short_policy() with a faster implementation, to improve - microdescriptor parsing time. Closes ticket 28853. diff --git a/changes/ticket28856 b/changes/ticket28856 deleted file mode 100644 index b136470494..0000000000 --- a/changes/ticket28856 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (performance): - - Speed up directory parsing a little by avoiding use of the - non-inlined strcmp_len() function. Closes ticket 28856. -- cgit v1.2.3-54-g00ecf From d3b122485e09302f7befd43bef59e0e8f09142f0 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 13 Dec 2018 17:22:43 -0500 Subject: Add a changes file for 28837 (OpenSSL sha3) --- changes/ticket28837 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket28837 (limited to 'changes') diff --git a/changes/ticket28837 b/changes/ticket28837 new file mode 100644 index 0000000000..3bc8f12597 --- /dev/null +++ b/changes/ticket28837 @@ -0,0 +1,4 @@ + o Minor features (performance): + - Use OpenSSL's implementations of SHA3 when available (in OpenSSL 1.1.1 + and later), since they tend to be faster than tiny-keccak. Closes + ticket 28837. -- cgit v1.2.3-54-g00ecf From 88818eacbdcbdd1fddb3452c3eddf8fba3f26e9c Mon Sep 17 00:00:00 2001 From: rl1987 Date: Fri, 18 Jan 2019 13:49:30 +0200 Subject: Cleanup shellcheck warnings in autogen.sh --- autogen.sh | 5 +++-- changes/ticket26069 | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 changes/ticket26069 (limited to 'changes') diff --git a/autogen.sh b/autogen.sh index 276dd4047c..63ef6d49ef 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,9 +1,9 @@ #!/bin/sh -if [ -x "`which autoreconf 2>/dev/null`" ] ; then +if command -v autoreconf; then opt="-i -f -W all,error" - for i in $@; do + for i in "$@"; do case "$i" in -v) opt="${opt} -v" @@ -11,6 +11,7 @@ if [ -x "`which autoreconf 2>/dev/null`" ] ; then esac done + # shellcheck disable=SC2086 exec autoreconf $opt fi diff --git a/changes/ticket26069 b/changes/ticket26069 new file mode 100644 index 0000000000..caed9be348 --- /dev/null +++ b/changes/ticket26069 @@ -0,0 +1,2 @@ + o Code simplification and refactoring (shell scripts): + - Cleanup autogen.sh to silence shellcheck warnings. Closes ticket 26069. -- cgit v1.2.3-54-g00ecf From 2529b29a75e24dcc1a6c92ef8f19a5916028a63f Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sat, 19 Jan 2019 17:39:48 +0200 Subject: Fix shellcheck warning SC2145 in torify script --- changes/ticket29070 | 2 ++ contrib/client-tools/torify | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 changes/ticket29070 (limited to 'changes') diff --git a/changes/ticket29070 b/changes/ticket29070 new file mode 100644 index 0000000000..2716915359 --- /dev/null +++ b/changes/ticket29070 @@ -0,0 +1,2 @@ + o Code simplification and refactoring (shell scripts): + - Fix shellcheck warning in torify script. Resolves issue 29070. diff --git a/contrib/client-tools/torify b/contrib/client-tools/torify index 54acfed654..ac4c9b5c7f 100755 --- a/contrib/client-tools/torify +++ b/contrib/client-tools/torify @@ -53,7 +53,7 @@ pathfind() { if pathfind torsocks; then exec torsocks "$@" - echo "$0: Failed to exec torsocks $@" >&2 + echo "$0: Failed to exec torsocks $*" >&2 exit 1 else echo "$0: torsocks not found in your PATH. Perhaps it isn't installed? (tsocks is no longer supported, for security reasons.)" >&2 -- cgit v1.2.3-54-g00ecf From 00fff96e4884e295a767532aa570abf8d27e75ee Mon Sep 17 00:00:00 2001 From: rl1987 Date: Tue, 22 Jan 2019 15:14:16 +0200 Subject: Fix shellcheck warning in test_rebind.sh --- changes/bug29063 | 2 ++ src/test/test_rebind.sh | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 changes/bug29063 (limited to 'changes') diff --git a/changes/bug29063 b/changes/bug29063 new file mode 100644 index 0000000000..8cbcbebc6e --- /dev/null +++ b/changes/bug29063 @@ -0,0 +1,2 @@ + o Code simplification and refactoring (shell scripts): + - Fix issues shellcheck found in test_rebind.sh. Resolves issue 29063. diff --git a/src/test/test_rebind.sh b/src/test/test_rebind.sh index 498072de35..a8f07c7c1e 100755 --- a/src/test/test_rebind.sh +++ b/src/test/test_rebind.sh @@ -15,10 +15,15 @@ fi exitcode=0 tmpdir= -clean () { test -n "$tmpdir" && test -d "$tmpdir" && rm -rf "$tmpdir" || :; } +clean () { + if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then + rm -rf "$tmpdir" + fi +} + trap clean EXIT HUP INT TERM -tmpdir="`mktemp -d -t tor_rebind_test.XXXXXX`" +tmpdir="$(mktemp -d -t tor_rebind_test.XXXXXX)" if [ -z "$tmpdir" ]; then echo >&2 mktemp failed exit 2 -- cgit v1.2.3-54-g00ecf From 6243133a71e816ba9a462c9fa667c63729483627 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 21 Jan 2019 12:36:33 +0200 Subject: Fix intermittent failures of test_circuitpadding_wronghop(). We fix it by disabling the scheduling of actual padding. Fixes #29122. --- changes/bug29122 | 3 +++ src/test/test_circuitpadding.c | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 changes/bug29122 (limited to 'changes') diff --git a/changes/bug29122 b/changes/bug29122 new file mode 100644 index 0000000000..020052ff8f --- /dev/null +++ b/changes/bug29122 @@ -0,0 +1,3 @@ + o Minor bugfixes (unit tests): + - Fix intermittent failures on an adaptive padding unittest. Fixes bug + 29122; bugfix on 0.4.0.1-alpha diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c index f4d003969e..61bd174e6c 100644 --- a/src/test/test_circuitpadding.c +++ b/src/test/test_circuitpadding.c @@ -1239,6 +1239,10 @@ test_circuitpadding_wronghop(void *arg) MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); + /* Mock this function so that our cell counting tests don't get confused by + * padding that gets sent by scheduled timers. */ + MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); + client_side = (circuit_t *)origin_circuit_new(); dummy_channel.cmux = circuitmux_alloc(); relay_side = (circuit_t *)new_fake_orcirc(&dummy_channel, -- cgit v1.2.3-54-g00ecf From 99fffc6c2fbc00cdeb9edd07ebb580f55d0a3513 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Mon, 21 Jan 2019 13:01:52 +0200 Subject: Add a pre-commit hook that runs code and changelog entry formatting checks --- changes/feature28976 | 4 ++++ scripts/maint/pre-commit.git-hook | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 changes/feature28976 create mode 100755 scripts/maint/pre-commit.git-hook (limited to 'changes') diff --git a/changes/feature28976 b/changes/feature28976 new file mode 100644 index 0000000000..c7ebc207f7 --- /dev/null +++ b/changes/feature28976 @@ -0,0 +1,4 @@ + o Minor features (developer tooling): + - Provide a git pre-commit hook that disallows commiting if we have any + failures in our code and changelog formatting checks. It is now available + in scripts/maint/pre-commit.git-hook. Implements feature 28976. diff --git a/scripts/maint/pre-commit.git-hook b/scripts/maint/pre-commit.git-hook new file mode 100755 index 0000000000..0868559606 --- /dev/null +++ b/scripts/maint/pre-commit.git-hook @@ -0,0 +1,23 @@ +#!/bin/bash +# +# To install this script, copy it to .git/hooks/pre-commit in local copy of +# tor git repo and make sure it has permission to execute. +# +# This is pre-commit git hook script that prevents commiting your changeset if +# it fails our code formatting or changelog entry formatting checkers. + +workdir=$(git rev-parse --show-toplevel) + +cd "$workdir" || exit 1 + +python scripts/maint/lintChanges.py ./changes + +perl scripts/maint/checkSpace.pl -C \ +src/lib/*/*.[ch] \ +src/core/*/*.[ch] \ +src/feature/*/*.[ch] \ +src/app/*/*.[ch] \ +src/test/*.[ch] \ +src/test/*/*.[ch] \ +src/tools/*.[ch] + -- cgit v1.2.3-54-g00ecf From c985940de9ec743cbb3e9a3e32fd482bd859c9ed Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Mon, 14 Jan 2019 14:09:53 -0500 Subject: Add version 3 onion service support to HSFETCH --- changes/ticket25417 | 4 ++++ src/feature/control/control.c | 26 ++++++++++++++++++++------ src/feature/hs/hs_client.c | 18 ++++++++++++++++++ src/feature/hs/hs_client.h | 4 ++++ src/feature/hs/hs_control.c | 14 ++++++++++++++ src/feature/hs/hs_control.h | 4 ++++ 6 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 changes/ticket25417 (limited to 'changes') diff --git a/changes/ticket25417 b/changes/ticket25417 new file mode 100644 index 0000000000..41f2acc988 --- /dev/null +++ b/changes/ticket25417 @@ -0,0 +1,4 @@ + o Minor features (controller): + - Add onion service version 3 support to HSFETCH. Previously, only + version 2 onion services were supported. Closes ticket 25417. + Patch by Neel Chauhan diff --git a/src/feature/control/control.c b/src/feature/control/control.c index 170037e060..d7299a4cf6 100644 --- a/src/feature/control/control.c +++ b/src/feature/control/control.c @@ -4426,6 +4426,8 @@ handle_control_hsfetch(control_connection_t *conn, uint32_t len, static const char *v2_str = "v2-"; const size_t v2_str_len = strlen(v2_str); rend_data_t *rend_query = NULL; + ed25519_public_key_t v3_pk; + uint32_t version; /* Make sure we have at least one argument, the HSAddress. */ args = getargs_helper(hsfetch_command, conn, body, 1, -1); @@ -4438,6 +4440,7 @@ handle_control_hsfetch(control_connection_t *conn, uint32_t len, /* Test if it's an HS address without the .onion part. */ if (rend_valid_v2_service_id(arg1)) { hsaddress = arg1; + version = HS_VERSION_TWO; } else if (strcmpstart(arg1, v2_str) == 0 && rend_valid_descriptor_id(arg1 + v2_str_len) && base32_decode(digest, sizeof(digest), arg1 + v2_str_len, @@ -4445,6 +4448,11 @@ handle_control_hsfetch(control_connection_t *conn, uint32_t len, /* We have a well formed version 2 descriptor ID. Keep the decoded value * of the id. */ desc_id = digest; + version = HS_VERSION_TWO; + } else if (hs_address_is_valid(arg1)) { + hsaddress = arg1; + version = HS_VERSION_THREE; + hs_parse_address(hsaddress, &v3_pk, NULL, NULL); } else { connection_printf_to_buf(conn, "513 Invalid argument \"%s\"\r\n", arg1); @@ -4481,11 +4489,13 @@ handle_control_hsfetch(control_connection_t *conn, uint32_t len, } } - rend_query = rend_data_client_create(hsaddress, desc_id, NULL, - REND_NO_AUTH); - if (rend_query == NULL) { - connection_printf_to_buf(conn, "551 Error creating the HS query\r\n"); - goto done; + if (version == HS_VERSION_TWO) { + rend_query = rend_data_client_create(hsaddress, desc_id, NULL, + REND_NO_AUTH); + if (rend_query == NULL) { + connection_printf_to_buf(conn, "551 Error creating the HS query\r\n"); + goto done; + } } /* Using a descriptor ID, we force the user to provide at least one @@ -4504,7 +4514,11 @@ handle_control_hsfetch(control_connection_t *conn, uint32_t len, /* Trigger the fetch using the built rend query and possibly a list of HS * directory to use. This function ignores the client cache thus this will * always send a fetch command. */ - rend_client_fetch_v2_desc(rend_query, hsdirs); + if (version == HS_VERSION_TWO) { + rend_client_fetch_v2_desc(rend_query, hsdirs); + } else if (version == HS_VERSION_THREE) { + hs_control_hsfetch_command(&v3_pk, hsdirs); + } done: SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c index 5fded92fe3..7dc856ae54 100644 --- a/src/feature/hs/hs_client.c +++ b/src/feature/hs/hs_client.c @@ -459,6 +459,24 @@ fetch_v3_desc, (const ed25519_public_key_t *onion_identity_pk)) return directory_launch_v3_desc_fetch(onion_identity_pk, hsdir_rs); } +/* With a given onion_identity_pk, fetch its descriptor. If + * hsdirs is specified, use the directory servers specified in the list. + * Else, use a random server. */ +void +hs_client_launch_v3_desc_fetch(const ed25519_public_key_t *onion_identity_pk, + const smartlist_t *hsdirs) +{ + tor_assert(onion_identity_pk); + + if (hsdirs != NULL) { + SMARTLIST_FOREACH_BEGIN(hsdirs, const routerstatus_t *, hsdir) { + directory_launch_v3_desc_fetch(onion_identity_pk, hsdir); + } SMARTLIST_FOREACH_END(hsdir); + } else { + fetch_v3_desc(onion_identity_pk); + } +} + /* Make sure that the given v3 origin circuit circ is a valid correct * introduction circuit. This will BUG() on any problems and hard assert if * the anonymity of the circuit is not ok. Return 0 on success else -1 where diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h index f6fb167ea2..47c525242f 100644 --- a/src/feature/hs/hs_client.h +++ b/src/feature/hs/hs_client.h @@ -44,6 +44,10 @@ typedef struct hs_client_service_authorization_t { void hs_client_note_connection_attempt_succeeded( const edge_connection_t *conn); +void hs_client_launch_v3_desc_fetch( + const ed25519_public_key_t *onion_identity_pk, + const smartlist_t *hsdirs); + int hs_client_decode_descriptor( const char *desc_str, const ed25519_public_key_t *service_identity_pk, diff --git a/src/feature/hs/hs_control.c b/src/feature/hs/hs_control.c index a21788ecd7..df8c1958b5 100644 --- a/src/feature/hs/hs_control.c +++ b/src/feature/hs/hs_control.c @@ -10,6 +10,7 @@ #include "feature/control/control.h" #include "lib/crypt_ops/crypto_format.h" #include "lib/crypt_ops/crypto_util.h" +#include "feature/hs/hs_client.h" #include "feature/hs/hs_common.h" #include "feature/hs/hs_control.h" #include "feature/hs/hs_descriptor.h" @@ -259,3 +260,16 @@ hs_control_hspost_command(const char *body, const char *onion_address, smartlist_free(hsdirs); return ret; } + +/* With a given onion_identity_pk, fetch its descriptor, optionally + * using the list of directory servers given in hsdirs, or a random + * server if it is NULL. This function calls hs_client_launch_v3_desc_fetch(). + */ +void +hs_control_hsfetch_command(const ed25519_public_key_t *onion_identity_pk, + const smartlist_t *hsdirs) +{ + tor_assert(onion_identity_pk); + + hs_client_launch_v3_desc_fetch(onion_identity_pk, hsdirs); +} diff --git a/src/feature/hs/hs_control.h b/src/feature/hs/hs_control.h index 63e3fe13d6..2f5dcd2154 100644 --- a/src/feature/hs/hs_control.h +++ b/src/feature/hs/hs_control.h @@ -48,5 +48,9 @@ void hs_control_desc_event_content(const hs_ident_dir_conn_t *ident, int hs_control_hspost_command(const char *body, const char *onion_address, const smartlist_t *hsdirs_rs); +/* Command "HSFETCH [...]" */ +void hs_control_hsfetch_command(const ed25519_public_key_t *onion_identity_pk, + const smartlist_t *hsdirs); + #endif /* !defined(TOR_HS_CONTROL_H) */ -- cgit v1.2.3-54-g00ecf From e19222a0daee40302218ab8efce359c154e575f0 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 24 Jan 2019 13:20:21 -0500 Subject: Use tt_u64_op() in test_circuitpadding.c to fix compilation warnings Fixes bug 29169. --- changes/bug29169 | 3 ++ src/test/test_circuitpadding.c | 69 +++++++++++++++++++++--------------------- 2 files changed, 37 insertions(+), 35 deletions(-) create mode 100644 changes/bug29169 (limited to 'changes') diff --git a/changes/bug29169 b/changes/bug29169 new file mode 100644 index 0000000000..41d4b76ef5 --- /dev/null +++ b/changes/bug29169 @@ -0,0 +1,3 @@ + o Minor bugfixes (compilation): + - Fix compilation warnings in test_circuitpadding.c. Fixes bug 29169; + bugfix on 0.4.0.1-alpha. diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c index 61bd174e6c..12a07fa957 100644 --- a/src/test/test_circuitpadding.c +++ b/src/test/test_circuitpadding.c @@ -321,12 +321,12 @@ test_circuitpadding_rtt(void *arg) /* Test 1: Test measuring RTT */ circpad_cell_event_nonpadding_received((circuit_t*)relay_side); - tt_int_op(relay_side->padding_info[0]->last_received_time_usec, OP_NE, 0); + tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_NE, 0); timers_advance_and_run(20); circpad_cell_event_nonpadding_sent((circuit_t*)relay_side); - tt_int_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); + tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_GE, 19000); tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_LE, 30000); @@ -338,11 +338,11 @@ test_circuitpadding_rtt(void *arg) circpad_cell_event_nonpadding_received((circuit_t*)relay_side); circpad_cell_event_nonpadding_received((circuit_t*)relay_side); - tt_int_op(relay_side->padding_info[0]->last_received_time_usec, OP_NE, 0); + tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_NE, 0); timers_advance_and_run(20); circpad_cell_event_nonpadding_sent((circuit_t*)relay_side); circpad_cell_event_nonpadding_sent((circuit_t*)relay_side); - tt_int_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); + tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_GE, 20000); tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_LE, 21000); @@ -362,7 +362,7 @@ test_circuitpadding_rtt(void *arg) tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_EQ, rtt_estimate); - tt_int_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); + tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); tt_int_op(relay_side->padding_info[0]->stop_rtt_update, OP_EQ, 1); tt_int_op(circpad_histogram_bin_to_usec(relay_side->padding_info[0], 0), OP_EQ, @@ -372,11 +372,11 @@ test_circuitpadding_rtt(void *arg) /* Test 3: Make sure client side machine properly ignores RTT */ circpad_cell_event_nonpadding_received((circuit_t*)client_side); - tt_int_op(client_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); + tt_u64_op(client_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); timers_advance_and_run(20); circpad_cell_event_nonpadding_sent((circuit_t*)client_side); - tt_int_op(client_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); + tt_u64_op(client_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); tt_int_op(client_side->padding_info[0]->rtt_estimate_usec, OP_EQ, 0); tt_int_op(circpad_histogram_bin_to_usec(client_side->padding_info[0], 0), @@ -1861,7 +1861,7 @@ test_circuitpadding_circuitsetup_machine(void *arg) tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_BURST); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); tt_int_op(relay_side->padding_info[0]->is_padding_timer_scheduled, OP_EQ, 0); @@ -1872,73 +1872,73 @@ test_circuitpadding_circuitsetup_machine(void *arg) tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_GAP); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_EQ, 0); - tt_int_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); timers_advance_and_run(5000); tt_int_op(n_client_cells, OP_EQ, 2); tt_int_op(n_relay_cells, OP_EQ, 2); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); - tt_int_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, OP_EQ, 0); timers_advance_and_run(2000); tt_int_op(n_client_cells, OP_EQ, 3); tt_int_op(n_relay_cells, OP_EQ, 2); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_EQ, 0); - tt_int_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); timers_advance_and_run(5000); tt_int_op(n_client_cells, OP_EQ, 3); tt_int_op(n_relay_cells, OP_EQ, 3); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); - tt_int_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, OP_EQ, 0); timers_advance_and_run(2000); tt_int_op(n_client_cells, OP_EQ, 4); tt_int_op(n_relay_cells, OP_EQ, 3); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_EQ, 0); - tt_int_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); timers_advance_and_run(5000); tt_int_op(n_client_cells, OP_EQ, 4); tt_int_op(n_relay_cells, OP_EQ, 4); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); - tt_int_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, OP_EQ, 0); timers_advance_and_run(2000); tt_int_op(n_client_cells, OP_EQ, 5); tt_int_op(n_relay_cells, OP_EQ, 4); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_EQ, 0); - tt_int_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); timers_advance_and_run(5000); tt_int_op(n_client_cells, OP_EQ, 5); tt_int_op(n_relay_cells, OP_EQ, 5); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); - tt_int_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, OP_EQ, 0); timers_advance_and_run(2000); tt_int_op(n_client_cells, OP_EQ, 6); tt_int_op(n_relay_cells, OP_EQ, 5); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_EQ, 0); - tt_int_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); timers_advance_and_run(5000); tt_int_op(n_client_cells, OP_EQ, 6); @@ -1946,11 +1946,11 @@ test_circuitpadding_circuitsetup_machine(void *arg) tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_END); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_EQ, 0); tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_GAP); - tt_int_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, OP_EQ, 0); /* Verify we can't schedule padding in END state */ @@ -1986,17 +1986,17 @@ test_circuitpadding_circuitsetup_machine(void *arg) tt_int_op(n_client_cells, OP_EQ, 8); tt_int_op(n_relay_cells, OP_EQ, 8); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); - tt_int_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); /* Test timer cancel due to state rules */ circpad_cell_event_nonpadding_sent(client_side); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_EQ, 0); circpad_cell_event_padding_received(client_side); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); /* Simulate application traffic to cancel timer */ @@ -2030,9 +2030,9 @@ test_circuitpadding_circuitsetup_machine(void *arg) tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_GAP); - tt_int_op(client_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); - tt_int_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, OP_NE, 0); circuit_mark_for_close(client_side, END_CIRC_REASON_FLAG_REMOTE); free_fake_orcirc(relay_side); @@ -2357,4 +2357,3 @@ struct testcase_t circuitpadding_tests[] = { TEST_CIRCUITPADDING(circuitpadding_token_removal_exact, TT_FORK), END_OF_TESTCASES }; - -- cgit v1.2.3-54-g00ecf From bbd893d6bd8e79ab6e303152c871027bc0380a38 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 29 Jan 2019 16:18:41 +0100 Subject: Write consensus files in binary mode This will help us out on windows now that we mmap files. Fixes part of ticket 28614. --- changes/ticket28614 | 4 ++++ src/feature/nodelist/networkstatus.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 changes/ticket28614 (limited to 'changes') diff --git a/changes/ticket28614 b/changes/ticket28614 new file mode 100644 index 0000000000..c022baf668 --- /dev/null +++ b/changes/ticket28614 @@ -0,0 +1,4 @@ + o Major bugfixes (windows, startup): + - When writing a consensus file to disk, always write in + "binary" mode so that we can safely map it into memory later. + Fixes part bug 28614; bugfix on 0.4.0.1-alpha. diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index d9659b67c0..64169f6a4b 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -1991,7 +1991,7 @@ networkstatus_set_current_consensus(const char *consensus, waiting->set_at = now; waiting->dl_failed = 0; if (!from_cache) { - write_bytes_to_file(unverified_fname, consensus, consensus_len, 0); + write_bytes_to_file(unverified_fname, consensus, consensus_len, 1); } if (dl_certs) authority_certs_fetch_missing(c, now, source_dir); @@ -2142,7 +2142,7 @@ networkstatus_set_current_consensus(const char *consensus, } if (!from_cache) { - write_bytes_to_file(consensus_fname, consensus, consensus_len, 0); + write_bytes_to_file(consensus_fname, consensus, consensus_len, 1); } warn_early_consensus(c, flavor, now); -- cgit v1.2.3-54-g00ecf From 58cbe517084d4ec8cd4ff3c297f841e561804cc3 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Wed, 30 Jan 2019 17:13:40 +0200 Subject: Use RFC5737-compliant example IP addresses in manpage when describing MapAddress --- changes/doc28623 | 3 +++ doc/tor.1.txt | 13 +++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 changes/doc28623 (limited to 'changes') diff --git a/changes/doc28623 b/changes/doc28623 new file mode 100644 index 0000000000..3c3313abdd --- /dev/null +++ b/changes/doc28623 @@ -0,0 +1,3 @@ + o Documentation: + - In manpage entry describing MapAddress torrc setting, use example + IP addresses from ranges specified by RFC 5737. Resolves issue 28623. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 00d6929c19..eb16037430 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -1159,17 +1159,18 @@ The following options are useful only for clients (that is, if 1. When evaluating MapAddress expressions Tor stops when it hits the most recently added expression that matches the requested address. So if you - have the following in your torrc, www.torproject.org will map to 1.1.1.1: + have the following in your torrc, www.torproject.org will map to + 198.51.100.1: - MapAddress www.torproject.org 2.2.2.2 - MapAddress www.torproject.org 1.1.1.1 + MapAddress www.torproject.org 192.0.2.1 + MapAddress www.torproject.org 198.51.100.1 2. Tor evaluates the MapAddress configuration until it finds no matches. So if you have the following in your torrc, www.torproject.org will map to - 2.2.2.2: + 203.0.113.1: - MapAddress 1.1.1.1 2.2.2.2 - MapAddress www.torproject.org 1.1.1.1 + MapAddress 198.51.100.1 203.0.113.1 + MapAddress www.torproject.org 198.51.100.1 3. The following MapAddress expression is invalid (and will be ignored) because you cannot map from a specific address to a wildcard -- cgit v1.2.3-54-g00ecf From 6170d3fcf12f4345ec13561d0f444930f2f12e84 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 31 Jul 2018 14:30:17 +1000 Subject: hs: Onion services put IPv6 addresses in service descriptors Rewrite service_intro_point_new() to take a node_t. Since node_get_link_specifier_smartlist() supports IPv6 link specifiers, this refactor adds IPv6 addresses to onion service descriptors. Part of 23576, implements 26992. --- changes/bug23576 | 7 ++++ src/feature/hs/hs_common.c | 18 +++++++- src/feature/hs/hs_service.c | 96 ++++++++----------------------------------- src/feature/hs/hs_service.h | 5 +-- src/test/test_hs_cell.c | 4 +- src/test/test_hs_intropoint.c | 4 +- src/test/test_hs_service.c | 2 +- 7 files changed, 48 insertions(+), 88 deletions(-) create mode 100644 changes/bug23576 (limited to 'changes') diff --git a/changes/bug23576 b/changes/bug23576 new file mode 100644 index 0000000000..edcae02e5e --- /dev/null +++ b/changes/bug23576 @@ -0,0 +1,7 @@ + o Minor features (IPv6, v3 onion services): + - Make v3 onion services put IPv6 addresses in service + descriptors. Before this change, service descriptors only + contained IPv4 addressesd. Implements 26992. + o Code simplification and refactoring: + - Simplify v3 onion service link specifier handling code. + Fixes bug 23576; bugfix on 0.3.2.1-alpha. diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c index ebe49f09a5..5d8f54230f 100644 --- a/src/feature/hs/hs_common.c +++ b/src/feature/hs/hs_common.c @@ -1697,6 +1697,12 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, tor_assert(lspecs); + if (smartlist_len(lspecs) == 0) { + log_fn(LOG_PROTOCOL_WARN, LD_REND, "Empty link specifier list."); + /* Return NULL. */ + goto done; + } + SMARTLIST_FOREACH_BEGIN(lspecs, const link_specifier_t *, ls) { switch (link_specifier_get_ls_type(ls)) { case LS_IPV4: @@ -1730,6 +1736,12 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, /* Legacy ID is mandatory, and we require IPv4. */ if (!have_v4 || !have_legacy_id) { + bool both = !have_v4 && !have_legacy_id; + log_fn(LOG_PROTOCOL_WARN, LD_REND, "Missing %s%s%s link specifier%s.", + !have_v4 ? "IPv4" : "", + both ? " and " : "", + !have_legacy_id ? "legacy ID" : "", + both ? "s" : ""); goto done; } @@ -1748,6 +1760,10 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, * release. */ } else { /* If we can't reach IPv4, return NULL. */ + log_fn(LOG_PROTOCOL_WARN, LD_REND, + "Received an IPv4 link specifier, " + "but the address is not reachable: %s:%u", + fmt_addr(&addr_v4), port_v4); goto done; } @@ -1755,7 +1771,7 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, validate: /* We'll validate now that the address we've picked isn't a private one. If - * it is, are we allowing to extend to private address? */ + * it is, are we allowed to extend to private addresses? */ if (!extend_info_addr_is_allowed(&addr_v4)) { log_fn(LOG_PROTOCOL_WARN, LD_REND, "Requested address is private and we are not allowed to extend to " diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index b94dd9a481..6e4da8856a 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -426,23 +426,16 @@ 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. - * If supports_ed25519_link_handshake_any is true, we add the relay's ed25519 - * key to the link specifiers. + * given node_t node, if non NULL. * - * If ei is NULL, returns a hs_service_intro_point_t with an empty link + * If node 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. */ + * node must be an node_t with an IPv4 address. */ STATIC hs_service_intro_point_t * -service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy, - unsigned int supports_ed25519_link_handshake_any) +service_intro_point_new(const node_t *node) { - hs_desc_link_specifier_t *ls; hs_service_intro_point_t *ip; ip = tor_malloc_zero(sizeof(*ip)); @@ -472,12 +465,17 @@ service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy, ip->replay_cache = replaycache_new(0, 0); /* Initialize the base object. We don't need the certificate object. */ - ip->base.link_specifiers = smartlist_new(); + ip->base.link_specifiers = node_get_link_specifier_smartlist(node, 0); + + if (node == NULL) { + goto done; + } /* Generate the encryption key for this intro point. */ curve25519_keypair_generate(&ip->enc_key_kp, 0); - /* Figure out if this chosen node supports v3 or is legacy only. */ - if (is_legacy) { + /* Figure out if this chosen node supports v3 or is legacy only. + * NULL nodes are used in the unit tests. */ + if (!node_supports_ed25519_hs_intro(node)) { ip->base.is_only_legacy = 1; /* Legacy mode that is doesn't support v3+ with ed25519 auth key. */ ip->legacy_key = crypto_pk_new(); @@ -490,40 +488,9 @@ service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy, } } - if (ei == NULL) { - goto done; - } - - /* We'll try to add all link specifiers. Legacy is mandatory. - * IPv4 or IPv6 is required, and we always send IPv4. */ - ls = hs_desc_link_specifier_new(ei, LS_IPV4); - /* It is impossible to have an extend info object without a v4. */ - if (BUG(!ls)) { - goto err; - } - smartlist_add(ip->base.link_specifiers, ls); - - ls = hs_desc_link_specifier_new(ei, LS_LEGACY_ID); - /* It is impossible to have an extend info object without an identity - * digest. */ - if (BUG(!ls)) { - goto err; - } - 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. */ - - /* Finally, copy onion key from the extend_info_t object. */ - memcpy(&ip->onion_key, &ei->curve25519_onion_key, sizeof(ip->onion_key)); + /* Finally, copy onion key from the node. */ + memcpy(&ip->onion_key, node_get_curve25519_onion_key(node), + sizeof(ip->onion_key)); done: return ip; @@ -2106,7 +2073,6 @@ static hs_service_intro_point_t * pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes) { const node_t *node; - extend_info_t *info = NULL; hs_service_intro_point_t *ip = NULL; /* Normal 3-hop introduction point flags. */ router_crn_flags_t flags = CRN_NEED_UPTIME | CRN_NEED_DESC; @@ -2127,43 +2093,17 @@ pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes) * we don't want to use that node anymore. */ smartlist_add(exclude_nodes, (void *) node); - /* We do this to ease our life but also this call makes appropriate checks - * of the node object such as validating ntor support for instance. - * - * We must provide an extend_info for clients to connect over a 3-hop path, - * so we don't pass direct_conn here. */ - info = extend_info_from_node(node, 0); - if (BUG(info == NULL)) { - goto err; - } - - /* Let's do a basic sanity check here so that we don't end up advertising the - * ed25519 identity key of relays that don't actually support the link - * protocol */ - if (!node_supports_ed25519_link_authentication(node, 0)) { - tor_assert_nonfatal(ed25519_public_key_is_zero(&info->ed_identity)); - } else { - /* Make sure we *do* have an ed key if we support the link authentication. - * Sending an empty key would result in a failure to extend. */ - 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(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; } - log_info(LD_REND, "Picked intro point: %s", extend_info_describe(info)); - extend_info_free(info); + log_info(LD_REND, "Picked intro point: %s", node_describe(node)); return ip; err: service_intro_point_free(ip); - extend_info_free(info); return NULL; } diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h index ec53f2f23b..8d7f773219 100644 --- a/src/feature/hs/hs_service.h +++ b/src/feature/hs/hs_service.h @@ -369,10 +369,7 @@ STATIC hs_service_t *find_service(hs_service_ht *map, 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, - unsigned int supports_ed25519_link_handshake_any); +STATIC hs_service_intro_point_t *service_intro_point_new(const node_t *node); 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/test/test_hs_cell.c b/src/test/test_hs_cell.c index 0c93f593ce..6e00e8807e 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, 0); + hs_service_intro_point_t *ip = service_intro_point_new(NULL); /* 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, 0); + ip = service_intro_point_new(NULL); 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 660f21ffd8..b7163c5c13 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, 0); + ip = service_intro_point_new(NULL); 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, 0); + ip = service_intro_point_new(NULL); 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 43bf894383..e8bdcd86e2 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -329,7 +329,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, 0); + hs_service_intro_point_t *ip = service_intro_point_new(NULL); tor_assert(ip); /* Add a first unused link specifier. */ ls = tor_malloc_zero(sizeof(*ls)); -- cgit v1.2.3-54-g00ecf From cb1072790f17cd43787a41c04b36a24833fbf7ee Mon Sep 17 00:00:00 2001 From: "José M. Guisado" Date: Thu, 31 Jan 2019 13:27:42 +0100 Subject: Warn about missing ContactInfo when MyFamily set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operators should be warned when setting MyFamily in addition to missing ContactInfo Signed-off-by: José M. Guisado --- changes/ticket25110 | 4 ++++ src/app/config/config.c | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 changes/ticket25110 (limited to 'changes') diff --git a/changes/ticket25110 b/changes/ticket25110 new file mode 100644 index 0000000000..298e33287f --- /dev/null +++ b/changes/ticket25110 @@ -0,0 +1,4 @@ + o Minor bugfixes (logging, configuration): + - Warn operators when MyFamily option is set but ContactInfo + is missing, as the latter should be set too. + Fixes bug 25110; bugfix on 0.3.3.1-alpha. diff --git a/src/app/config/config.c b/src/app/config/config.c index 952b9cd301..6b9162a3df 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -4179,6 +4179,10 @@ options_validate(or_options_t *old_options, or_options_t *options, "You should also make sure you aren't listing this bridge's " "fingerprint in any other MyFamily."); } + if (options->MyFamily_lines && !options->ContactInfo) { + log_warn(LD_CONFIG, "MyFamily is set but ContactInfo is not configured. " + "ContactInfo should always be set when MyFamily option is too."); + } if (normalize_nickname_list(&options->MyFamily, options->MyFamily_lines, "MyFamily", msg)) return -1; -- cgit v1.2.3-54-g00ecf From 10455aeff228042ee769205e43788d0e81cde910 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Fri, 1 Feb 2019 20:53:40 +0200 Subject: Fix shellcheck warnings in test_rust.sh --- changes/ticket29064 | 2 ++ src/test/test_rust.sh | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 changes/ticket29064 (limited to 'changes') diff --git a/changes/ticket29064 b/changes/ticket29064 new file mode 100644 index 0000000000..616b8aa77e --- /dev/null +++ b/changes/ticket29064 @@ -0,0 +1,2 @@ + o Code simplification and refactoring (shell scripts): + - Fix shellcheck warning in test_rust.sh. Fixes issue 29064. diff --git a/src/test/test_rust.sh b/src/test/test_rust.sh index 00b3e88d37..da2bd32d21 100755 --- a/src/test/test_rust.sh +++ b/src/test/test_rust.sh @@ -16,10 +16,10 @@ for cargo_toml_dir in "${abs_top_srcdir:-../../..}"/src/rust/*; do if [ -e "${cargo_toml_dir}/Cargo.toml" ]; then cd "${abs_top_builddir:-../../..}/src/rust" && \ CARGO_TARGET_DIR="${abs_top_builddir:-../../..}/src/rust/target" \ - "${CARGO:-cargo}" test ${CARGO_ONLINE-"--frozen"} \ + "${CARGO:-cargo}" test "${CARGO_ONLINE-'--frozen'}" \ --features "test_linking_hack" \ - --target $rustc_host \ - ${EXTRA_CARGO_OPTIONS} \ + --target "$rustc_host" \ + "${EXTRA_CARGO_OPTIONS}" \ --manifest-path "${cargo_toml_dir}/Cargo.toml" || exitcode=1 fi done -- cgit v1.2.3-54-g00ecf From 0b245e418e91cbbc325dfdc399fc184b067e9471 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Fri, 1 Feb 2019 21:43:45 +0200 Subject: Add changes file --- changes/ticket29062 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket29062 (limited to 'changes') diff --git a/changes/ticket29062 b/changes/ticket29062 new file mode 100644 index 0000000000..de05c621f1 --- /dev/null +++ b/changes/ticket29062 @@ -0,0 +1,3 @@ + o Code simplification and refactoring (shell scripts): + - Cleanup test_keygen.sh to silence all shellcheck warnings. Closes + ticket 29062. -- cgit v1.2.3-54-g00ecf From 583e20615cf0826a4b1774eead50c40d246f6962 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sat, 2 Feb 2019 16:54:50 +0200 Subject: Add changes file --- changes/ticket29060 | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 changes/ticket29060 (limited to 'changes') diff --git a/changes/ticket29060 b/changes/ticket29060 new file mode 100644 index 0000000000..380cc8eb11 --- /dev/null +++ b/changes/ticket29060 @@ -0,0 +1,2 @@ + o Code simplification and refactoring (shell scripts): + - Fix shellcheck warnings in test-network.sh. Resolves issue 29060. -- cgit v1.2.3-54-g00ecf From 83b1ca9b07195cc2f2ad514043eaebfaf9e85641 Mon Sep 17 00:00:00 2001 From: Peter Gerber Date: Sat, 2 Feb 2019 23:09:44 +0000 Subject: Add release note for bug 29150 --- changes/bug29150 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/bug29150 (limited to 'changes') diff --git a/changes/bug29150 b/changes/bug29150 new file mode 100644 index 0000000000..7696b90378 --- /dev/null +++ b/changes/bug29150 @@ -0,0 +1,3 @@ + o Minor bugfixes (linux seccomp sandbox): + - Fix startup crash when experimental sandbox support is enabled. + Fixes bug 29150; bugfix on 0.4.0.1-alpha. Patch by Peter Gerber. -- cgit v1.2.3-54-g00ecf From 4e3880607ad2f09711e18429afda1514a2cb7e28 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Wed, 6 Feb 2019 10:53:12 +0200 Subject: Add changes file --- changes/ticket29071 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket29071 (limited to 'changes') diff --git a/changes/ticket29071 b/changes/ticket29071 new file mode 100644 index 0000000000..0997a8d22f --- /dev/null +++ b/changes/ticket29071 @@ -0,0 +1,3 @@ + o Code simplification and refactoring (shell scripts): + - Fix shellcheck warnings in nagios-check-tor-authority-cert script. + Resolves issue 29071. -- cgit v1.2.3-54-g00ecf From daff9e1ba11bdf1d6fe55eeeda45dd4bb2918874 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sat, 2 Feb 2019 17:14:49 +0200 Subject: Fix shellcheck warning in fuzz_static_testcases.sh --- changes/ticket29059 | 3 +++ src/test/fuzz_static_testcases.sh | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/ticket29059 (limited to 'changes') diff --git a/changes/ticket29059 b/changes/ticket29059 new file mode 100644 index 0000000000..d47d0e2a3b --- /dev/null +++ b/changes/ticket29059 @@ -0,0 +1,3 @@ + o Code simplification and refactoring (shell scripts): + - Fix shellcheck warnings in fuzz_static_testcases.sh. Resolves ticket + 29059. diff --git a/src/test/fuzz_static_testcases.sh b/src/test/fuzz_static_testcases.sh index f7b3adffb1..b883352402 100755 --- a/src/test/fuzz_static_testcases.sh +++ b/src/test/fuzz_static_testcases.sh @@ -14,7 +14,7 @@ fi for fuzzer in "${builddir:-.}"/src/test/fuzz/fuzz-* ; do - f=`basename $fuzzer` + f=$(basename "$fuzzer") case="${f#fuzz-}" if [ -d "${TOR_FUZZ_CORPORA}/${case}" ]; then echo "Running tests for ${case}" -- cgit v1.2.3-54-g00ecf From 8df6a65e6b86be70ab1d7f57b097913068ace72c Mon Sep 17 00:00:00 2001 From: rl1987 Date: Thu, 7 Feb 2019 17:22:06 +0200 Subject: Fix shellcheck warning in zero_length_keys.sh --- changes/ticket29068 | 2 ++ src/test/zero_length_keys.sh | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 changes/ticket29068 (limited to 'changes') diff --git a/changes/ticket29068 b/changes/ticket29068 new file mode 100644 index 0000000000..77ef304f1d --- /dev/null +++ b/changes/ticket29068 @@ -0,0 +1,2 @@ + o Code simplification and refactoring (shell scripts): + - Fix shellcheck warnings in zero_length_keys.sh. Resolves issue 29068. diff --git a/src/test/zero_length_keys.sh b/src/test/zero_length_keys.sh index 3c61f8d465..4069148e0b 100755 --- a/src/test/zero_length_keys.sh +++ b/src/test/zero_length_keys.sh @@ -19,7 +19,7 @@ # 3: a command failed - the test could not be completed # -if [ $# -eq 0 ] || [ ! -f ${1} ] || [ ! -x ${1} ]; then +if [ $# -eq 0 ] || [ ! -f "${1}" ] || [ ! -x "${1}" ]; then echo "Usage: ${0} PATH_TO_TOR [-z|-d|-e]" exit 1 elif [ $# -eq 1 ]; then @@ -31,7 +31,7 @@ else #[$# -gt 1 ]; then shift fi -DATA_DIR=`mktemp -d -t tor_zero_length_keys.XXXXXX` +DATA_DIR=$(mktemp -d -t tor_zero_length_keys.XXXXXX) if [ -z "$DATA_DIR" ]; then echo "Failure: mktemp invocation returned empty string" >&2 exit 3 @@ -40,7 +40,7 @@ if [ ! -d "$DATA_DIR" ]; then echo "Failure: mktemp invocation result doesn't point to directory" >&2 exit 3 fi -trap "rm -rf '$DATA_DIR'" 0 +trap 'rm -rf "$DATA_DIR"' 0 touch "$DATA_DIR"/empty_torrc -- cgit v1.2.3-54-g00ecf From b53fee46223a425ed27f37944ac0d26569cead78 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Fri, 8 Feb 2019 16:51:49 +0200 Subject: Fix SC2086 warning in test_workqueue_*.sh shell scripts --- changes/ticket29067 | 3 +++ src/test/test_workqueue_cancel.sh | 2 +- src/test/test_workqueue_efd.sh | 2 +- src/test/test_workqueue_efd2.sh | 2 +- src/test/test_workqueue_pipe.sh | 2 +- src/test/test_workqueue_pipe2.sh | 2 +- src/test/test_workqueue_socketpair.sh | 2 +- 7 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 changes/ticket29067 (limited to 'changes') diff --git a/changes/ticket29067 b/changes/ticket29067 new file mode 100644 index 0000000000..a660648775 --- /dev/null +++ b/changes/ticket29067 @@ -0,0 +1,3 @@ + o Code simplification and refactoring (shell scripts): + - Fix test_workqueue_*.sh scripts to silence shellcheck SC2086 + warnings. Fixes issue 29067. diff --git a/src/test/test_workqueue_cancel.sh b/src/test/test_workqueue_cancel.sh index f7c663171e..e50b884f26 100755 --- a/src/test/test_workqueue_cancel.sh +++ b/src/test/test_workqueue_cancel.sh @@ -1,4 +1,4 @@ #!/bin/sh -${builddir:-.}/src/test/test_workqueue -C 1 +"${builddir:-.}/src/test/test_workqueue" -C 1 diff --git a/src/test/test_workqueue_efd.sh b/src/test/test_workqueue_efd.sh index 4d89396819..592841fc91 100755 --- a/src/test/test_workqueue_efd.sh +++ b/src/test/test_workqueue_efd.sh @@ -1,4 +1,4 @@ #!/bin/sh -${builddir:-.}/src/test/test_workqueue \ +"${builddir:-.}/src/test/test_workqueue" \ --no-eventfd2 --no-pipe2 --no-pipe --no-socketpair diff --git a/src/test/test_workqueue_efd2.sh b/src/test/test_workqueue_efd2.sh index 7cfff45ff3..4cf1b76cbe 100755 --- a/src/test/test_workqueue_efd2.sh +++ b/src/test/test_workqueue_efd2.sh @@ -1,4 +1,4 @@ #!/bin/sh -${builddir:-.}/src/test/test_workqueue \ +"${builddir:-.}/src/test/test_workqueue" \ --no-eventfd --no-pipe2 --no-pipe --no-socketpair diff --git a/src/test/test_workqueue_pipe.sh b/src/test/test_workqueue_pipe.sh index afcef87853..fc3ef34c6c 100755 --- a/src/test/test_workqueue_pipe.sh +++ b/src/test/test_workqueue_pipe.sh @@ -1,4 +1,4 @@ #!/bin/sh -${builddir:-.}/src/test/test_workqueue \ +"${builddir:-.}/src/test/test_workqueue" \ --no-eventfd2 --no-eventfd --no-pipe2 --no-socketpair diff --git a/src/test/test_workqueue_pipe2.sh b/src/test/test_workqueue_pipe2.sh index a20a1427e0..7f19ea880d 100755 --- a/src/test/test_workqueue_pipe2.sh +++ b/src/test/test_workqueue_pipe2.sh @@ -1,4 +1,4 @@ #!/bin/sh -${builddir:-.}/src/test/test_workqueue \ +"${builddir:-.}/src/test/test_workqueue" \ --no-eventfd2 --no-eventfd --no-pipe --no-socketpair diff --git a/src/test/test_workqueue_socketpair.sh b/src/test/test_workqueue_socketpair.sh index 76af79746d..1ee1776447 100755 --- a/src/test/test_workqueue_socketpair.sh +++ b/src/test/test_workqueue_socketpair.sh @@ -1,4 +1,4 @@ #!/bin/sh -${builddir:-.}/src/test/test_workqueue \ +"${builddir:-.}/src/test/test_workqueue" \ --no-eventfd2 --no-eventfd --no-pipe2 --no-pipe -- cgit v1.2.3-54-g00ecf From f4c76661d1bb49a47829c6999a07c1de63b55cc9 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 8 Feb 2019 11:21:09 -0500 Subject: Add a script to check for coverage nondeterminism Closes ticket 29436. --- changes/ticket29436 | 4 +++ scripts/test/cov-test-determinism.sh | 48 ++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 changes/ticket29436 create mode 100755 scripts/test/cov-test-determinism.sh (limited to 'changes') diff --git a/changes/ticket29436 b/changes/ticket29436 new file mode 100644 index 0000000000..025be619e5 --- /dev/null +++ b/changes/ticket29436 @@ -0,0 +1,4 @@ + o Minor features (testing): + - We now have a script, cov-test-determinism.sh, to identify places + where our unit test coverage has become nondeterministic. + Closes ticket 29436. diff --git a/scripts/test/cov-test-determinism.sh b/scripts/test/cov-test-determinism.sh new file mode 100755 index 0000000000..3b4f372e04 --- /dev/null +++ b/scripts/test/cov-test-determinism.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +# To use this script, build Tor with coverage enabled, and then say: +# ./scripts/test/cov-test-determinism.sh run +# +# Let it run for a long time so it can run the tests over and over. It +# will put their coverage outputs in coverage-raw/coverage-*/. +# +# Then say: +# ./scripts/test/cov-test-determinism.sh check +# +# It will diff the other coverage outputs to the first one, and put their +# diffs in coverage-raw/diff-coverage-*. + +run=0 +check=0 + +if test "$1" = run; then + run=1 +elif test "$1" = check; then + check=1 +else + echo "First use 'run' with this script, then use 'check'." + exit 1 +fi + +if test "$run" = 1; then + while true; do + make reset-gcov + CD=coverage-raw/coverage-$(date +%s) + make -j5 check + mkdir -p "$CD" + ./scripts/test/coverage "$CD" + done +fi + +if test "$check" = 1; then + cd coverage-raw || exit 1 + + FIRST="$(find . -name "coverage-*" -type d | head -1)" + rm -f A + ln -sf "$FIRST" A + for dir in coverage-*; do + rm -f B + ln -sf "$dir" B + ../scripts/test/cov-diff A B > "diff-$dir" + done +fi -- cgit v1.2.3-54-g00ecf From 8d04dc416bd6aa3fefc0914add8708083dc99d52 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sat, 9 Feb 2019 16:56:54 +0200 Subject: Add changes file --- changes/ticket28816 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket28816 (limited to 'changes') diff --git a/changes/ticket28816 b/changes/ticket28816 new file mode 100644 index 0000000000..02878ccfdc --- /dev/null +++ b/changes/ticket28816 @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Introduce a connection_dir_buf_add() helper function that checks for + compress_state of dir_connection_t and automatically writes a string to + directory connection with or without compression. Resolves issue 28816. -- cgit v1.2.3-54-g00ecf From 72b978c3a58983d9b4d57f56db618e074ddae31e Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 30 Jan 2019 09:22:36 +0100 Subject: On windows, if we fail to load a consensus and it has a CRLF, retry. Fixes bug 28614; bugfix on 0.4.0.1-alpha when we started mmapping the consensus. --- changes/ticket28614 | 6 ++- src/feature/nodelist/networkstatus.c | 81 +++++++++++++++++++++++------------- 2 files changed, 56 insertions(+), 31 deletions(-) (limited to 'changes') diff --git a/changes/ticket28614 b/changes/ticket28614 index c022baf668..6c65ce49de 100644 --- a/changes/ticket28614 +++ b/changes/ticket28614 @@ -1,4 +1,8 @@ o Major bugfixes (windows, startup): - When writing a consensus file to disk, always write in "binary" mode so that we can safely map it into memory later. - Fixes part bug 28614; bugfix on 0.4.0.1-alpha. + Fixes part of bug 28614; bugfix on 0.4.0.1-alpha. + - When reading a consensus file from disk, detect whether it + was written in text mode, and re-read it in text mode if it + Fixes part of bug 28614; bugfix on 0.4.0.1-alpha. + diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index 64169f6a4b..2c34754621 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -178,6 +178,10 @@ static void update_consensus_bootstrap_multiple_downloads( static int networkstatus_check_required_protocols(const networkstatus_t *ns, int client_mode, char **warning_out); +static int reload_consensus_from_file(const char *fname, + const char *flavor, + unsigned flags, + const char *source_dir); /** Forget that we've warned about anything networkstatus-related, so we will * give fresh warnings if the same behavior happens again. */ @@ -269,27 +273,15 @@ router_reload_consensus_networkstatus(void) /* FFFF Suppress warnings if cached consensus is bad? */ for (flav = 0; flav < N_CONSENSUS_FLAVORS; ++flav) { const char *flavor = networkstatus_get_flavor_name(flav); - tor_mmap_t *m = networkstatus_map_cached_consensus_impl(flav, flavor, 0); - if (m) { - if (networkstatus_set_current_consensus(m->data, m->size, - flavor, flags, NULL) < -1) { - log_warn(LD_FS, "Couldn't load consensus %s networkstatus from cache", - flavor); - } - tor_munmap_file(m); - } + char *fname = networkstatus_get_cache_fname(flav, flavor, 0); + reload_consensus_from_file(fname, flavor, flags, NULL); + tor_free(fname); - m = networkstatus_map_cached_consensus_impl(flav, flavor, 1); - if (m) { - if (networkstatus_set_current_consensus(m->data, m->size, - flavor, - flags | NSSET_WAS_WAITING_FOR_CERTS, - NULL)) { - log_info(LD_FS, "Couldn't load unverified consensus %s networkstatus " - "from cache", flavor); - } - tor_munmap_file(m); - } + fname = networkstatus_get_cache_fname(flav, flavor, 1); + reload_consensus_from_file(fname, flavor, + flags | NSSET_WAS_WAITING_FOR_CERTS, + NULL); + tor_free(fname); } update_certificate_downloads(time(NULL)); @@ -1750,6 +1742,41 @@ networkstatus_set_current_consensus_from_ns(networkstatus_t *c, } #endif /* defined(TOR_UNIT_TESTS) */ +/** + * Helper: Read a the current consensus of type flavor from + * fname. Flags and return values are as for + * networkstatus_set_current_consensus(). + **/ +static int +reload_consensus_from_file(const char *fname, + const char *flavor, + unsigned flags, + const char *source_dir) +{ + tor_mmap_t *map = tor_mmap_file(fname); + if (!map) + return 0; + + int rv = networkstatus_set_current_consensus(map->data, map->size, + flavor, flags, source_dir); +#ifdef _WIN32 + if (rv < 0 && tor_memstr(map->data, map->size, "\r\n")) { + log_info(LD_GENERAL, "Found CRLF in consensus file %s; falling back to " + "read_file_to_string.", escaped(fname)); + char *content = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); + rv = networkstatus_set_current_consensus(content, strlen(content), + flavor, flags, source_dir); + tor_free(content); + } +#endif + if (rv < -1) { + log_warn(LD_GENERAL, "Couldn't set consensus from cache file %s", + escaped(fname)); + } + tor_munmap_file(map); + return rv; +} + /** * Helper for handle_missing_protocol_warning: handles either the * client case (if is_client is set) or the server case otherwise. @@ -2178,16 +2205,10 @@ networkstatus_note_certs_arrived(const char *source_dir) if (!waiting->consensus) continue; if (networkstatus_check_consensus_signature(waiting->consensus, 0)>=0) { - tor_mmap_t *mapping = networkstatus_map_cached_consensus_impl( - i, flavor_name, 1); - if (mapping) { - networkstatus_set_current_consensus(mapping->data, - mapping->size, - flavor_name, - NSSET_WAS_WAITING_FOR_CERTS, - source_dir); - } - tor_munmap_file(mapping); + char *fname = networkstatus_get_cache_fname(i, flavor_name, 1); + reload_consensus_from_file(fname, flavor_name, + NSSET_WAS_WAITING_FOR_CERTS, source_dir); + tor_free(fname); } } } -- cgit v1.2.3-54-g00ecf From b61c3c6dfa072a9717c878675ed431c3f8f74d24 Mon Sep 17 00:00:00 2001 From: juga0 Date: Tue, 6 Nov 2018 14:58:15 +0000 Subject: changes: Add changes file for #26698 --- changes/ticket26698 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket26698 (limited to 'changes') diff --git a/changes/ticket26698 b/changes/ticket26698 new file mode 100644 index 0000000000..6b029a1b73 --- /dev/null +++ b/changes/ticket26698 @@ -0,0 +1,4 @@ + o Minor features (directory authority): + - When a directory authority is using a bandwidth file to obtain the + bandwidth values, include the digest of the file in the vote. + Closes ticket 26698. -- cgit v1.2.3-54-g00ecf From f5a6d4c6ea78e73e8f27292fac6d4153e8e84aa0 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 14 Feb 2019 12:07:10 +0200 Subject: Disable unstable circuit padding unittest. until #29298 is implemented. --- changes/bug29298 | 5 +++++ src/test/test_circuitpadding.c | 8 +++++--- 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 changes/bug29298 (limited to 'changes') diff --git a/changes/bug29298 b/changes/bug29298 new file mode 100644 index 0000000000..df12db77d7 --- /dev/null +++ b/changes/bug29298 @@ -0,0 +1,5 @@ + o Minor bugfixes (testing, circuit padding): + - Disabled unstable circuit padding unittest that was causing intermittent + test failures because of ill-defined small histogram. Such histograms + will be allowed again after 29298 is implemented. Fixes second case of + bug 29122; bugfix on 0.4.0.1-alpha. \ No newline at end of file diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c index 12a07fa957..eee1edc50c 100644 --- a/src/test/test_circuitpadding.c +++ b/src/test/test_circuitpadding.c @@ -46,7 +46,6 @@ void test_circuitpadding_conditions(void *arg); void test_circuitpadding_serialize(void *arg); void test_circuitpadding_rtt(void *arg); void test_circuitpadding_tokens(void *arg); -void test_circuitpadding_circuitsetup_machine(void *arg); static void simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay, @@ -1809,6 +1808,8 @@ test_circuitpadding_conditions(void *arg) return; } +/** Disabled unstable test until #29298 is implemented (see #29122) */ +#if 0 void test_circuitpadding_circuitsetup_machine(void *arg) { @@ -2054,6 +2055,7 @@ test_circuitpadding_circuitsetup_machine(void *arg) return; } +#endif /** Helper function: Initializes a padding machine where every state uses the * uniform probability distribution. */ @@ -2340,11 +2342,11 @@ test_circuitpadding_global_rate_limiting(void *arg) { #name, test_##name, (flags), NULL, NULL } struct testcase_t circuitpadding_tests[] = { - //TEST_CIRCUITPADDING(circuitpadding_circuitsetup_machine, 0), TEST_CIRCUITPADDING(circuitpadding_tokens, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_negotiation, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_wronghop, TT_FORK), - TEST_CIRCUITPADDING(circuitpadding_circuitsetup_machine, TT_FORK), + /** Disabled unstable test until #29298 is implemented (see #29122) */ + // TEST_CIRCUITPADDING(circuitpadding_circuitsetup_machine, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_conditions, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_rtt, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_sample_distribution, TT_FORK), -- cgit v1.2.3-54-g00ecf From b054a6c6b9cdda5c35b905f98ff092f15d8b749d Mon Sep 17 00:00:00 2001 From: Matt Traudt Date: Thu, 14 Feb 2019 16:18:58 -0500 Subject: kist: When readding chans, check correct chan's sched_heap_idx Closes #29508 Signed-off-by: David Goulet --- changes/bug29508 | 3 +++ src/core/or/scheduler_kist.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/bug29508 (limited to 'changes') diff --git a/changes/bug29508 b/changes/bug29508 new file mode 100644 index 0000000000..ee728bbbc9 --- /dev/null +++ b/changes/bug29508 @@ -0,0 +1,3 @@ + o Minor bugfixes (scheduler): + - When readding channels to the pending list, check the correct channel's + sched_heap_idx. Fixes bug 29508; bugfix on 0.3.2.10 diff --git a/src/core/or/scheduler_kist.c b/src/core/or/scheduler_kist.c index 34e5672074..01be751ad2 100644 --- a/src/core/or/scheduler_kist.c +++ b/src/core/or/scheduler_kist.c @@ -724,7 +724,7 @@ kist_scheduler_run(void) SMARTLIST_FOREACH_BEGIN(to_readd, channel_t *, readd_chan) { scheduler_set_channel_state(readd_chan, SCHED_CHAN_PENDING); if (!smartlist_contains(cp, readd_chan)) { - if (!SCHED_BUG(chan->sched_heap_idx != -1, chan)) { + if (!SCHED_BUG(readd_chan->sched_heap_idx != -1, readd_chan)) { /* XXXX Note that the check above is in theory redundant with * the smartlist_contains check. But let's make sure we're * not messing anything up, and leave them both for now. */ -- cgit v1.2.3-54-g00ecf From 80abe4170d590ca3b5bcf136457f16d0d6e3692f Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 15 Feb 2019 17:16:18 +0200 Subject: Update all the histogram functions to use the new design. --- changes/bug29298 | 6 +++ src/core/or/circuitpadding.c | 113 +++++++++++++++++-------------------------- src/core/or/circuitpadding.h | 4 ++ 3 files changed, 55 insertions(+), 68 deletions(-) create mode 100644 changes/bug29298 (limited to 'changes') diff --git a/changes/bug29298 b/changes/bug29298 new file mode 100644 index 0000000000..6e447b62dd --- /dev/null +++ b/changes/bug29298 @@ -0,0 +1,6 @@ + o Minor features (circuit padding): + - Allow the padding machine designer to pick the edges of their histogram + instead of trying to compute them automatically using an exponential + formula. Resolves some undefined behavior in the case of small histograms + and allows greater flexibility on machine design. Closes ticket 29298; + bugfix on 0.4.0.1-alpha. \ No newline at end of file diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c index a9c5796caa..383e59d1e6 100644 --- a/src/core/or/circuitpadding.c +++ b/src/core/or/circuitpadding.c @@ -222,25 +222,15 @@ circpad_machine_current_state(const circpad_machine_state_t *mi) } /** - * Calculate the lower bound of a histogram bin. The upper bound - * is obtained by calling this function with bin+1, and subtracting 1. - * - * The 0th bin has a special value -- it only represents start_usec. - * This is so we can specify a probability on 0-delay values. - * - * After bin 0, bins are exponentially spaced, so that each subsequent - * bin is twice as large as the previous. This is done so that higher - * time resolution is given to lower time values. - * - * The infinity bin is a the last bin in the array (histogram_len-1). - * It has a usec value of CIRCPAD_DELAY_INFINITE (UINT32_MAX). + * Get the lower bound of a histogram bin. The upper bound is obtained by + * calling this function with bin+1, and subtracting 1. */ STATIC circpad_delay_t circpad_histogram_bin_to_usec(const circpad_machine_state_t *mi, circpad_hist_index_t bin) { const circpad_state_t *state = circpad_machine_current_state(mi); - circpad_delay_t start_usec; + circpad_delay_t rtt_add_usec = 0; /* Our state should have been checked to be non-null by the caller * (circpad_machine_remove_token()) */ @@ -248,27 +238,29 @@ circpad_histogram_bin_to_usec(const circpad_machine_state_t *mi, return CIRCPAD_DELAY_INFINITE; } - if (state->use_rtt_estimate) - start_usec = mi->rtt_estimate_usec+state->start_usec; - else - start_usec = state->start_usec; - - if (bin >= CIRCPAD_INFINITY_BIN(state)) + /* The infinity bin has an upper bound of infinity, so make sure we return + * that if they ask for it. */ + if (bin > CIRCPAD_INFINITY_BIN(mi)) { return CIRCPAD_DELAY_INFINITE; + } - if (bin == 0) - return start_usec; + /* If we are using an RTT estimate, consider it as well. */ + if (state->use_rtt_estimate) { + rtt_add_usec = mi->rtt_estimate_usec; + } - if (bin == 1) - return start_usec+1; + return state->histogram_edges[bin] + rtt_add_usec; +} - /* The bin widths double every index, so that we can have more resolution - * for lower time values in the histogram. */ - const circpad_time_t bin_width_exponent = - 1 << (CIRCPAD_INFINITY_BIN(state) - bin); - return (circpad_delay_t)MIN(start_usec + - state->range_usec/bin_width_exponent, - CIRCPAD_DELAY_INFINITE); +/** + * Like circpad_histogram_bin_to_usec() but return the upper bound of bin. + * (The upper bound is included in the bin.) + */ +STATIC circpad_delay_t +histogram_get_bin_upper_bound(const circpad_machine_state_t *mi, + circpad_hist_index_t bin) +{ + return circpad_histogram_bin_to_usec(mi, bin+1) - 1; } /** Return the midpoint of the histogram bin bin_index. */ @@ -287,19 +279,17 @@ circpad_get_histogram_bin_midpoint(const circpad_machine_state_t *mi, * Return the bin that contains the usec argument. * "Contains" is defined as us in [lower, upper). * - * This function will never return the infinity bin (histogram_len-1), - * in order to simplify the rest of the code. - * - * This means that technically the last bin (histogram_len-2) - * has range [start_usec+range_usec, CIRCPAD_DELAY_INFINITE]. + * This function will never return the infinity bin (histogram_len-1), in order + * to simplify the rest of the code, so if a usec is provided that falls above + * the highest non-infinity bin, that bin index will be returned. */ STATIC circpad_hist_index_t circpad_histogram_usec_to_bin(const circpad_machine_state_t *mi, circpad_delay_t usec) { const circpad_state_t *state = circpad_machine_current_state(mi); - circpad_delay_t start_usec; - int32_t bin; /* Larger than return type to properly clamp overflow */ + circpad_delay_t rtt_add_usec = 0; + int32_t bin; /* Our state should have been checked to be non-null by the caller * (circpad_machine_remove_token()) */ @@ -307,34 +297,25 @@ circpad_histogram_usec_to_bin(const circpad_machine_state_t *mi, return 0; } - if (state->use_rtt_estimate) - start_usec = mi->rtt_estimate_usec+state->start_usec; - else - start_usec = state->start_usec; - - /* The first bin (#0) has zero width and starts (and ends) at start_usec. */ - if (usec <= start_usec) - return 0; - - if (usec == start_usec+1) - return 1; + /* If we are using an RTT estimate, consider it as well. */ + if (state->use_rtt_estimate) { + rtt_add_usec = mi->rtt_estimate_usec; + } - const circpad_time_t histogram_range_usec = state->range_usec; - /* We need to find the bin corresponding to our position in the range. - * Since bins are exponentially spaced in powers of two, we need to - * take the log2 of our position in histogram_range_usec. However, - * since tor_log2() returns the floor(log2(u64)), we have to adjust - * it to behave like ceil(log2(u64)). This is verified in our tests - * to properly invert the operation done in - * circpad_histogram_bin_to_usec(). */ - bin = CIRCPAD_INFINITY_BIN(state) - - tor_log2(2*histogram_range_usec/(usec-start_usec+1)); + /* Walk through the bins and check the upper bound of each bin, if 'usec' is + * less-or-equal to that, return that bin. If rtt_estimate is enabled then + * add that to the upper bound of each bin. + * + * We don't want to return the infinity bin here, so don't go there. */ + for (bin = 0 ; bin < CIRCPAD_INFINITY_BIN(state) ; bin++) { + if (usec <= histogram_get_bin_upper_bound(mi, bin) + rtt_add_usec) { + return bin; + } + } - /* Clamp the return value to account for timevals before the start - * of bin 0, or after the last bin. Don't return the infinity bin - * index. */ - bin = MIN(MAX(bin, 1), CIRCPAD_INFINITY_BIN(state)-1); - return bin; + /* We don't want to return the infinity bin here, so if we still didn't find + * the right bin, return the highest non-infinity bin */ + return CIRCPAD_INFINITY_BIN(state)-1; } /** @@ -506,10 +487,6 @@ circpad_machine_sample_delay(circpad_machine_state_t *mi) * function below samples from [bin_start, bin_end) */ bin_end = circpad_histogram_bin_to_usec(mi, curr_bin+1); - /* Truncate the high bin in case it's the infinity bin: - * Don't actually schedule an "infinite"-1 delay */ - bin_end = MIN(bin_end, start_usec+state->range_usec); - // Sample uniformly between histogram[i] to histogram[i+1]-1, // but no need to sample if they are the same timeval (aka bin 0 or bin 1). if (bin_end <= bin_start+1) @@ -621,7 +598,7 @@ circpad_machine_first_higher_index(const circpad_machine_state_t *mi, /* Don't remove from the infinity bin */ for (; bin < CIRCPAD_INFINITY_BIN(mi); bin++) { if (mi->histogram[bin] && - circpad_histogram_bin_to_usec(mi, bin+1) > target_bin_usec) { + histogram_get_bin_upper_bound(mi, bin) >= target_bin_usec) { return bin; } } diff --git a/src/core/or/circuitpadding.h b/src/core/or/circuitpadding.h index 918a7d0ddd..b9e903b9f0 100644 --- a/src/core/or/circuitpadding.h +++ b/src/core/or/circuitpadding.h @@ -710,6 +710,10 @@ circpad_send_command_to_hop,(struct origin_circuit_t *circ, uint8_t hopnum, uint8_t relay_command, const uint8_t *payload, ssize_t payload_len)); +STATIC circpad_delay_t +histogram_get_bin_upper_bound(const circpad_machine_state_t *mi, + circpad_hist_index_t bin); + #ifdef TOR_UNIT_TESTS extern smartlist_t *origin_padding_machines; extern smartlist_t *relay_padding_machines; -- cgit v1.2.3-54-g00ecf From 6fdd34acd69e6e54562855acffa23df0cec2aee2 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Fri, 15 Feb 2019 19:18:24 +0200 Subject: Remove check-tor script --- changes/ticket29072 | 2 ++ contrib/or-tools/check-tor | 41 ----------------------------------------- 2 files changed, 2 insertions(+), 41 deletions(-) create mode 100644 changes/ticket29072 delete mode 100755 contrib/or-tools/check-tor (limited to 'changes') diff --git a/changes/ticket29072 b/changes/ticket29072 new file mode 100644 index 0000000000..3526330f30 --- /dev/null +++ b/changes/ticket29072 @@ -0,0 +1,2 @@ + o Removed features: + - Remove check-tor script from repository. Resolves issue 29072. diff --git a/contrib/or-tools/check-tor b/contrib/or-tools/check-tor deleted file mode 100755 index e981a35fcc..0000000000 --- a/contrib/or-tools/check-tor +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh - -## Originally written by Peter Palfrader. - -## This script lets you quickly check if a given router (by nickname) -## will let you do a TLS handshake, or will let you download a directory. - -## Usage: check-tor nickname - -#set -x - -router="$1" -dirserver="http://belegost.seul.org:80/tor/" - -lines=$( wget -q $dirserver --proxy=off -O - | grep -A5 '^router '"$router"' ' ) -line=$( echo "$lines" | head -n1 ) - -if [ -z "$line" ]; then - echo "Not found" >&2 - exit 1 -fi - -echo "$lines" -echo - -ipor=$( echo "$line" | awk '{printf "%s:%s", $3, $4}' ) - -op=$( echo "$line" | awk '{printf $6}' ) -ipop=$( echo "$line" | awk '{printf "%s:%s", $3, $6}' ) - -echo -echo ">>" openssl s_client -connect "$ipor" -timeout 5 openssl s_client -connect "$ipor" < /dev/null -if [ "$op" != "0" ]; then - echo - echo ">>" wget --proxy=off -O - http://$ipop/tor/ - timeout 5 wget --proxy=off -O - http://$ipop/tor/ | head -n3 -fi - -echo -echo -n "$router "; echo "$lines" | grep 'fingerprint' | sed -e 's/^opt //' -e 's/^fingerprint //'; -- cgit v1.2.3-54-g00ecf From a798bd40fb108f83bcd3dea5c8fa8a60dbbb9fe2 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 8 Jan 2019 18:40:03 +1000 Subject: stats: Stop reporting statistics when ExtraInfoStatistics is 0 When ExtraInfoStatistics is 0, stop including bandwidth usage statistics, GeoIPFile hashes, ServerTransportPlugin lines, and bridge statistics by country in extra-info documents. Fixes bug 29018; bugfix on 0.2.4.1-alpha (and earlier versions). --- changes/bug29018 | 5 +++++ doc/tor.1.txt | 5 ++++- src/feature/relay/router.c | 49 +++++++++++++++++++++++----------------------- 3 files changed, 33 insertions(+), 26 deletions(-) create mode 100644 changes/bug29018 (limited to 'changes') diff --git a/changes/bug29018 b/changes/bug29018 new file mode 100644 index 0000000000..b006ae36a7 --- /dev/null +++ b/changes/bug29018 @@ -0,0 +1,5 @@ + o Minor bugfixes (stats): + - When ExtraInfoStatistics is 0, stop including bandwidth usage statistics, + GeoIPFile hashes, ServerTransportPlugin lines, and bridge statistics + by country in extra-info documents. Fixes bug 29018; + bugfix on 0.2.4.1-alpha. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 52f5bfa0c3..d94e0dcac2 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -2313,7 +2313,8 @@ is non-zero): When this option is enabled and BridgeRelay is also enabled, and we have GeoIP data, Tor keeps a per-country count of how many client addresses have contacted it so that it can help the bridge authority guess - which countries have blocked access to it. (Default: 1) + which countries have blocked access to it. If ExtraInfoStatistics is + enabled, it will be published as part of extra-info document. (Default: 1) [[ServerDNSRandomizeCase]] **ServerDNSRandomizeCase** **0**|**1**:: When this option is set, Tor sets the case of each character randomly in @@ -2395,6 +2396,8 @@ is non-zero): [[ExtraInfoStatistics]] **ExtraInfoStatistics** **0**|**1**:: When this option is enabled, Tor includes previously gathered statistics in its extra-info documents that it uploads to the directory authorities. + Disabling this option also disables bandwidth usage statistics, GeoIPFile + hashes, and ServerTransportPlugin lists in the extra-info file. (Default: 1) [[ExtendAllowPrivateAddresses]] **ExtendAllowPrivateAddresses** **0**|**1**:: diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index cdd032f78d..93bc8c96cb 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -2942,7 +2942,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, char identity[HEX_DIGEST_LEN+1]; char published[ISO_TIME_LEN+1]; char digest[DIGEST_LEN]; - char *bandwidth_usage; int result; static int write_stats_to_extrainfo = 1; char sig[DIROBJ_MAX_SIG_LEN+1]; @@ -2957,7 +2956,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, base16_encode(identity, sizeof(identity), extrainfo->cache_info.identity_digest, DIGEST_LEN); format_iso_time(published, extrainfo->cache_info.published_on); - bandwidth_usage = rep_hist_get_bandwidth_lines(); if (emit_ed_sigs) { if (!extrainfo->cache_info.signing_key_cert->signing_key_included || !ed25519_pubkey_eq(&extrainfo->cache_info.signing_key_cert->signed_key, @@ -2983,21 +2981,25 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, ed_cert_line = tor_strdup(""); } - tor_asprintf(&pre, "extra-info %s %s\n%spublished %s\n%s", + tor_asprintf(&pre, "extra-info %s %s\n%spublished %s\n", extrainfo->nickname, identity, ed_cert_line, - published, bandwidth_usage); + published); smartlist_add(chunks, pre); - if (geoip_is_loaded(AF_INET)) - smartlist_add_asprintf(chunks, "geoip-db-digest %s\n", - geoip_db_digest(AF_INET)); - if (geoip_is_loaded(AF_INET6)) - smartlist_add_asprintf(chunks, "geoip6-db-digest %s\n", - geoip_db_digest(AF_INET6)); - if (options->ExtraInfoStatistics && write_stats_to_extrainfo) { log_info(LD_GENERAL, "Adding stats to extra-info descriptor."); + /* Bandwidth usage stats don't have their own option */ + { + contents = rep_hist_get_bandwidth_lines(); + smartlist_add(chunks, contents); + } + if (geoip_is_loaded(AF_INET)) + smartlist_add_asprintf(chunks, "geoip-db-digest %s\n", + geoip_db_digest(AF_INET)); + if (geoip_is_loaded(AF_INET6)) + smartlist_add_asprintf(chunks, "geoip6-db-digest %s\n", + geoip_db_digest(AF_INET6)); if (options->DirReqStatistics && load_stats_file("stats"PATH_SEPARATOR"dirreq-stats", "dirreq-stats-end", now, &contents) > 0) { @@ -3033,19 +3035,17 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, if (contents) smartlist_add(chunks, contents); } - } - - /* Add information about the pluggable transports we support. */ - if (options->ServerTransportPlugin) { - char *pluggable_transports = pt_get_extra_info_descriptor_string(); - if (pluggable_transports) - smartlist_add(chunks, pluggable_transports); - } - - if (should_record_bridge_info(options) && write_stats_to_extrainfo) { - const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now); - if (bridge_stats) { - smartlist_add_strdup(chunks, bridge_stats); + /* Add information about the pluggable transports we support. */ + if (options->ServerTransportPlugin) { + char *pluggable_transports = pt_get_extra_info_descriptor_string(); + if (pluggable_transports) + smartlist_add(chunks, pluggable_transports); + } + if (should_record_bridge_info(options)) { + const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now); + if (bridge_stats) { + smartlist_add_strdup(chunks, bridge_stats); + } } } @@ -3139,7 +3139,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, tor_free(s_dup); tor_free(ed_cert_line); extrainfo_free(ei_tmp); - tor_free(bandwidth_usage); return result; } -- cgit v1.2.3-54-g00ecf From b25cd5cfe168b85500c160ca538a44d9adba52c1 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 19 Feb 2019 15:23:31 -0500 Subject: Implement code to manage a per-thread instance of crypto_fast_rng() The subsystems API makes this really simple, fortunately. Closes ticket 29536 --- changes/ticket29536 | 9 +++++ src/lib/crypt_ops/crypto_init.c | 7 ++++ src/lib/crypt_ops/crypto_rand.h | 9 +++++ src/lib/crypt_ops/crypto_rand_fast.c | 67 +++++++++++++++++++++++++++++++++++- 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 changes/ticket29536 (limited to 'changes') diff --git a/changes/ticket29536 b/changes/ticket29536 new file mode 100644 index 0000000000..a5ae26b701 --- /dev/null +++ b/changes/ticket29536 @@ -0,0 +1,9 @@ + o Minor features (performance, RNG): + - Tor now constructs a fast secure pseudorandom number generator for + each thread, to use for cases where performance is critical. This PRNG + is based on AES-CTR, using a buffering construction similar to + libottery and the (newer) OpenBSD arc4random() code. It outperforms + OpenSSL 1.1.1a's CSPRNG by roughly a factor of 100 for small outputs. + Although we believe it to be cryptographically strong, we are only + using it when necessary for reasonable performance. Implements tickets + 29023 and 29536. diff --git a/src/lib/crypt_ops/crypto_init.c b/src/lib/crypt_ops/crypto_init.c index 4040085c76..cf491f32d1 100644 --- a/src/lib/crypt_ops/crypto_init.c +++ b/src/lib/crypt_ops/crypto_init.c @@ -12,6 +12,8 @@ #include "orconfig.h" +#define CRYPTO_PRIVATE + #include "lib/crypt_ops/crypto_init.h" #include "lib/crypt_ops/crypto_curve25519.h" @@ -69,6 +71,8 @@ crypto_early_init(void) if (crypto_init_siphash_key() < 0) return -1; + crypto_rand_fast_init(); + curve25519_init(); ed25519_init(); } @@ -111,6 +115,7 @@ crypto_thread_cleanup(void) #ifdef ENABLE_OPENSSL crypto_openssl_thread_cleanup(); #endif + destroy_thread_fast_rng(); } /** @@ -129,6 +134,8 @@ crypto_global_cleanup(void) crypto_nss_global_cleanup(); #endif + crypto_rand_fast_shutdown(); + crypto_early_initialized_ = 0; crypto_global_initialized_ = 0; have_seeded_siphash = 0; diff --git a/src/lib/crypt_ops/crypto_rand.h b/src/lib/crypt_ops/crypto_rand.h index 8a81a4acdc..6eef22ed4d 100644 --- a/src/lib/crypt_ops/crypto_rand.h +++ b/src/lib/crypt_ops/crypto_rand.h @@ -68,6 +68,15 @@ unsigned crypto_fast_rng_get_uint(crypto_fast_rng_t *rng, unsigned limit); uint64_t crypto_fast_rng_get_uint64(crypto_fast_rng_t *rng, uint64_t limit); double crypto_fast_rng_get_double(crypto_fast_rng_t *rng); +crypto_fast_rng_t *get_thread_fast_rng(void); + +#ifdef CRYPTO_PRIVATE +/* These are only used from crypto_init.c */ +void destroy_thread_fast_rng(void); +void crypto_rand_fast_init(void); +void crypto_rand_fast_shutdown(void); +#endif + #if defined(TOR_UNIT_TESTS) /* Used for white-box testing */ size_t crypto_fast_rng_get_bytes_used_per_stream(void); diff --git a/src/lib/crypt_ops/crypto_rand_fast.c b/src/lib/crypt_ops/crypto_rand_fast.c index 34e763bf51..760e1025ed 100644 --- a/src/lib/crypt_ops/crypto_rand_fast.c +++ b/src/lib/crypt_ops/crypto_rand_fast.c @@ -33,6 +33,7 @@ */ #define CRYPTO_RAND_FAST_PRIVATE +#define CRYPTO_PRIVATE #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_cipher.h" @@ -41,6 +42,7 @@ #include "lib/intmath/cmp.h" #include "lib/cc/ctassert.h" #include "lib/malloc/map_anon.h" +#include "lib/thread/threads.h" #include "lib/log/util_bug.h" @@ -122,7 +124,8 @@ crypto_fast_rng_new(void) * long. * * Note that this object is NOT thread-safe. If you need a thread-safe - * prng, use crypto_rand(), or wrap this in a mutex. + * prng, you should probably look at get_thread_fast_rng(). Alternatively, + * use crypto_rand(), wrap this in a mutex. **/ crypto_fast_rng_t * crypto_fast_rng_new_from_seed(const uint8_t *seed) @@ -261,3 +264,65 @@ crypto_fast_rng_get_bytes_used_per_stream(void) return BUFLEN; } #endif + +/** + * Thread-local instance for our fast RNG. + **/ +static tor_threadlocal_t thread_rng; + +/** + * Return a per-thread fast RNG, initializing it if necessary. + * + * You do not need to free this yourself. + * + * It is NOT safe to share this value across threads. + **/ +crypto_fast_rng_t * +get_thread_fast_rng(void) +{ + crypto_fast_rng_t *rng = tor_threadlocal_get(&thread_rng); + + if (PREDICT_UNLIKELY(rng == NULL)) { + rng = crypto_fast_rng_new(); + tor_threadlocal_set(&thread_rng, rng); + } + + return rng; +} + +/** + * Used when a thread is exiting: free the per-thread fast RNG if needed. + * Invoked from the crypto subsystem's thread-cleanup code. + **/ +void +destroy_thread_fast_rng(void) +{ + crypto_fast_rng_t *rng = tor_threadlocal_get(&thread_rng); + if (!rng) + return; + crypto_fast_rng_free(rng); + tor_threadlocal_set(&thread_rng, NULL); +} + +/** + * Initialize the global thread-local key that will be used to keep track + * of per-thread fast RNG instances. Called from the crypto subsystem's + * initialization code. + **/ +void +crypto_rand_fast_init(void) +{ + tor_threadlocal_init(&thread_rng); +} + +/** + * Initialize the global thread-local key that will be used to keep track + * of per-thread fast RNG instances. Called from the crypto subsystem's + * shutdown code. + **/ +void +crypto_rand_fast_shutdown(void) +{ + destroy_thread_fast_rng(); + tor_threadlocal_destroy(&thread_rng); +} -- cgit v1.2.3-54-g00ecf From 249319ec5d3a17faf9a6060f1b3109f640874863 Mon Sep 17 00:00:00 2001 From: Roger Dingledine Date: Wed, 20 Feb 2019 10:32:47 -0500 Subject: fix typos from #28614 --- changes/ticket28614 | 2 +- src/feature/nodelist/networkstatus.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'changes') diff --git a/changes/ticket28614 b/changes/ticket28614 index 6c65ce49de..3c93313726 100644 --- a/changes/ticket28614 +++ b/changes/ticket28614 @@ -3,6 +3,6 @@ "binary" mode so that we can safely map it into memory later. Fixes part of bug 28614; bugfix on 0.4.0.1-alpha. - When reading a consensus file from disk, detect whether it - was written in text mode, and re-read it in text mode if it + was written in text mode, and re-read it in text mode if so. Fixes part of bug 28614; bugfix on 0.4.0.1-alpha. diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index 2c34754621..023115978c 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -1743,7 +1743,7 @@ networkstatus_set_current_consensus_from_ns(networkstatus_t *c, #endif /* defined(TOR_UNIT_TESTS) */ /** - * Helper: Read a the current consensus of type flavor from + * Helper: Read the current consensus of type flavor from * fname. Flags and return values are as for * networkstatus_set_current_consensus(). **/ -- cgit v1.2.3-54-g00ecf From b7ad8bcaad093a5d043c63f30c196c52741830d2 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Wed, 13 Feb 2019 15:50:09 +0200 Subject: Use setrlimit instead of ulimit -c in backtrace tests --- changes/bug29061 | 4 ++++ src/test/test_bt.sh | 2 -- src/test/test_bt_cl.c | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 changes/bug29061 (limited to 'changes') diff --git a/changes/bug29061 b/changes/bug29061 new file mode 100644 index 0000000000..58fc4f22e9 --- /dev/null +++ b/changes/bug29061 @@ -0,0 +1,4 @@ + o Minor bugfixes (testing): + - Call setrlimit() to disable core dumps in test_bt_cl.c instead of + using `ulimit -c` in test_bt.sh, which violates POSIX shell + compatibility. Fixes bug 29061; bugfix on 0.3.5.1-alpha. diff --git a/src/test/test_bt.sh b/src/test/test_bt.sh index df8bcb8eda..312905a4e2 100755 --- a/src/test/test_bt.sh +++ b/src/test/test_bt.sh @@ -3,8 +3,6 @@ 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_bt_cl.c b/src/test/test_bt_cl.c index 0c15a02ee4..08b08ba423 100644 --- a/src/test/test_bt_cl.c +++ b/src/test/test_bt_cl.c @@ -4,6 +4,9 @@ #include "orconfig.h" #include #include +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif /* To prevent 'assert' from going away. */ #undef TOR_COVERAGE @@ -88,6 +91,11 @@ main(int argc, char **argv) return 1; } +#ifdef HAVE_SYS_RESOURCE_H + struct rlimit rlim = { .rlim_cur = 0, .rlim_max = 0 }; + setrlimit(RLIMIT_CORE, &rlim); +#endif + #if !(defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)) puts("Backtrace reporting is not supported on this platform"); -- cgit v1.2.3-54-g00ecf From b3416476b487304426296173dd177e1277388e48 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 20 Feb 2019 12:21:23 -0500 Subject: Remove all uses of weak_rng. I'm not removing the weak_rng code itself yet, since it is possible that we will want to revert one of these. --- changes/ticket29542 | 7 +++++++ src/app/main/main.c | 2 +- src/core/mainloop/cpuworker.c | 7 ++----- src/core/or/relay.c | 14 ++------------ src/core/or/relay.h | 3 --- src/lib/evloop/workqueue.c | 10 +--------- 6 files changed, 13 insertions(+), 30 deletions(-) create mode 100644 changes/ticket29542 (limited to 'changes') diff --git a/changes/ticket29542 b/changes/ticket29542 new file mode 100644 index 0000000000..465a8e31bc --- /dev/null +++ b/changes/ticket29542 @@ -0,0 +1,7 @@ + o Minor features (defense in depth): + - Tor now uses a fast cryptographically strong PRNG even for decisions + that we do not believe are security-sensitive. Previously, for + performance reasons, we had used a trivially predictable linear + congruential generator algorithm for certain load-balancing and + statistical sampling decisions. Now we use our fast RNG in those cases. + Closes ticket 29542. diff --git a/src/app/main/main.c b/src/app/main/main.c index 0ffc27d456..ec15109f6c 100644 --- a/src/app/main/main.c +++ b/src/app/main/main.c @@ -669,7 +669,7 @@ tor_init(int argc, char *argv[]) log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting."); return -1; } - stream_choice_seed_weak_rng(); + if (tor_init_libevent_rng() < 0) { log_warn(LD_NET, "Problem initializing libevent RNG."); } diff --git a/src/core/mainloop/cpuworker.c b/src/core/mainloop/cpuworker.c index e704d55642..436fcd28c3 100644 --- a/src/core/mainloop/cpuworker.c +++ b/src/core/mainloop/cpuworker.c @@ -34,7 +34,6 @@ #include "core/crypto/onion_crypto.h" #include "core/or/or_circuit_st.h" -#include "lib/intmath/weakrng.h" static void queue_pending_tasks(void); @@ -74,8 +73,6 @@ worker_state_free_void(void *arg) static replyqueue_t *replyqueue = NULL; static threadpool_t *threadpool = NULL; -static tor_weak_rng_t request_sample_rng = TOR_WEAK_RNG_INIT; - static int total_pending_tasks = 0; static int max_pending_tasks = 128; @@ -109,7 +106,6 @@ cpu_init(void) /* Total voodoo. Can we make this more sensible? */ max_pending_tasks = get_num_cpus(get_options()) * 64; - crypto_seed_weak_rng(&request_sample_rng); } /** Magic numbers to make sure our cpuworker_requests don't grow any @@ -235,9 +231,10 @@ should_time_request(uint16_t onionskin_type) * sample */ if (onionskins_n_processed[onionskin_type] < 4096) return 1; + /** Otherwise, measure with P=1/128. We avoid doing this for every * handshake, since the measurement itself can take a little time. */ - return tor_weak_random_one_in_n(&request_sample_rng, 128); + return crypto_fast_rng_one_in_n(get_thread_fast_rng(), 128); } /** Return an estimate of how many microseconds we will need for a single diff --git a/src/core/or/relay.c b/src/core/or/relay.c index 706a6e05cb..7f7fa2fe1f 100644 --- a/src/core/or/relay.c +++ b/src/core/or/relay.c @@ -94,8 +94,6 @@ #include "feature/nodelist/routerinfo_st.h" #include "core/or/socks_request_st.h" -#include "lib/intmath/weakrng.h" - static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction, crypt_path_t *layer_hint); @@ -134,9 +132,6 @@ uint64_t stats_n_relay_cells_delivered = 0; * reached (see append_cell_to_circuit_queue()) */ uint64_t stats_n_circ_max_cell_reached = 0; -/** Used to tell which stream to read from first on a circuit. */ -static tor_weak_rng_t stream_choice_rng = TOR_WEAK_RNG_INIT; - /** * Update channel usage state based on the type of relay cell and * circuit properties. @@ -2180,12 +2175,6 @@ circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) circ, layer_hint); } -void -stream_choice_seed_weak_rng(void) -{ - crypto_seed_weak_rng(&stream_choice_rng); -} - /** A helper function for circuit_resume_edge_reading() above. * The arguments are the same, except that conn is the head * of a linked list of edge streams that should each be considered. @@ -2237,7 +2226,8 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn, int num_streams = 0; for (conn = first_conn; conn; conn = conn->next_stream) { num_streams++; - if (tor_weak_random_one_in_n(&stream_choice_rng, num_streams)) { + + if (crypto_fast_rng_one_in_n(get_thread_fast_rng(), num_streams)) { chosen_stream = conn; } /* Invariant: chosen_stream has been chosen uniformly at random from diff --git a/src/core/or/relay.h b/src/core/or/relay.h index 044f6be156..ea1b358ffb 100644 --- a/src/core/or/relay.h +++ b/src/core/or/relay.h @@ -94,8 +94,6 @@ const uint8_t *decode_address_from_payload(tor_addr_t *addr_out, int payload_len); void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan); -void stream_choice_seed_weak_rng(void); - circid_t packed_cell_get_circid(const packed_cell_t *cell, int wide_circ_ids); #ifdef RELAY_PRIVATE @@ -126,4 +124,3 @@ STATIC int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, #endif /* defined(RELAY_PRIVATE) */ #endif /* !defined(TOR_RELAY_H) */ - diff --git a/src/lib/evloop/workqueue.c b/src/lib/evloop/workqueue.c index b36a02da5e..015b694290 100644 --- a/src/lib/evloop/workqueue.c +++ b/src/lib/evloop/workqueue.c @@ -59,9 +59,6 @@ struct threadpool_s { * p is work[p]. */ work_tailq_t work[WORKQUEUE_N_PRIORITIES]; - /** Weak RNG, used to decide when to ignore priority. */ - tor_weak_rng_t weak_rng; - /** The current 'update generation' of the threadpool. Any thread that is * at an earlier generation needs to run the update function. */ unsigned generation; @@ -238,7 +235,7 @@ worker_thread_extract_next_work(workerthread_t *thread) this_queue = &pool->work[i]; if (!TOR_TAILQ_EMPTY(this_queue)) { queue = this_queue; - if (! tor_weak_random_one_in_n(&pool->weak_rng, + if (! crypto_fast_rng_one_in_n(get_thread_fast_rng(), thread->lower_priority_chance)) { /* Usually we'll just break now, so that we can get out of the loop * and use the queue where we found work. But with a small @@ -555,11 +552,6 @@ threadpool_new(int n_threads, for (i = WORKQUEUE_PRIORITY_FIRST; i <= WORKQUEUE_PRIORITY_LAST; ++i) { TOR_TAILQ_INIT(&pool->work[i]); } - { - unsigned seed; - crypto_rand((void*)&seed, sizeof(seed)); - tor_init_weak_random(&pool->weak_rng, seed); - } pool->new_thread_state_fn = new_thread_state_fn; pool->new_thread_state_arg = arg; -- cgit v1.2.3-54-g00ecf From 658770a0f05810cf9a12f4efe349ecda9b63c969 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 21 Feb 2019 10:33:16 -0500 Subject: Remove changes entries for fixes that appeared in 0.4.0.2-alpha --- changes/bug28698 | 3 --- changes/bug28979 | 4 ---- changes/bug28981 | 5 ----- changes/bug29029 | 5 ----- changes/bug29040 | 4 ---- changes/bug29042 | 5 ----- changes/bug29122 | 3 --- changes/bug29135 | 5 ----- changes/bug29145 | 3 --- changes/bug29150 | 3 --- changes/bug29161 | 3 --- changes/bug29169 | 3 --- changes/bug29175_035 | 4 ---- changes/bug29244 | 4 ---- changes/bug29298 | 5 ----- changes/bug29508 | 3 --- changes/doc28623 | 3 --- changes/feature28976 | 4 ---- changes/geoip-2019-02-05 | 4 ---- changes/ticket26698 | 4 ---- changes/ticket27761 | 4 ---- changes/ticket28614 | 8 -------- changes/ticket28668 | 3 --- changes/ticket29026 | 4 ---- changes/ticket29072 | 2 -- changes/ticket29160 | 4 ---- changes/ticket29168 | 5 ----- 27 files changed, 107 deletions(-) delete mode 100644 changes/bug28698 delete mode 100644 changes/bug28979 delete mode 100644 changes/bug28981 delete mode 100644 changes/bug29029 delete mode 100644 changes/bug29040 delete mode 100644 changes/bug29042 delete mode 100644 changes/bug29122 delete mode 100644 changes/bug29135 delete mode 100644 changes/bug29145 delete mode 100644 changes/bug29150 delete mode 100644 changes/bug29161 delete mode 100644 changes/bug29169 delete mode 100644 changes/bug29175_035 delete mode 100644 changes/bug29244 delete mode 100644 changes/bug29298 delete mode 100644 changes/bug29508 delete mode 100644 changes/doc28623 delete mode 100644 changes/feature28976 delete mode 100644 changes/geoip-2019-02-05 delete mode 100644 changes/ticket26698 delete mode 100644 changes/ticket27761 delete mode 100644 changes/ticket28614 delete mode 100644 changes/ticket28668 delete mode 100644 changes/ticket29026 delete mode 100644 changes/ticket29072 delete mode 100644 changes/ticket29160 delete mode 100644 changes/ticket29168 (limited to 'changes') diff --git a/changes/bug28698 b/changes/bug28698 deleted file mode 100644 index 716aa0c552..0000000000 --- a/changes/bug28698 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfix (logging): - - Avoid logging about relaxing circuits when their time is fixed. - Fixes bug 28698; bugfix on 0.2.4.7-alpha diff --git a/changes/bug28979 b/changes/bug28979 deleted file mode 100644 index 0625fd5d25..0000000000 --- a/changes/bug28979 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (documentation): - - Describe the contents of the v3 onion service client authorization - files correctly: They hold public keys, not private keys. Fixes bug - 28979; bugfix on 0.3.5.1-alpha. Spotted by "Felixix". diff --git a/changes/bug28981 b/changes/bug28981 deleted file mode 100644 index c0ea92ab35..0000000000 --- a/changes/bug28981 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (misc): - - The amount of total available physical memory is now determined - using the sysctl identifier HW_PHYSMEM (rather than HW_USERMEM) - when it is defined and a 64-bit variant is not available. Fixes - bug 28981; bugfix on 0.2.5.4-alpha. Patch from Kris Katterjohn. diff --git a/changes/bug29029 b/changes/bug29029 deleted file mode 100644 index e100a8c2ed..0000000000 --- a/changes/bug29029 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (logging, onion services): - - Stop logging "Tried to establish rendezvous on non-OR circuit..." as - a warning. Instead, log it as a protocol warning, because there is - nothing that relay operators can do to fix it. Fixes bug 29029; - bugfix on 0.2.5.7-rc. diff --git a/changes/bug29040 b/changes/bug29040 deleted file mode 100644 index 0662aaa8a5..0000000000 --- a/changes/bug29040 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (onion services): - - Avoid crashing if ClientOnionAuthDir (incorrectly) contains - more than one private key for a hidden service. Fixes bug 29040; - bugfix on 0.3.5.1-alpha. diff --git a/changes/bug29042 b/changes/bug29042 deleted file mode 100644 index 8d76939cea..0000000000 --- a/changes/bug29042 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (logging): - - Log more information at "warning" level when unable to read a private - key; log more information ad "info" level when unable to read a public - key. We had warnings here before, but they were lost during our - NSS work. Fixes bug 29042; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug29122 b/changes/bug29122 deleted file mode 100644 index 020052ff8f..0000000000 --- a/changes/bug29122 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (unit tests): - - Fix intermittent failures on an adaptive padding unittest. Fixes bug - 29122; bugfix on 0.4.0.1-alpha diff --git a/changes/bug29135 b/changes/bug29135 deleted file mode 100644 index fd7b1ae80e..0000000000 --- a/changes/bug29135 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (onion services, logging): - - In hs_cache_store_as_client() log an HSDesc we failed to parse at Debug - loglevel. Tor used to log it at Warning loglevel, which caused - very long log lines to appear for some users. Fixes bug 29135; bugfix on - 0.3.2.1-alpha. diff --git a/changes/bug29145 b/changes/bug29145 deleted file mode 100644 index 40d3da4b91..0000000000 --- a/changes/bug29145 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (compilation, testing): - - Silence a compiler warning in test-memwipe.c on OpenBSD. Fixes - bug 29145; bugfix on 0.2.9.3-alpha. Patch from Kris Katterjohn. diff --git a/changes/bug29150 b/changes/bug29150 deleted file mode 100644 index 7696b90378..0000000000 --- a/changes/bug29150 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (linux seccomp sandbox): - - Fix startup crash when experimental sandbox support is enabled. - Fixes bug 29150; bugfix on 0.4.0.1-alpha. Patch by Peter Gerber. diff --git a/changes/bug29161 b/changes/bug29161 deleted file mode 100644 index 39a638acf6..0000000000 --- a/changes/bug29161 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (tests): - - Detect and suppress "bug" warnings from the util/time test on Windows. - Fixes bug 29161; bugfix on 0.2.9.3-alpha. diff --git a/changes/bug29169 b/changes/bug29169 deleted file mode 100644 index 41d4b76ef5..0000000000 --- a/changes/bug29169 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (compilation): - - Fix compilation warnings in test_circuitpadding.c. Fixes bug 29169; - bugfix on 0.4.0.1-alpha. diff --git a/changes/bug29175_035 b/changes/bug29175_035 deleted file mode 100644 index 134c1d9529..0000000000 --- a/changes/bug29175_035 +++ /dev/null @@ -1,4 +0,0 @@ - o Major bugfixes (networking): - - Gracefully handle empty username/password fields in SOCKS5 - username/password auth messsage and allow SOCKS5 handshake to - continue. Fixes bug 29175; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug29244 b/changes/bug29244 deleted file mode 100644 index 6206a95463..0000000000 --- a/changes/bug29244 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (build, compatibility): - - Update Cargo.lock file to match the version made by the latest - version of Rust, so that "make distcheck" will pass again. - Fixes bug 29244; bugfix on 0.3.3.4-alpha. diff --git a/changes/bug29298 b/changes/bug29298 deleted file mode 100644 index df12db77d7..0000000000 --- a/changes/bug29298 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (testing, circuit padding): - - Disabled unstable circuit padding unittest that was causing intermittent - test failures because of ill-defined small histogram. Such histograms - will be allowed again after 29298 is implemented. Fixes second case of - bug 29122; bugfix on 0.4.0.1-alpha. \ No newline at end of file diff --git a/changes/bug29508 b/changes/bug29508 deleted file mode 100644 index ee728bbbc9..0000000000 --- a/changes/bug29508 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (scheduler): - - When readding channels to the pending list, check the correct channel's - sched_heap_idx. Fixes bug 29508; bugfix on 0.3.2.10 diff --git a/changes/doc28623 b/changes/doc28623 deleted file mode 100644 index 3c3313abdd..0000000000 --- a/changes/doc28623 +++ /dev/null @@ -1,3 +0,0 @@ - o Documentation: - - In manpage entry describing MapAddress torrc setting, use example - IP addresses from ranges specified by RFC 5737. Resolves issue 28623. diff --git a/changes/feature28976 b/changes/feature28976 deleted file mode 100644 index c7ebc207f7..0000000000 --- a/changes/feature28976 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (developer tooling): - - Provide a git pre-commit hook that disallows commiting if we have any - failures in our code and changelog formatting checks. It is now available - in scripts/maint/pre-commit.git-hook. Implements feature 28976. diff --git a/changes/geoip-2019-02-05 b/changes/geoip-2019-02-05 deleted file mode 100644 index 78ee6d4242..0000000000 --- a/changes/geoip-2019-02-05 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (geoip): - - Update geoip and geoip6 to the February 5 2019 Maxmind GeoLite2 - Country database. Closes ticket 29478. - diff --git a/changes/ticket26698 b/changes/ticket26698 deleted file mode 100644 index 6b029a1b73..0000000000 --- a/changes/ticket26698 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (directory authority): - - When a directory authority is using a bandwidth file to obtain the - bandwidth values, include the digest of the file in the vote. - Closes ticket 26698. diff --git a/changes/ticket27761 b/changes/ticket27761 deleted file mode 100644 index 35106ee9c6..0000000000 --- a/changes/ticket27761 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (changelogs): - - Check that bugfix versions in changes files look like Tor versions - from the versions spec. Warn when bugfixes claim to be on a future - release. Closes ticket 27761. diff --git a/changes/ticket28614 b/changes/ticket28614 deleted file mode 100644 index 3c93313726..0000000000 --- a/changes/ticket28614 +++ /dev/null @@ -1,8 +0,0 @@ - o Major bugfixes (windows, startup): - - When writing a consensus file to disk, always write in - "binary" mode so that we can safely map it into memory later. - Fixes part of bug 28614; bugfix on 0.4.0.1-alpha. - - When reading a consensus file from disk, detect whether it - was written in text mode, and re-read it in text mode if so. - Fixes part of bug 28614; bugfix on 0.4.0.1-alpha. - diff --git a/changes/ticket28668 b/changes/ticket28668 deleted file mode 100644 index 6386e0051f..0000000000 --- a/changes/ticket28668 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (testing): - - Treat all unexpected ERR and BUG messages as test failures. - Closes ticket 28668. diff --git a/changes/ticket29026 b/changes/ticket29026 deleted file mode 100644 index 1db873dfcf..0000000000 --- a/changes/ticket29026 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (compilation): - - Compile correctly when OpenSSL is built with engine support - disabled, or with deprecated APIs disabled. Closes ticket - 29026. Patches from "Mangix". diff --git a/changes/ticket29072 b/changes/ticket29072 deleted file mode 100644 index 3526330f30..0000000000 --- a/changes/ticket29072 +++ /dev/null @@ -1,2 +0,0 @@ - o Removed features: - - Remove check-tor script from repository. Resolves issue 29072. diff --git a/changes/ticket29160 b/changes/ticket29160 deleted file mode 100644 index 8e11183064..0000000000 --- a/changes/ticket29160 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (tests): - - Do not log an error-level message if we fail to find an IPv6 - network interface from the unit tests. Fixes bug 29160; bugfix on - 0.2.7.3-rc. diff --git a/changes/ticket29168 b/changes/ticket29168 deleted file mode 100644 index 65c5232f65..0000000000 --- a/changes/ticket29168 +++ /dev/null @@ -1,5 +0,0 @@ - o Major bugfixes (cell scheduler, KIST): - - Make KIST to always take into account the outbuf length when computing - what we can actually put in the outbuf. This could lead to the outbuf - being filled up and thus a possible memory DoS vector. TROVE-2019-001. - Fixes bug 29168; bugfix on 0.3.2.1-alpha. -- cgit v1.2.3-54-g00ecf From b3b737b8750b2063c5be260287088defbfadd1b9 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 21 Feb 2019 13:35:33 -0500 Subject: Update pre-commit.git-hook for ticket 29553 - handle older source layout - handle empty changes directories - "set -e" so that we exit if there's a problem. --- changes/ticket29553 | 5 +++++ scripts/maint/pre-commit.git-hook | 33 ++++++++++++++++++++++++--------- 2 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 changes/ticket29553 (limited to 'changes') diff --git a/changes/ticket29553 b/changes/ticket29553 new file mode 100644 index 0000000000..af441b92b0 --- /dev/null +++ b/changes/ticket29553 @@ -0,0 +1,5 @@ + o Minor bugfixes (developer tools): + - Update our pre-commit.git-hook script to work correctly on older Tor + branches and release branches without any changes files, + and to actually exit when something fails. Fixes bug 29553; bugfix on + 0.4.0.2-alpha. diff --git a/scripts/maint/pre-commit.git-hook b/scripts/maint/pre-commit.git-hook index b4c4ce2061..65fa99f4c4 100755 --- a/scripts/maint/pre-commit.git-hook +++ b/scripts/maint/pre-commit.git-hook @@ -10,16 +10,31 @@ workdir=$(git rev-parse --show-toplevel) cd "$workdir" || exit 1 -python scripts/maint/lintChanges.py ./changes/* +set -e -perl scripts/maint/checkSpace.pl -C \ -src/lib/*/*.[ch] \ -src/core/*/*.[ch] \ -src/feature/*/*.[ch] \ -src/app/*/*.[ch] \ -src/test/*.[ch] \ -src/test/*/*.[ch] \ -src/tools/*.[ch] +if [ ! -z "ls ./changes/*" ]; then + python scripts/maint/lintChanges.py ./changes/* +fi + +if [ -d src/lib ]; then + # This is the layout in 0.3.5 + perl scripts/maint/checkSpace.pl -C \ + src/lib/*/*.[ch] \ + src/core/*/*.[ch] \ + src/feature/*/*.[ch] \ + src/app/*/*.[ch] \ + src/test/*.[ch] \ + src/test/*/*.[ch] \ + src/tools/*.[ch] +elif [ -d src/common]; then + # This was the layout before 0.3.5 + perl scripts/maint/checkSpace.pl -C \ + src/common/*/*.[ch] \ + src/or/*/*.[ch] \ + src/test/*.[ch] \ + src/test/*/*.[ch] \ + src/tools/*.[ch] +fi if test -e scripts/maint/checkIncludes.py; then python scripts/maint/checkIncludes.py -- cgit v1.2.3-54-g00ecf From df8ad6473575e217fe69de7d0d12341a1162b95e Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Fri, 22 Feb 2019 13:36:02 -0500 Subject: When a DirAuth checks reachability on itself and has IPv6, mark it as reachable --- changes/bug24338 | 4 ++++ src/feature/dirauth/voteflags.c | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 changes/bug24338 (limited to 'changes') diff --git a/changes/bug24338 b/changes/bug24338 new file mode 100644 index 0000000000..75984b6329 --- /dev/null +++ b/changes/bug24338 @@ -0,0 +1,4 @@ + o Minor bugfixes (dirauth, ipv6): + - If we are a durauth with IPv6 and are marking relays as running, mark + ourselves as reachable on IPv6. Fixes bug 24338; bugfix on 0.4.0.2-alpha. + Patch by Neel Chauhan diff --git a/src/feature/dirauth/voteflags.c b/src/feature/dirauth/voteflags.c index 4f7593a3e1..0a53c588d6 100644 --- a/src/feature/dirauth/voteflags.c +++ b/src/feature/dirauth/voteflags.c @@ -531,6 +531,20 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now) node->is_running = answer; } +/* Check node and ri on whether or not we should publish a + * relay's IPv6 addresses. */ +static int +should_publish_node_ipv6(const node_t *node, const routerinfo_t *ri, + time_t now) +{ + const or_options_t *options = get_options(); + + return options->AuthDirHasIPv6Connectivity == 1 && + !tor_addr_is_null(&ri->ipv6_addr) && + ((node->last_reachable6 >= now - REACHABLE_TIMEOUT) || + router_is_me(ri)); +} + /** Extract status information from ri and from other authority * functions and store it in rs. rs is zeroed out before it is * set. @@ -597,9 +611,7 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs, rs->is_staledesc = (ri->cache_info.published_on + DESC_IS_STALE_INTERVAL) < now; - if (options->AuthDirHasIPv6Connectivity == 1 && - !tor_addr_is_null(&ri->ipv6_addr) && - node->last_reachable6 >= now - REACHABLE_TIMEOUT) { + if (should_publish_node_ipv6(node, ri, now)) { /* We're configured as having IPv6 connectivity. There's an IPv6 OR port and it's reachable so copy it to the routerstatus. */ tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr); -- cgit v1.2.3-54-g00ecf From b7dced893a7de1c0ba303905f69022fee7d05fc9 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Thu, 7 Feb 2019 17:05:14 +0200 Subject: Fix shellcheck SC2006 warnings in test_switch_id.sh --- changes/ticket29065 | 3 +++ src/test/test_switch_id.sh | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 changes/ticket29065 (limited to 'changes') diff --git a/changes/ticket29065 b/changes/ticket29065 new file mode 100644 index 0000000000..edf00ac99c --- /dev/null +++ b/changes/ticket29065 @@ -0,0 +1,3 @@ + o Code simplification and refactoring (shell scripts): + - Cleanup test_switch_id.sh to silence shellcheck warnings. Closes + ticket 29065. diff --git a/src/test/test_switch_id.sh b/src/test/test_switch_id.sh index 79c44f2eb1..b13bf7602f 100755 --- a/src/test/test_switch_id.sh +++ b/src/test/test_switch_id.sh @@ -1,11 +1,11 @@ #!/bin/sh -if test "`id -u`" != '0'; then +if test "$(id -u)" != '0'; then echo "This test only works when run as root. Skipping." >&2 exit 77 fi -if test "`id -u nobody`" = ""; then +if test "$(id -u nobody)" = ""; then echo "This test requires that your system have a 'nobody' user. Sorry." >&2 exit 1 fi -- cgit v1.2.3-54-g00ecf From d731ab45831cfc2104b17b3a623e0c89c3174145 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Mon, 25 Feb 2019 19:07:47 +0200 Subject: Check that all valid values of int and unsigned int can be put into void pointer --- changes/ticket29537 | 3 +++ src/test/include.am | 1 + src/test/test.h | 1 + src/test/test_ptr_slow.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ src/test/test_slow.c | 1 + 5 files changed, 73 insertions(+) create mode 100644 changes/ticket29537 create mode 100644 src/test/test_ptr_slow.c (limited to 'changes') diff --git a/changes/ticket29537 b/changes/ticket29537 new file mode 100644 index 0000000000..048e13c65f --- /dev/null +++ b/changes/ticket29537 @@ -0,0 +1,3 @@ + o Testing: + - Check that all valid values of `int` and `unsigned int` can be + represented by `void *`. Resolves issue 29537. diff --git a/src/test/include.am b/src/test/include.am index d585c2a38a..e6cebe1d1a 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -211,6 +211,7 @@ src_test_test_slow_SOURCES += \ src/test/test_crypto_slow.c \ src/test/test_process_slow.c \ src/test/test_prob_distr.c \ + src/test/test_ptr_slow.c \ src/test/testing_common.c \ src/test/testing_rsakeys.c \ src/ext/tinytest.c diff --git a/src/test/test.h b/src/test/test.h index 2564432985..9d9184e2aa 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -278,6 +278,7 @@ extern struct testcase_t x509_tests[]; extern struct testcase_t slow_crypto_tests[]; extern struct testcase_t slow_process_tests[]; +extern struct testcase_t slow_ptr_tests[]; extern struct testgroup_t testgroups[]; diff --git a/src/test/test_ptr_slow.c b/src/test/test_ptr_slow.c new file mode 100644 index 0000000000..a5914c9120 --- /dev/null +++ b/src/test/test_ptr_slow.c @@ -0,0 +1,67 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "core/or/or.h" +#include "test/test.h" + +#include +#include + +/** Check that all values of int can be cast to void * and back. */ +static void +test_int_voidstar_interop(void *arg) +{ + int a; + (void)arg; + + for (a = INT_MIN; a < INT_MAX; a++) { + intptr_t ap = (intptr_t)a; + void *b = (void *)ap; + intptr_t c = (intptr_t)b; + void *d = (void *)c; + + tt_assert(ap == c); + tt_assert(b == d); + } + + done: + return; +} + +/** Check that all values of unsigned int can be cast to void * and back. */ +static void +test_uint_voidstar_interop(void *arg) +{ + unsigned int a; + (void)arg; + + for (a = 0; a < UINT_MAX; a++) { + intptr_t ap = (intptr_t)a; + void *b = (void *)ap; + intptr_t c = (intptr_t)b; + void *d = (void *)c; + + tt_assert(ap == c); + tt_assert(b == d); + } + + done: + return; +} + +struct testcase_t slow_ptr_tests[] = { + { .name = "int_voidstar_interop", + .fn = test_int_voidstar_interop, + .flags = 0, + .setup = NULL, + .setup_data = NULL }, + { .name = "uint_voidstar_interop", + .fn = test_uint_voidstar_interop, + .flags = 0, + .setup = NULL, + .setup_data = NULL }, + END_OF_TESTCASES +}; diff --git a/src/test/test_slow.c b/src/test/test_slow.c index c3e7edd408..d4d5b755a5 100644 --- a/src/test/test_slow.c +++ b/src/test/test_slow.c @@ -22,6 +22,7 @@ struct testgroup_t testgroups[] = { { "slow/crypto/", slow_crypto_tests }, { "slow/process/", slow_process_tests }, { "slow/prob_distr/", slow_stochastic_prob_distr_tests }, + { "slow/ptr/", slow_ptr_tests }, END_OF_GROUPS }; -- cgit v1.2.3-54-g00ecf From aa360b255bc1c262486500655bac70c4f0f00118 Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Tue, 26 Feb 2019 15:26:33 +0100 Subject: Fix crash bug in PT subsystem. This patch fixes a crash bug (assertion failure) in the PT subsystem that could get triggered if the user cancels bootstrap via the UI in TorBrowser. This would cause Tor to call `managed_proxy_destroy()` which called `process_free()` after it had called `process_terminate()`. This leads to a crash when the various process callbacks returns with data after the `process_t` have been freed using `process_free()`. We solve this issue by ensuring that everywhere we call `process_terminate()` we make sure to detach the `managed_proxy_t` from the `process_t` (by calling `process_set_data(process, NULL)`) and avoid calling `process_free()` at all in the transports code. Instead we just call `process_terminate()` and let the process exit callback in `managed_proxy_exit_callback()` handle the `process_free()` call by returning true to the process subsystem. See: https://bugs.torproject.org/29562 --- changes/bug29562 | 4 ++++ src/feature/client/transports.c | 29 ++++++++++++++--------------- 2 files changed, 18 insertions(+), 15 deletions(-) create mode 100644 changes/bug29562 (limited to 'changes') diff --git a/changes/bug29562 b/changes/bug29562 new file mode 100644 index 0000000000..0621cd09a0 --- /dev/null +++ b/changes/bug29562 @@ -0,0 +1,4 @@ + o Minor bugfixes (pluggable transports): + - Fix an assertion failure crash bug when a pluggable transport process is + terminated during the bootstrap phase. Fixes bug 29562; bugfix on + 0.4.0.1-alpha. diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c index e247055164..e7ff3bf34a 100644 --- a/src/feature/client/transports.c +++ b/src/feature/client/transports.c @@ -713,10 +713,13 @@ managed_proxy_destroy(managed_proxy_t *mp, tor_free(mp->proxy_uri); /* do we want to terminate our process if it's still running? */ - if (also_terminate_process && mp->process) + if (also_terminate_process && mp->process) { + /* Note that we do not call process_free(mp->process) here because we let + * the exit handler in managed_proxy_exit_callback() return `true` which + * makes the process subsystem deallocate the process_t. */ + process_set_data(mp->process, NULL); process_terminate(mp->process); - - process_free(mp->process); + } tor_free(mp); } @@ -1823,6 +1826,9 @@ managed_proxy_stdout_callback(process_t *process, managed_proxy_t *mp = process_get_data(process); + if (BUG(mp == NULL)) + return; + handle_proxy_line(line, mp); if (proxy_configuration_finished(mp)) { @@ -1846,6 +1852,9 @@ managed_proxy_stderr_callback(process_t *process, managed_proxy_t *mp = process_get_data(process); + if (BUG(mp == NULL)) + return; + log_warn(LD_PT, "Managed proxy at '%s' reported: %s", mp->argv[0], line); } @@ -1862,18 +1871,8 @@ managed_proxy_exit_callback(process_t *process, process_exit_code_t exit_code) "Pluggable Transport process terminated with status code %" PRIu64, exit_code); - /* We detach ourself from the MP (if we are attached) and free ourself. */ - managed_proxy_t *mp = process_get_data(process); - - /* If we are still attached to the process, it is probably because our PT - * process crashed before we got to call process_set_data(p, NULL); */ - if (BUG(mp != NULL)) { - /* FIXME(ahf): Our process stopped without us having told it to stop - * (crashed). Should we restart it here? */ - mp->process = NULL; - process_set_data(process, NULL); - } - + /* Returning true here means that the process subsystem will take care of + * calling process_free() on our process_t. */ return true; } -- cgit v1.2.3-54-g00ecf From e1ad22643e414da9802f4f5c2522fde35933fd47 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 14 Feb 2019 14:27:40 -0500 Subject: maint: Helpful scripts for tor maintenance Closes #29391 Signed-off-by: David Goulet --- changes/ticket29391 | 3 + scripts/maint/git-merge-forward.sh | 194 +++++++++++++++++++++++++++++++++++++ scripts/maint/git-pull-all.sh | 178 ++++++++++++++++++++++++++++++++++ scripts/maint/git-push-all.sh | 12 +++ 4 files changed, 387 insertions(+) create mode 100644 changes/ticket29391 create mode 100755 scripts/maint/git-merge-forward.sh create mode 100755 scripts/maint/git-pull-all.sh create mode 100755 scripts/maint/git-push-all.sh (limited to 'changes') diff --git a/changes/ticket29391 b/changes/ticket29391 new file mode 100644 index 0000000000..f00fa61c47 --- /dev/null +++ b/changes/ticket29391 @@ -0,0 +1,3 @@ + o Minor feature (maintenance scripts): + - Add to scripts/maint/ helper maintainer scripts used for git maintenance. + Closes ticket 29391. diff --git a/scripts/maint/git-merge-forward.sh b/scripts/maint/git-merge-forward.sh new file mode 100755 index 0000000000..3728067e7a --- /dev/null +++ b/scripts/maint/git-merge-forward.sh @@ -0,0 +1,194 @@ +#!/bin/bash + +############################## +# Configuration (change me!) # +############################## + +# The general setup that is suggested here is: +# +# GIT_PATH = /home//git/ +# ... where the git repository directories resides. +# TOR_MASTER_NAME = "tor" +# ... which means that tor.git was cloned in /home//git/tor +# TOR_WKT_NAME = "tor-wkt" +# ... which means that the tor worktrees are in /home//git/tor-wkt + +# Where are all those git repositories? +GIT_PATH="FULL_PATH_TO_GIT_REPOSITORY_DIRECTORY" +# The tor master git repository directory from which all the worktree have +# been created. +TOR_MASTER_NAME="tor" +# The worktrees location (directory). +TOR_WKT_NAME="tor-wkt" + +######################### +# End of configuration. # +######################### + +# Configuration of the branches that needs merging. The values are in order: +# (1) Branch name that we merge onto. +# (2) Branch name to merge from. In other words, this is merge into (1) +# (3) Full path of the git worktree. +# +# As an example: +# $ cd (3) +# $ git checkout maint-0.3.5 (1) +# $ git pull +# $ git merge maint-0.3.4 (2) +# +# First set of arrays are the maint-* branch and then the release-* branch. +# New arrays need to be in the WORKTREE= array else they aren't considered. +MAINT_033=( "maint-0.3.3" "maint-0.2.9" "$GIT_PATH/$TOR_WKT_NAME/maint-0.3.3" ) +MAINT_034=( "maint-0.3.4" "maint-0.3.3" "$GIT_PATH/$TOR_WKT_NAME/maint-0.3.4" ) +MAINT_035=( "maint-0.3.5" "maint-0.3.4" "$GIT_PATH/$TOR_WKT_NAME/maint-0.3.5" ) +MAINT_040=( "maint-0.4.0" "maint-0.3.5" "$GIT_PATH/$TOR_WKT_NAME/maint-0.4.0" ) +MAINT_MASTER=( "master" "maint-0.4.0" "$GIT_PATH/$TOR_MASTER_NAME" ) + +RELEASE_029=( "release-0.2.9" "maint-0.2.9" "$GIT_PATH/$TOR_WKT_NAME/release-0.2.9" ) +RELEASE_033=( "release-0.3.3" "maint-0.3.3" "$GIT_PATH/$TOR_WKT_NAME/release-0.3.3" ) +RELEASE_034=( "release-0.3.4" "maint-0.3.4" "$GIT_PATH/$TOR_WKT_NAME/release-0.3.4" ) +RELEASE_035=( "release-0.3.5" "maint-0.3.5" "$GIT_PATH/$TOR_WKT_NAME/release-0.3.5" ) +RELEASE_040=( "release-0.4.0" "maint-0.4.0" "$GIT_PATH/$TOR_WKT_NAME/release-0.4.0" ) + +########################## +# Git Worktree to manage # +########################## + +# List of all worktrees to work on. All defined above. Ordering is important. +# Always the maint-* branch BEFORE then the release-*. +WORKTREE=( + RELEASE_029[@] + + MAINT_033[@] + RELEASE_033[@] + + MAINT_034[@] + RELEASE_034[@] + + MAINT_035[@] + RELEASE_035[@] + + MAINT_040[@] + RELEASE_040[@] + + MAINT_MASTER[@] +) +COUNT=${#WORKTREE[@]} + +# Controlled by the -n option. The dry run option will just output the command +# that would have been executed for each worktree. +DRY_RUN=0 + +# Control characters +CNRM=$'\x1b[0;0m' # Clear color + +# Bright color +BGRN=$'\x1b[1;32m' +BBLU=$'\x1b[1;34m' +BRED=$'\x1b[1;31m' +BYEL=$'\x1b[1;33m' +IWTH=$'\x1b[3;37m' + +# Strings for the pretty print. +MARKER="${BBLU}[${BGRN}+${BBLU}]${CNRM}" +SUCCESS="${BGRN}success${CNRM}" +FAILED="${BRED}failed${CNRM}" + +#################### +# Helper functions # +#################### + +# Validate the given returned value (error code), print success or failed. The +# second argument is the error output in case of failure, it is printed out. +# On failure, this function exits. +function validate_ret +{ + if [ "$1" -eq 0 ]; then + printf "%s\\n" "$SUCCESS" + else + printf "%s\\n" "$FAILED" + printf " %s" "$2" + exit 1 + fi +} + +# Switch to the given branch name. +function switch_branch +{ + local cmd="git checkout $1" + printf " %s Switching branch to %s..." "$MARKER" "$1" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +# Pull the given branch name. +function pull_branch +{ + local cmd="git pull" + printf " %s Pulling branch %s..." "$MARKER" "$1" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +# Merge the given branch name ($2) into the current branch ($1). +function merge_branch +{ + local cmd="git merge --no-edit $1" + printf " %s Merging branch %s into %s..." "$MARKER" "$1" "$2" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +# Go into the worktree repository. +function goto_repo +{ + if [ ! -d "$1" ]; then + echo " $1: Not found. Stopping." + exit 1 + fi + cd "$1" || exit +} + +############### +# Entry point # +############### + +while getopts "n" opt; do + case "$opt" in + n) DRY_RUN=1 + echo " *** DRY DRUN MODE ***" + ;; + *) + ;; + esac +done + +# Go over all configured worktree. +for ((i=0; i/git/ +# ... where the git repository directories resides. +# TOR_MASTER_NAME = "tor" +# ... which means that tor.git was cloned in /home//git/tor +# TOR_WKT_NAME = "tor-wkt" +# ... which means that the tor worktrees are in /home//git/tor-wkt + +# Where are all those git repositories? +GIT_PATH="FULL_PATH_TO_GIT_REPOSITORY_DIRECTORY" +# The tor master git repository directory from which all the worktree have +# been created. +TOR_MASTER_NAME="tor" +# The worktrees location (directory). +TOR_WKT_NAME="tor-wkt" + +######################### +# End of configuration. # +######################### + +# Configuration of the branches that needs merging. The values are in order: +# (1) Branch name to pull (update). +# (2) Full path of the git worktree. +# +# As an example: +# $ cd (3) +# $ git checkout maint-0.3.5 (1) +# $ git pull +# +# First set of arrays are the maint-* branch and then the release-* branch. +# New arrays need to be in the WORKTREE= array else they aren't considered. +MAINT_029=( "maint-0.2.9" "$GIT_PATH/$TOR_WKT_NAME/maint-0.2.9" ) +MAINT_033=( "maint-0.3.3" "$GIT_PATH/$TOR_WKT_NAME/maint-0.3.3" ) +MAINT_034=( "maint-0.3.4" "$GIT_PATH/$TOR_WKT_NAME/maint-0.3.4" ) +MAINT_035=( "maint-0.3.5" "$GIT_PATH/$TOR_WKT_NAME/maint-0.3.5" ) +MAINT_040=( "maint-0.4.0" "$GIT_PATH/$TOR_WKT_NAME/maint-0.4.0" ) +MAINT_MASTER=( "master" "$GIT_PATH/$TOR_MASTER_NAME" ) + +RELEASE_029=( "release-0.2.9" "$GIT_PATH/$TOR_WKT_NAME/release-0.2.9" ) +RELEASE_033=( "release-0.3.3" "$GIT_PATH/$TOR_WKT_NAME/release-0.3.3" ) +RELEASE_034=( "release-0.3.4" "$GIT_PATH/$TOR_WKT_NAME/release-0.3.4" ) +RELEASE_035=( "release-0.3.5" "$GIT_PATH/$TOR_WKT_NAME/release-0.3.5" ) +RELEASE_040=( "release-0.4.0" "$GIT_PATH/$TOR_WKT_NAME/release-0.4.0" ) + +########################## +# Git Worktree to manage # +########################## + +# List of all worktrees to work on. All defined above. Ordering is important. +# Always the maint-* branch first then the release-*. +WORKTREE=( + MAINT_029[@] + RELEASE_029[@] + + MAINT_033[@] + RELEASE_033[@] + + MAINT_034[@] + RELEASE_034[@] + + MAINT_035[@] + RELEASE_035[@] + + MAINT_040[@] + RELEASE_040[@] + + MAINT_MASTER[@] +) +COUNT=${#WORKTREE[@]} + +# Controlled by the -n option. The dry run option will just output the command +# that would have been executed for each worktree. +DRY_RUN=0 + +# Control characters +CNRM=$'\x1b[0;0m' # Clear color + +# Bright color +BGRN=$'\x1b[1;32m' +BBLU=$'\x1b[1;34m' +BRED=$'\x1b[1;31m' +BYEL=$'\x1b[1;33m' +IWTH=$'\x1b[3;37m' + +# Strings for the pretty print. +MARKER="${BBLU}[${BGRN}+${BBLU}]${CNRM}" +SUCCESS="${BGRN}ok${CNRM}" +FAILED="${BRED}failed${CNRM}" + +#################### +# Helper functions # +#################### + +# Validate the given returned value (error code), print success or failed. The +# second argument is the error output in case of failure, it is printed out. +# On failure, this function exits. +function validate_ret +{ + if [ "$1" -eq 0 ]; then + printf "%s\\n" "$SUCCESS" + else + printf "%s\\n" "$FAILED" + printf " %s" "$2" + exit 1 + fi +} + +# Switch to the given branch name. +function switch_branch +{ + local cmd="git checkout $1" + printf " %s Switching branch to %s..." "$MARKER" "$1" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +# Pull the given branch name. +function pull_branch +{ + local cmd="git pull" + printf " %s Pulling branch %s..." "$MARKER" "$1" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +# Go into the worktree repository. +function goto_repo +{ + if [ ! -d "$1" ]; then + echo " $1: Not found. Stopping." + exit 1 + fi + cd "$1" || exit +} + +############### +# Entry point # +############### + +while getopts "n" opt; do + case "$opt" in + n) DRY_RUN=1 + echo " *** DRY DRUN MODE ***" + ;; + *) + ;; + esac +done + +# Go over all configured worktree. +for ((i=0; i Date: Wed, 27 Feb 2019 13:54:23 -0500 Subject: Set CIRCLAUNCH_NEED_UPTIME in rend_service_relaunch_rendezvous() on a hs_service_requires_uptime_circ() --- changes/bug17357 | 7 +++++++ src/feature/rend/rendservice.c | 26 ++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 changes/bug17357 (limited to 'changes') diff --git a/changes/bug17357 b/changes/bug17357 new file mode 100644 index 0000000000..1188b65fd7 --- /dev/null +++ b/changes/bug17357 @@ -0,0 +1,7 @@ + o Minor bugfixes (onion services): + - If we are relaunching a circuit to a rendevous service in + rend_service_relaunch_rendezvous() and hs_service_requires_uptime_circ() + is true, the CIRCLAUNCH_NEED_UPTIME flag is added to the circuit. + Previously, we only set this flag when we received a INTRODUCE2 + cell in rend_service_receive_introduction(). Fixes bug 17357; + bugfix on 0.4.0.2-alpha. Patch by Neel Chauhan diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c index 5ee084b0b7..73edcaccf5 100644 --- a/src/feature/rend/rendservice.c +++ b/src/feature/rend/rendservice.c @@ -3012,6 +3012,10 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) { origin_circuit_t *newcirc; cpath_build_state_t *newstate, *oldstate; + const char *rend_pk_digest; + rend_service_t *service = NULL; + + int flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL; tor_assert(oldcirc->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); oldstate = oldcirc->build_state; @@ -3026,13 +3030,31 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) log_info(LD_REND,"Reattempting rendezvous circuit to '%s'", safe_str(extend_info_describe(oldstate->chosen_exit))); + /* Look up the service. */ + rend_pk_digest = (char *) rend_data_get_pk_digest(oldcirc->rend_data, NULL); + service = rend_service_get_by_pk_digest(rend_pk_digest); + + if (!service) { + char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; + base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, + rend_pk_digest, REND_SERVICE_ID_LEN); + + log_warn(LD_BUG, "Internal error: Trying to relaunch a rendezvous circ " + "for an unrecognized service %s.", + safe_str_client(serviceid)); + return; + } + + if (hs_service_requires_uptime_circ(service->ports)) { + flags |= CIRCLAUNCH_NEED_UPTIME; + } + /* You'd think Single Onion Services would want to retry the rendezvous * using a direct connection. But if it's blocked by a firewall, or the * service is IPv6-only, or the rend point avoiding becoming a one-hop * proxy, we need a 3-hop connection. */ newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, - oldstate->chosen_exit, - CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL); + oldstate->chosen_exit, flags); if (!newcirc) { log_warn(LD_REND,"Couldn't relaunch rendezvous circuit to '%s'.", -- cgit v1.2.3-54-g00ecf From 5d53862139ea3244735834d7a89077f53cd3df76 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Fri, 18 Jan 2019 12:26:13 +0200 Subject: Split crypto_digest.c * Move out code that depends on NSS to crypto_digest_nss.c * Move out code that depends on OpenSSL to crypto_digest_openssl.c * Keep the general code that is not specific to any of the above in crypto_digest.c --- changes/ticket29108 | 5 + src/lib/crypt_ops/crypto_digest.c | 736 ------------------------------ src/lib/crypt_ops/crypto_digest_nss.c | 560 +++++++++++++++++++++++ src/lib/crypt_ops/crypto_digest_openssl.c | 522 +++++++++++++++++++++ src/lib/crypt_ops/include.am | 2 + 5 files changed, 1089 insertions(+), 736 deletions(-) create mode 100644 changes/ticket29108 create mode 100644 src/lib/crypt_ops/crypto_digest_nss.c create mode 100644 src/lib/crypt_ops/crypto_digest_openssl.c (limited to 'changes') diff --git a/changes/ticket29108 b/changes/ticket29108 new file mode 100644 index 0000000000..7adb08ecb1 --- /dev/null +++ b/changes/ticket29108 @@ -0,0 +1,5 @@ + o Code simplification and refactoring: + - Split crypto_digest.c into three parts: 1) general code that does not + depend on either NSS or OpenSSL (stays in crypto_digest.c); 2) code that + depends on NSS API (moved to crypto_digest_nss.c); 3) code that depends + on OpenSSL API (moved to crypto_digest_openssl.c). Resolves ticket 29108. diff --git a/src/lib/crypt_ops/crypto_digest.c b/src/lib/crypt_ops/crypto_digest.c index 1e64100f2f..9da135e9c4 100644 --- a/src/lib/crypt_ops/crypto_digest.c +++ b/src/lib/crypt_ops/crypto_digest.c @@ -23,187 +23,6 @@ #include "lib/arch/bytes.h" -#ifdef ENABLE_NSS -DISABLE_GCC_WARNING(strict-prototypes) -#include -ENABLE_GCC_WARNING(strict-prototypes) -#else - -#include "lib/crypt_ops/crypto_openssl_mgt.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include -#include - -ENABLE_GCC_WARNING(redundant-decls) - -#ifdef HAVE_EVP_SHA3_256 -#define OPENSSL_HAS_SHA3 -#include -#endif - -#endif - -#ifdef ENABLE_NSS -/** - * Convert a digest_algorithm_t (used by tor) to a HashType (used by NSS). - * On failure, return SEC_OID_UNKNOWN. */ -static SECOidTag -digest_alg_to_nss_oid(digest_algorithm_t alg) -{ - switch (alg) { - case DIGEST_SHA1: return SEC_OID_SHA1; - case DIGEST_SHA256: return SEC_OID_SHA256; - case DIGEST_SHA512: return SEC_OID_SHA512; - case DIGEST_SHA3_256: /* Fall through */ - case DIGEST_SHA3_512: /* Fall through */ - default: - return SEC_OID_UNKNOWN; - } -} - -/* Helper: get an unkeyed digest via pk11wrap */ -static int -digest_nss_internal(SECOidTag alg, - char *digest, unsigned len_out, - const char *msg, size_t msg_len) -{ - if (alg == SEC_OID_UNKNOWN) - return -1; - tor_assert(msg_len <= UINT_MAX); - - int rv = -1; - SECStatus s; - PK11Context *ctx = PK11_CreateDigestContext(alg); - if (!ctx) - return -1; - - s = PK11_DigestBegin(ctx); - if (s != SECSuccess) - goto done; - - s = PK11_DigestOp(ctx, (const unsigned char *)msg, (unsigned int)msg_len); - if (s != SECSuccess) - goto done; - - unsigned int len = 0; - s = PK11_DigestFinal(ctx, (unsigned char *)digest, &len, len_out); - if (s != SECSuccess) - goto done; - - rv = 0; - done: - PK11_DestroyContext(ctx, PR_TRUE); - return rv; -} - -/** True iff alg is implemented in our crypto library, and we want to use that - * implementation */ -static bool -library_supports_digest(digest_algorithm_t alg) -{ - switch (alg) { - case DIGEST_SHA1: /* Fall through */ - case DIGEST_SHA256: /* Fall through */ - case DIGEST_SHA512: /* Fall through */ - return true; - case DIGEST_SHA3_256: /* Fall through */ - case DIGEST_SHA3_512: /* Fall through */ - default: - return false; - } -} -#endif - -/* Crypto digest functions */ - -/** Compute the SHA1 digest of the len bytes on data stored in - * m. Write the DIGEST_LEN byte result into digest. - * Return 0 on success, -1 on failure. - */ -MOCK_IMPL(int, -crypto_digest,(char *digest, const char *m, size_t len)) -{ - tor_assert(m); - tor_assert(digest); -#ifdef ENABLE_NSS - return digest_nss_internal(SEC_OID_SHA1, digest, DIGEST_LEN, m, len); -#else - if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL) { - return -1; - } -#endif - return 0; -} - -/** Compute a 256-bit digest of len bytes in data stored in m, - * using the algorithm algorithm. Write the DIGEST_LEN256-byte result - * into digest. Return 0 on success, -1 on failure. */ -int -crypto_digest256(char *digest, const char *m, size_t len, - digest_algorithm_t algorithm) -{ - tor_assert(m); - tor_assert(digest); - tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); - - int ret = 0; - if (algorithm == DIGEST_SHA256) { -#ifdef ENABLE_NSS - return digest_nss_internal(SEC_OID_SHA256, digest, DIGEST256_LEN, m, len); -#else - ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL); -#endif - } else { -#ifdef OPENSSL_HAS_SHA3 - unsigned int dlen = DIGEST256_LEN; - ret = EVP_Digest(m, len, (uint8_t*)digest, &dlen, EVP_sha3_256(), NULL); -#else - ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len) - > -1); -#endif - } - - if (!ret) - return -1; - return 0; -} - -/** Compute a 512-bit digest of len bytes in data stored in m, - * using the algorithm algorithm. Write the DIGEST_LEN512-byte result - * into digest. Return 0 on success, -1 on failure. */ -int -crypto_digest512(char *digest, const char *m, size_t len, - digest_algorithm_t algorithm) -{ - tor_assert(m); - tor_assert(digest); - tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); - - int ret = 0; - if (algorithm == DIGEST_SHA512) { -#ifdef ENABLE_NSS - return digest_nss_internal(SEC_OID_SHA512, digest, DIGEST512_LEN, m, len); -#else - ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest) - != NULL); -#endif - } else { -#ifdef OPENSSL_HAS_SHA3 - unsigned int dlen = DIGEST512_LEN; - ret = EVP_Digest(m, len, (uint8_t*)digest, &dlen, EVP_sha3_512(), NULL); -#else - ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len) - > -1); -#endif - } - - if (!ret) - return -1; - return 0; -} - /** Set the common_digests_t in ds_out to contain every digest on the * len bytes in m that we know how to compute. Return 0 on * success, -1 on failure. */ @@ -283,561 +102,6 @@ crypto_digest_algorithm_get_length(digest_algorithm_t alg) } } -/** Intermediate information about the digest of a stream of data. */ -struct crypto_digest_t { - digest_algorithm_t algorithm; /**< Which algorithm is in use? */ - /** State for the digest we're using. Only one member of the - * union is usable, depending on the value of algorithm. Note also - * that space for other members might not even be allocated! - */ - union { -#ifdef ENABLE_NSS - PK11Context *ctx; -#else - SHA_CTX sha1; /**< state for SHA1 */ - SHA256_CTX sha2; /**< state for SHA256 */ - SHA512_CTX sha512; /**< state for SHA512 */ -#endif -#ifdef OPENSSL_HAS_SHA3 - EVP_MD_CTX *md; -#else - keccak_state sha3; /**< state for SHA3-[256,512] */ -#endif - } d; -}; - -#ifdef TOR_UNIT_TESTS - -digest_algorithm_t -crypto_digest_get_algorithm(crypto_digest_t *digest) -{ - tor_assert(digest); - - return digest->algorithm; -} - -#endif /* defined(TOR_UNIT_TESTS) */ - -/** - * Return the number of bytes we need to malloc in order to get a - * crypto_digest_t for alg, or the number of bytes we need to wipe - * when we free one. - */ -static size_t -crypto_digest_alloc_bytes(digest_algorithm_t alg) -{ - /* Helper: returns the number of bytes in the 'f' field of 'st' */ -#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f )) - /* Gives the length of crypto_digest_t through the end of the field 'd' */ -#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \ - STRUCT_FIELD_SIZE(crypto_digest_t, f)) - switch (alg) { -#ifdef ENABLE_NSS - case DIGEST_SHA1: /* Fall through */ - case DIGEST_SHA256: /* Fall through */ - case DIGEST_SHA512: - return END_OF_FIELD(d.ctx); -#else - case DIGEST_SHA1: - return END_OF_FIELD(d.sha1); - case DIGEST_SHA256: - return END_OF_FIELD(d.sha2); - case DIGEST_SHA512: - return END_OF_FIELD(d.sha512); -#endif -#ifdef OPENSSL_HAS_SHA3 - case DIGEST_SHA3_256: /* Fall through */ - case DIGEST_SHA3_512: - return END_OF_FIELD(d.md); -#else - case DIGEST_SHA3_256: /* Fall through */ - case DIGEST_SHA3_512: - return END_OF_FIELD(d.sha3); -#endif - default: - tor_assert(0); // LCOV_EXCL_LINE - return 0; // LCOV_EXCL_LINE - } -#undef END_OF_FIELD -#undef STRUCT_FIELD_SIZE -} - -/** - * Internal function: create and return a new digest object for 'algorithm'. - * Does not typecheck the algorithm. - */ -static crypto_digest_t * -crypto_digest_new_internal(digest_algorithm_t algorithm) -{ - crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm)); - r->algorithm = algorithm; - - switch (algorithm) - { -#ifdef ENABLE_NSS - case DIGEST_SHA1: /* fall through */ - case DIGEST_SHA256: /* fall through */ - case DIGEST_SHA512: - r->d.ctx = PK11_CreateDigestContext(digest_alg_to_nss_oid(algorithm)); - if (BUG(!r->d.ctx)) { - tor_free(r); - return NULL; - } - if (BUG(SECSuccess != PK11_DigestBegin(r->d.ctx))) { - crypto_digest_free(r); - return NULL; - } - break; -#else - case DIGEST_SHA1: - SHA1_Init(&r->d.sha1); - break; - case DIGEST_SHA256: - SHA256_Init(&r->d.sha2); - break; - case DIGEST_SHA512: - SHA512_Init(&r->d.sha512); - break; -#endif -#ifdef OPENSSL_HAS_SHA3 - case DIGEST_SHA3_256: - r->d.md = EVP_MD_CTX_new(); - if (!EVP_DigestInit(r->d.md, EVP_sha3_256())) { - crypto_digest_free(r); - return NULL; - } - break; - case DIGEST_SHA3_512: - r->d.md = EVP_MD_CTX_new(); - if (!EVP_DigestInit(r->d.md, EVP_sha3_512())) { - crypto_digest_free(r); - return NULL; - } - break; -#else - case DIGEST_SHA3_256: - keccak_digest_init(&r->d.sha3, 256); - break; - case DIGEST_SHA3_512: - keccak_digest_init(&r->d.sha3, 512); - break; -#endif - default: - tor_assert_unreached(); - } - - return r; -} - -/** Allocate and return a new digest object to compute SHA1 digests. - */ -crypto_digest_t * -crypto_digest_new(void) -{ - return crypto_digest_new_internal(DIGEST_SHA1); -} - -/** Allocate and return a new digest object to compute 256-bit digests - * using algorithm. - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest256_new` - * C_RUST_COUPLED: `crypto::digest::Sha256::default` - */ -crypto_digest_t * -crypto_digest256_new(digest_algorithm_t algorithm) -{ - tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); - return crypto_digest_new_internal(algorithm); -} - -/** Allocate and return a new digest object to compute 512-bit digests - * using algorithm. */ -crypto_digest_t * -crypto_digest512_new(digest_algorithm_t algorithm) -{ - tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); - return crypto_digest_new_internal(algorithm); -} - -/** Deallocate a digest object. - */ -void -crypto_digest_free_(crypto_digest_t *digest) -{ - if (!digest) - return; -#ifdef ENABLE_NSS - if (library_supports_digest(digest->algorithm)) { - PK11_DestroyContext(digest->d.ctx, PR_TRUE); - } -#endif -#ifdef OPENSSL_HAS_SHA3 - if (digest->algorithm == DIGEST_SHA3_256 || - digest->algorithm == DIGEST_SHA3_512) { - if (digest->d.md) { - EVP_MD_CTX_free(digest->d.md); - } - } -#endif - size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); - memwipe(digest, 0, bytes); - tor_free(digest); -} - -/** Add len bytes from data to the digest object. - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_add_bytess` - * C_RUST_COUPLED: `crypto::digest::Sha256::process` - */ -void -crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, - size_t len) -{ - tor_assert(digest); - tor_assert(data); - /* Using the SHA*_*() calls directly means we don't support doing - * SHA in hardware. But so far the delay of getting the question - * to the hardware, and hearing the answer, is likely higher than - * just doing it ourselves. Hashes are fast. - */ - switch (digest->algorithm) { -#ifdef ENABLE_NSS - case DIGEST_SHA1: /* fall through */ - case DIGEST_SHA256: /* fall through */ - case DIGEST_SHA512: - tor_assert(len <= UINT_MAX); - SECStatus s = PK11_DigestOp(digest->d.ctx, - (const unsigned char *)data, - (unsigned int)len); - tor_assert(s == SECSuccess); - break; -#else - case DIGEST_SHA1: - SHA1_Update(&digest->d.sha1, (void*)data, len); - break; - case DIGEST_SHA256: - SHA256_Update(&digest->d.sha2, (void*)data, len); - break; - case DIGEST_SHA512: - SHA512_Update(&digest->d.sha512, (void*)data, len); - break; -#endif -#ifdef OPENSSL_HAS_SHA3 - case DIGEST_SHA3_256: /* FALLSTHROUGH */ - case DIGEST_SHA3_512: { - int r = EVP_DigestUpdate(digest->d.md, data, len); - tor_assert(r); - } - break; -#else - case DIGEST_SHA3_256: /* FALLSTHROUGH */ - case DIGEST_SHA3_512: - keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len); - break; -#endif - default: - /* LCOV_EXCL_START */ - tor_fragile_assert(); - break; - /* LCOV_EXCL_STOP */ - } -} - -/** Compute the hash of the data that has been passed to the digest - * object; write the first out_len bytes of the result to out. - * out_len must be \<= DIGEST512_LEN. - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_get_digest` - * C_RUST_COUPLED: `impl digest::FixedOutput for Sha256` - */ -void -crypto_digest_get_digest(crypto_digest_t *digest, - char *out, size_t out_len) -{ - unsigned char r[DIGEST512_LEN]; - tor_assert(digest); - tor_assert(out); - tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm)); - - if (digest->algorithm == DIGEST_SHA3_256 || - digest->algorithm == DIGEST_SHA3_512) { -#ifdef OPENSSL_HAS_SHA3 - unsigned dlen = (unsigned) - crypto_digest_algorithm_get_length(digest->algorithm); - EVP_MD_CTX *tmp = EVP_MD_CTX_new(); - EVP_MD_CTX_copy(tmp, digest->d.md); - memset(r, 0xff, sizeof(r)); - int res = EVP_DigestFinal(tmp, r, &dlen); - EVP_MD_CTX_free(tmp); - tor_assert(res == 1); - goto done; -#else - /* Tiny-Keccak handles copying into a temporary ctx, and also can handle - * short output buffers by truncating appropriately. */ - keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len); - return; -#endif - } - -#ifdef ENABLE_NSS - /* Copy into a temporary buffer since DigestFinal (alters) the context */ - unsigned char buf[1024]; - unsigned int saved_len = 0; - unsigned rlen; - unsigned char *saved = PK11_SaveContextAlloc(digest->d.ctx, - buf, sizeof(buf), - &saved_len); - tor_assert(saved); - SECStatus s = PK11_DigestFinal(digest->d.ctx, r, &rlen, sizeof(r)); - tor_assert(s == SECSuccess); - tor_assert(rlen >= out_len); - s = PK11_RestoreContext(digest->d.ctx, saved, saved_len); - tor_assert(s == SECSuccess); - if (saved != buf) { - PORT_ZFree(saved, saved_len); - } -#else - const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); - crypto_digest_t tmpenv; - /* memcpy into a temporary ctx, since SHA*_Final clears the context */ - memcpy(&tmpenv, digest, alloc_bytes); - switch (digest->algorithm) { - case DIGEST_SHA1: - SHA1_Final(r, &tmpenv.d.sha1); - break; - case DIGEST_SHA256: - SHA256_Final(r, &tmpenv.d.sha2); - break; - case DIGEST_SHA512: - SHA512_Final(r, &tmpenv.d.sha512); - break; -//LCOV_EXCL_START - case DIGEST_SHA3_256: /* FALLSTHROUGH */ - case DIGEST_SHA3_512: - default: - log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm); - /* This is fatal, because it should never happen. */ - tor_assert_unreached(); - break; -//LCOV_EXCL_STOP - } -#endif - -#ifdef OPENSSL_HAS_SHA3 - done: -#endif - memcpy(out, r, out_len); - memwipe(r, 0, sizeof(r)); -} - -/** Allocate and return a new digest object with the same state as - * digest - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_dup` - * C_RUST_COUPLED: `impl Clone for crypto::digest::Sha256` - */ -crypto_digest_t * -crypto_digest_dup(const crypto_digest_t *digest) -{ - tor_assert(digest); - const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); - crypto_digest_t *result = tor_memdup(digest, alloc_bytes); -#ifdef ENABLE_NSS - if (library_supports_digest(digest->algorithm)) { - result->d.ctx = PK11_CloneContext(digest->d.ctx); - } -#endif -#ifdef OPENSSL_HAS_SHA3 - if (digest->algorithm == DIGEST_SHA3_256 || - digest->algorithm == DIGEST_SHA3_512) { - result->d.md = EVP_MD_CTX_new(); - EVP_MD_CTX_copy(result->d.md, digest->d.md); - } -#endif - return result; -} - -/** Temporarily save the state of digest in checkpoint. - * Asserts that digest is a SHA1 digest object. - */ -void -crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint, - const crypto_digest_t *digest) -{ - const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); - tor_assert(bytes <= sizeof(checkpoint->mem)); -#ifdef ENABLE_NSS - if (library_supports_digest(digest->algorithm)) { - unsigned char *allocated; - allocated = PK11_SaveContextAlloc(digest->d.ctx, - (unsigned char *)checkpoint->mem, - sizeof(checkpoint->mem), - &checkpoint->bytes_used); - /* No allocation is allowed here. */ - tor_assert(allocated == checkpoint->mem); - return; - } -#endif - memcpy(checkpoint->mem, digest, bytes); -} - -/** Restore the state of digest from checkpoint. - * Asserts that digest is a SHA1 digest object. Requires that the - * state was previously stored with crypto_digest_checkpoint() */ -void -crypto_digest_restore(crypto_digest_t *digest, - const crypto_digest_checkpoint_t *checkpoint) -{ - const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); -#ifdef ENABLE_NSS - if (library_supports_digest(digest->algorithm)) { - SECStatus s = PK11_RestoreContext(digest->d.ctx, - (unsigned char *)checkpoint->mem, - checkpoint->bytes_used); - tor_assert(s == SECSuccess); - return; - } -#endif - memcpy(digest, checkpoint->mem, bytes); -} - -/** Replace the state of the digest object into with the state - * of the digest object from. Requires that 'into' and 'from' - * have the same digest type. - */ -void -crypto_digest_assign(crypto_digest_t *into, - const crypto_digest_t *from) -{ - tor_assert(into); - tor_assert(from); - tor_assert(into->algorithm == from->algorithm); - const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm); -#ifdef ENABLE_NSS - if (library_supports_digest(from->algorithm)) { - PK11_DestroyContext(into->d.ctx, PR_TRUE); - into->d.ctx = PK11_CloneContext(from->d.ctx); - return; - } -#endif - -#ifdef OPENSSL_HAS_SHA3 - if (from->algorithm == DIGEST_SHA3_256 || - from->algorithm == DIGEST_SHA3_512) { - EVP_MD_CTX_copy(into->d.md, from->d.md); - return; - } -#endif - - memcpy(into,from,alloc_bytes); -} - -/** Given a list of strings in lst, set the len_out-byte digest - * at digest_out to the hash of the concatenation of those strings, - * plus the optional string append, computed with the algorithm - * alg. - * out_len must be \<= DIGEST512_LEN. */ -void -crypto_digest_smartlist(char *digest_out, size_t len_out, - const smartlist_t *lst, - const char *append, - digest_algorithm_t alg) -{ - crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg); -} - -/** Given a list of strings in lst, set the len_out-byte digest - * at digest_out to the hash of the concatenation of: the - * optional string prepend, those strings, - * and the optional string append, computed with the algorithm - * alg. - * len_out must be \<= DIGEST512_LEN. */ -void -crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, - const char *prepend, - const smartlist_t *lst, - const char *append, - digest_algorithm_t alg) -{ - crypto_digest_t *d = crypto_digest_new_internal(alg); - if (prepend) - crypto_digest_add_bytes(d, prepend, strlen(prepend)); - SMARTLIST_FOREACH(lst, const char *, cp, - crypto_digest_add_bytes(d, cp, strlen(cp))); - if (append) - crypto_digest_add_bytes(d, append, strlen(append)); - crypto_digest_get_digest(d, digest_out, len_out); - crypto_digest_free(d); -} - -/** Compute the HMAC-SHA-256 of the msg_len bytes in msg, using - * the key of length key_len. Store the DIGEST256_LEN-byte - * result in hmac_out. Asserts on failure. - */ -void -crypto_hmac_sha256(char *hmac_out, - const char *key, size_t key_len, - const char *msg, size_t msg_len) -{ - /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */ - tor_assert(key_len < INT_MAX); - tor_assert(msg_len < INT_MAX); - tor_assert(hmac_out); -#ifdef ENABLE_NSS - PK11SlotInfo *slot = NULL; - PK11SymKey *symKey = NULL; - PK11Context *hmac = NULL; - - int ok = 0; - SECStatus s; - SECItem keyItem, paramItem; - keyItem.data = (unsigned char *)key; - keyItem.len = (unsigned)key_len; - paramItem.type = siBuffer; - paramItem.data = NULL; - paramItem.len = 0; - - slot = PK11_GetBestSlot(CKM_SHA256_HMAC, NULL); - if (!slot) - goto done; - symKey = PK11_ImportSymKey(slot, CKM_SHA256_HMAC, - PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL); - if (!symKey) - goto done; - - hmac = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, symKey, - ¶mItem); - if (!hmac) - goto done; - s = PK11_DigestBegin(hmac); - if (s != SECSuccess) - goto done; - s = PK11_DigestOp(hmac, (const unsigned char *)msg, (unsigned int)msg_len); - if (s != SECSuccess) - goto done; - unsigned int len=0; - s = PK11_DigestFinal(hmac, (unsigned char *)hmac_out, &len, DIGEST256_LEN); - if (s != SECSuccess || len != DIGEST256_LEN) - goto done; - ok = 1; - - done: - if (hmac) - PK11_DestroyContext(hmac, PR_TRUE); - if (symKey) - PK11_FreeSymKey(symKey); - if (slot) - PK11_FreeSlot(slot); - - tor_assert(ok); -#else - unsigned char *rv = NULL; - rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len, - (unsigned char*)hmac_out, NULL); - tor_assert(rv); -#endif -} - /** Compute a MAC using SHA3-256 of msg_len bytes in msg using a * key of length key_len and a salt of length * salt_len. Store the result of len_out bytes in in diff --git a/src/lib/crypt_ops/crypto_digest_nss.c b/src/lib/crypt_ops/crypto_digest_nss.c new file mode 100644 index 0000000000..b73f0736fd --- /dev/null +++ b/src/lib/crypt_ops/crypto_digest_nss.c @@ -0,0 +1,560 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_digest_nss.c + * \brief Block of functions related with digest and xof utilities and + * operations (NSS specific implementations). + **/ + +#include "lib/container/smartlist.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/log/log.h" +#include "lib/log/util_bug.h" + +#include "keccak-tiny/keccak-tiny.h" + +#include +#include + +#include "lib/arch/bytes.h" + +DISABLE_GCC_WARNING(strict-prototypes) +#include +ENABLE_GCC_WARNING(strict-prototypes) + +/** + * Convert a digest_algorithm_t (used by tor) to a HashType (used by NSS). + * On failure, return SEC_OID_UNKNOWN. */ +static SECOidTag +digest_alg_to_nss_oid(digest_algorithm_t alg) +{ + switch (alg) { + case DIGEST_SHA1: return SEC_OID_SHA1; + case DIGEST_SHA256: return SEC_OID_SHA256; + case DIGEST_SHA512: return SEC_OID_SHA512; + case DIGEST_SHA3_256: /* Fall through */ + case DIGEST_SHA3_512: /* Fall through */ + default: + return SEC_OID_UNKNOWN; + } +} + +/* Helper: get an unkeyed digest via pk11wrap */ +static int +digest_nss_internal(SECOidTag alg, + char *digest, unsigned len_out, + const char *msg, size_t msg_len) +{ + if (alg == SEC_OID_UNKNOWN) + return -1; + tor_assert(msg_len <= UINT_MAX); + + int rv = -1; + SECStatus s; + PK11Context *ctx = PK11_CreateDigestContext(alg); + if (!ctx) + return -1; + + s = PK11_DigestBegin(ctx); + if (s != SECSuccess) + goto done; + + s = PK11_DigestOp(ctx, (const unsigned char *)msg, (unsigned int)msg_len); + if (s != SECSuccess) + goto done; + + unsigned int len = 0; + s = PK11_DigestFinal(ctx, (unsigned char *)digest, &len, len_out); + if (s != SECSuccess) + goto done; + + rv = 0; + done: + PK11_DestroyContext(ctx, PR_TRUE); + return rv; +} + +/** True iff alg is implemented in our crypto library, and we want to use that + * implementation */ +static bool +library_supports_digest(digest_algorithm_t alg) +{ + switch (alg) { + case DIGEST_SHA1: /* Fall through */ + case DIGEST_SHA256: /* Fall through */ + case DIGEST_SHA512: /* Fall through */ + return true; + case DIGEST_SHA3_256: /* Fall through */ + case DIGEST_SHA3_512: /* Fall through */ + default: + return false; + } +} + +/* Crypto digest functions */ + +/** Compute the SHA1 digest of the len bytes on data stored in + * m. Write the DIGEST_LEN byte result into digest. + * Return 0 on success, -1 on failure. + */ +MOCK_IMPL(int, +crypto_digest,(char *digest, const char *m, size_t len)) +{ + tor_assert(m); + tor_assert(digest); + return digest_nss_internal(SEC_OID_SHA1, digest, DIGEST_LEN, m, len); +} + +/** Compute a 256-bit digest of len bytes in data stored in m, + * using the algorithm algorithm. Write the DIGEST_LEN256-byte result + * into digest. Return 0 on success, -1 on failure. */ +int +crypto_digest256(char *digest, const char *m, size_t len, + digest_algorithm_t algorithm) +{ + tor_assert(m); + tor_assert(digest); + tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); + + int ret = 0; + if (algorithm == DIGEST_SHA256) { + return digest_nss_internal(SEC_OID_SHA256, digest, DIGEST256_LEN, m, len); + } else { + ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len) + > -1); + } + + if (!ret) + return -1; + return 0; +} + +/** Compute a 512-bit digest of len bytes in data stored in m, + * using the algorithm algorithm. Write the DIGEST_LEN512-byte result + * into digest. Return 0 on success, -1 on failure. */ +int +crypto_digest512(char *digest, const char *m, size_t len, + digest_algorithm_t algorithm) +{ + tor_assert(m); + tor_assert(digest); + tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); + + int ret = 0; + if (algorithm == DIGEST_SHA512) { + return digest_nss_internal(SEC_OID_SHA512, digest, DIGEST512_LEN, m, len); + } else { + ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len) + > -1); + } + + if (!ret) + return -1; + return 0; +} + +/** Intermediate information about the digest of a stream of data. */ +struct crypto_digest_t { + digest_algorithm_t algorithm; /**< Which algorithm is in use? */ + /** State for the digest we're using. Only one member of the + * union is usable, depending on the value of algorithm. Note also + * that space for other members might not even be allocated! + */ + union { + PK11Context *ctx; + keccak_state sha3; /**< state for SHA3-[256,512] */ + } d; +}; + +#ifdef TOR_UNIT_TESTS + +digest_algorithm_t +crypto_digest_get_algorithm(crypto_digest_t *digest) +{ + tor_assert(digest); + + return digest->algorithm; +} + +#endif /* defined(TOR_UNIT_TESTS) */ + +/** + * Return the number of bytes we need to malloc in order to get a + * crypto_digest_t for alg, or the number of bytes we need to wipe + * when we free one. + */ +static size_t +crypto_digest_alloc_bytes(digest_algorithm_t alg) +{ + /* Helper: returns the number of bytes in the 'f' field of 'st' */ +#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f )) + /* Gives the length of crypto_digest_t through the end of the field 'd' */ +#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \ + STRUCT_FIELD_SIZE(crypto_digest_t, f)) + switch (alg) { + case DIGEST_SHA1: /* Fall through */ + case DIGEST_SHA256: /* Fall through */ + case DIGEST_SHA512: + return END_OF_FIELD(d.ctx); + case DIGEST_SHA3_256: + case DIGEST_SHA3_512: + return END_OF_FIELD(d.sha3); + default: + tor_assert(0); // LCOV_EXCL_LINE + return 0; // LCOV_EXCL_LINE + } +#undef END_OF_FIELD +#undef STRUCT_FIELD_SIZE +} + +/** + * Internal function: create and return a new digest object for 'algorithm'. + * Does not typecheck the algorithm. + */ +static crypto_digest_t * +crypto_digest_new_internal(digest_algorithm_t algorithm) +{ + crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm)); + r->algorithm = algorithm; + + switch (algorithm) + { + case DIGEST_SHA1: /* fall through */ + case DIGEST_SHA256: /* fall through */ + case DIGEST_SHA512: + r->d.ctx = PK11_CreateDigestContext(digest_alg_to_nss_oid(algorithm)); + if (BUG(!r->d.ctx)) { + tor_free(r); + return NULL; + } + if (BUG(SECSuccess != PK11_DigestBegin(r->d.ctx))) { + crypto_digest_free(r); + return NULL; + } + break; + case DIGEST_SHA3_256: + keccak_digest_init(&r->d.sha3, 256); + break; + case DIGEST_SHA3_512: + keccak_digest_init(&r->d.sha3, 512); + break; + default: + tor_assert_unreached(); + } + + return r; +} + +/** Allocate and return a new digest object to compute SHA1 digests. + */ +crypto_digest_t * +crypto_digest_new(void) +{ + return crypto_digest_new_internal(DIGEST_SHA1); +} + +/** Allocate and return a new digest object to compute 256-bit digests + * using algorithm. + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest256_new` + * C_RUST_COUPLED: `crypto::digest::Sha256::default` + */ +crypto_digest_t * +crypto_digest256_new(digest_algorithm_t algorithm) +{ + tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); + return crypto_digest_new_internal(algorithm); +} + +/** Allocate and return a new digest object to compute 512-bit digests + * using algorithm. */ +crypto_digest_t * +crypto_digest512_new(digest_algorithm_t algorithm) +{ + tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); + return crypto_digest_new_internal(algorithm); +} + +/** Deallocate a digest object. + */ +void +crypto_digest_free_(crypto_digest_t *digest) +{ + if (!digest) + return; + if (library_supports_digest(digest->algorithm)) { + PK11_DestroyContext(digest->d.ctx, PR_TRUE); + } + size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); + memwipe(digest, 0, bytes); + tor_free(digest); +} + +/** Add len bytes from data to the digest object. + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_add_bytess` + * C_RUST_COUPLED: `crypto::digest::Sha256::process` + */ +void +crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, + size_t len) +{ + tor_assert(digest); + tor_assert(data); + /* Using the SHA*_*() calls directly means we don't support doing + * SHA in hardware. But so far the delay of getting the question + * to the hardware, and hearing the answer, is likely higher than + * just doing it ourselves. Hashes are fast. + */ + switch (digest->algorithm) { + case DIGEST_SHA1: /* fall through */ + case DIGEST_SHA256: /* fall through */ + case DIGEST_SHA512: + tor_assert(len <= UINT_MAX); + SECStatus s = PK11_DigestOp(digest->d.ctx, + (const unsigned char *)data, + (unsigned int)len); + tor_assert(s == SECSuccess); + break; + case DIGEST_SHA3_256: /* FALLSTHROUGH */ + case DIGEST_SHA3_512: + keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len); + break; + default: + /* LCOV_EXCL_START */ + tor_fragile_assert(); + break; + /* LCOV_EXCL_STOP */ + } +} + +/** Compute the hash of the data that has been passed to the digest + * object; write the first out_len bytes of the result to out. + * out_len must be \<= DIGEST512_LEN. + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_get_digest` + * C_RUST_COUPLED: `impl digest::FixedOutput for Sha256` + */ +void +crypto_digest_get_digest(crypto_digest_t *digest, + char *out, size_t out_len) +{ + unsigned char r[DIGEST512_LEN]; + tor_assert(digest); + tor_assert(out); + tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm)); + + /* The SHA-3 code handles copying into a temporary ctx, and also can handle + * short output buffers by truncating appropriately. */ + if (digest->algorithm == DIGEST_SHA3_256 || + digest->algorithm == DIGEST_SHA3_512) { + keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len); + return; + } + + /* Copy into a temporary buffer since DigestFinal (alters) the context */ + unsigned char buf[1024]; + unsigned int saved_len = 0; + unsigned rlen; + unsigned char *saved = PK11_SaveContextAlloc(digest->d.ctx, + buf, sizeof(buf), + &saved_len); + tor_assert(saved); + SECStatus s = PK11_DigestFinal(digest->d.ctx, r, &rlen, sizeof(r)); + tor_assert(s == SECSuccess); + tor_assert(rlen >= out_len); + s = PK11_RestoreContext(digest->d.ctx, saved, saved_len); + tor_assert(s == SECSuccess); + + if (saved != buf) { + PORT_ZFree(saved, saved_len); + } + memcpy(out, r, out_len); + memwipe(r, 0, sizeof(r)); +} + +/** Allocate and return a new digest object with the same state as + * digest + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_dup` + * C_RUST_COUPLED: `impl Clone for crypto::digest::Sha256` + */ +crypto_digest_t * +crypto_digest_dup(const crypto_digest_t *digest) +{ + tor_assert(digest); + const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); + crypto_digest_t *result = tor_memdup(digest, alloc_bytes); + + if (library_supports_digest(digest->algorithm)) { + result->d.ctx = PK11_CloneContext(digest->d.ctx); + } + + return result; +} + +/** Temporarily save the state of digest in checkpoint. + * Asserts that digest is a SHA1 digest object. + */ +void +crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint, + const crypto_digest_t *digest) +{ + const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); + tor_assert(bytes <= sizeof(checkpoint->mem)); + if (library_supports_digest(digest->algorithm)) { + unsigned char *allocated; + allocated = PK11_SaveContextAlloc(digest->d.ctx, + (unsigned char *)checkpoint->mem, + sizeof(checkpoint->mem), + &checkpoint->bytes_used); + /* No allocation is allowed here. */ + tor_assert(allocated == checkpoint->mem); + return; + } + memcpy(checkpoint->mem, digest, bytes); +} + +/** Restore the state of digest from checkpoint. + * Asserts that digest is a SHA1 digest object. Requires that the + * state was previously stored with crypto_digest_checkpoint() */ +void +crypto_digest_restore(crypto_digest_t *digest, + const crypto_digest_checkpoint_t *checkpoint) +{ + const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); + if (library_supports_digest(digest->algorithm)) { + SECStatus s = PK11_RestoreContext(digest->d.ctx, + (unsigned char *)checkpoint->mem, + checkpoint->bytes_used); + tor_assert(s == SECSuccess); + return; + } + memcpy(digest, checkpoint->mem, bytes); +} + +/** Replace the state of the digest object into with the state + * of the digest object from. Requires that 'into' and 'from' + * have the same digest type. + */ +void +crypto_digest_assign(crypto_digest_t *into, + const crypto_digest_t *from) +{ + tor_assert(into); + tor_assert(from); + tor_assert(into->algorithm == from->algorithm); + const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm); + if (library_supports_digest(from->algorithm)) { + PK11_DestroyContext(into->d.ctx, PR_TRUE); + into->d.ctx = PK11_CloneContext(from->d.ctx); + return; + } + memcpy(into,from,alloc_bytes); +} + +/** Given a list of strings in lst, set the len_out-byte digest + * at digest_out to the hash of the concatenation of those strings, + * plus the optional string append, computed with the algorithm + * alg. + * out_len must be \<= DIGEST512_LEN. */ +void +crypto_digest_smartlist(char *digest_out, size_t len_out, + const smartlist_t *lst, + const char *append, + digest_algorithm_t alg) +{ + crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg); +} + +/** Given a list of strings in lst, set the len_out-byte digest + * at digest_out to the hash of the concatenation of: the + * optional string prepend, those strings, + * and the optional string append, computed with the algorithm + * alg. + * len_out must be \<= DIGEST512_LEN. */ +void +crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, + const char *prepend, + const smartlist_t *lst, + const char *append, + digest_algorithm_t alg) +{ + crypto_digest_t *d = crypto_digest_new_internal(alg); + if (prepend) + crypto_digest_add_bytes(d, prepend, strlen(prepend)); + SMARTLIST_FOREACH(lst, const char *, cp, + crypto_digest_add_bytes(d, cp, strlen(cp))); + if (append) + crypto_digest_add_bytes(d, append, strlen(append)); + crypto_digest_get_digest(d, digest_out, len_out); + crypto_digest_free(d); +} + +/** Compute the HMAC-SHA-256 of the msg_len bytes in msg, using + * the key of length key_len. Store the DIGEST256_LEN-byte + * result in hmac_out. Asserts on failure. + */ +void +crypto_hmac_sha256(char *hmac_out, + const char *key, size_t key_len, + const char *msg, size_t msg_len) +{ + /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */ + tor_assert(key_len < INT_MAX); + tor_assert(msg_len < INT_MAX); + tor_assert(hmac_out); + + PK11SlotInfo *slot = NULL; + PK11SymKey *symKey = NULL; + PK11Context *hmac = NULL; + + int ok = 0; + SECStatus s; + SECItem keyItem, paramItem; + keyItem.data = (unsigned char *)key; + keyItem.len = (unsigned)key_len; + paramItem.type = siBuffer; + paramItem.data = NULL; + paramItem.len = 0; + + slot = PK11_GetBestSlot(CKM_SHA256_HMAC, NULL); + if (!slot) + goto done; + symKey = PK11_ImportSymKey(slot, CKM_SHA256_HMAC, + PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL); + if (!symKey) + goto done; + + hmac = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, symKey, + ¶mItem); + if (!hmac) + goto done; + s = PK11_DigestBegin(hmac); + if (s != SECSuccess) + goto done; + s = PK11_DigestOp(hmac, (const unsigned char *)msg, (unsigned int)msg_len); + if (s != SECSuccess) + goto done; + unsigned int len=0; + s = PK11_DigestFinal(hmac, (unsigned char *)hmac_out, &len, DIGEST256_LEN); + if (s != SECSuccess || len != DIGEST256_LEN) + goto done; + ok = 1; + + done: + if (hmac) + PK11_DestroyContext(hmac, PR_TRUE); + if (symKey) + PK11_FreeSymKey(symKey); + if (slot) + PK11_FreeSlot(slot); + + tor_assert(ok); +} + diff --git a/src/lib/crypt_ops/crypto_digest_openssl.c b/src/lib/crypt_ops/crypto_digest_openssl.c new file mode 100644 index 0000000000..a1c92351fc --- /dev/null +++ b/src/lib/crypt_ops/crypto_digest_openssl.c @@ -0,0 +1,522 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_digest_openssl.c + * \brief Block of functions related with digest and xof utilities and + * operations (OpenSSL specific implementations). + **/ + +#include "lib/container/smartlist.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/log/log.h" +#include "lib/log/util_bug.h" + +#include "keccak-tiny/keccak-tiny.h" + +#include +#include + +#include "lib/arch/bytes.h" + +#include "lib/crypt_ops/crypto_openssl_mgt.h" + +DISABLE_GCC_WARNING(redundant-decls) + +#include +#include + +ENABLE_GCC_WARNING(redundant-decls) + +/* Crypto digest functions */ + +/** Compute the SHA1 digest of the len bytes on data stored in + * m. Write the DIGEST_LEN byte result into digest. + * Return 0 on success, -1 on failure. + */ +MOCK_IMPL(int, +crypto_digest,(char *digest, const char *m, size_t len)) +{ + tor_assert(m); + tor_assert(digest); + if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL) { + return -1; + } + return 0; +} + +/** Compute a 256-bit digest of len bytes in data stored in m, + * using the algorithm algorithm. Write the DIGEST_LEN256-byte result + * into digest. Return 0 on success, -1 on failure. */ +int +crypto_digest256(char *digest, const char *m, size_t len, + digest_algorithm_t algorithm) +{ + tor_assert(m); + tor_assert(digest); + tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); + + int ret = 0; + if (algorithm == DIGEST_SHA256) { + ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL); + } else { +#ifdef OPENSSL_HAS_SHA3 + unsigned int dlen = DIGEST256_LEN; + ret = EVP_Digest(m, len, (uint8_t*)digest, &dlen, EVP_sha3_256(), NULL); +#else + ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len) + > -1); +#endif + } + + if (!ret) + return -1; + return 0; +} + +/** Compute a 512-bit digest of len bytes in data stored in m, + * using the algorithm algorithm. Write the DIGEST_LEN512-byte result + * into digest. Return 0 on success, -1 on failure. */ +int +crypto_digest512(char *digest, const char *m, size_t len, + digest_algorithm_t algorithm) +{ + tor_assert(m); + tor_assert(digest); + tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); + + int ret = 0; + if (algorithm == DIGEST_SHA512) { + ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest) + != NULL); + } else { +#ifdef OPENSSL_HAS_SHA3 + unsigned int dlen = DIGEST512_LEN; + ret = EVP_Digest(m, len, (uint8_t*)digest, &dlen, EVP_sha3_512(), NULL); +#else + ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len) + > -1); +#endif + } + + if (!ret) + return -1; + return 0; +} + +/** Intermediate information about the digest of a stream of data. */ +struct crypto_digest_t { + digest_algorithm_t algorithm; /**< Which algorithm is in use? */ + /** State for the digest we're using. Only one member of the + * union is usable, depending on the value of algorithm. Note also + * that space for other members might not even be allocated! + */ + union { + SHA_CTX sha1; /**< state for SHA1 */ + SHA256_CTX sha2; /**< state for SHA256 */ + SHA512_CTX sha512; /**< state for SHA512 */ +#ifdef OPENSSL_HAS_SHA3 + EVP_MD_CTX *md; +#else + keccak_state sha3; /**< state for SHA3-[256,512] */ +#endif + } d; +}; + +#ifdef TOR_UNIT_TESTS + +digest_algorithm_t +crypto_digest_get_algorithm(crypto_digest_t *digest) +{ + tor_assert(digest); + + return digest->algorithm; +} + +#endif /* defined(TOR_UNIT_TESTS) */ + +/** + * Return the number of bytes we need to malloc in order to get a + * crypto_digest_t for alg, or the number of bytes we need to wipe + * when we free one. + */ +static size_t +crypto_digest_alloc_bytes(digest_algorithm_t alg) +{ + /* Helper: returns the number of bytes in the 'f' field of 'st' */ +#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f )) + /* Gives the length of crypto_digest_t through the end of the field 'd' */ +#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \ + STRUCT_FIELD_SIZE(crypto_digest_t, f)) + switch (alg) { + case DIGEST_SHA1: + return END_OF_FIELD(d.sha1); + case DIGEST_SHA256: + return END_OF_FIELD(d.sha2); + case DIGEST_SHA512: + return END_OF_FIELD(d.sha512); +#ifdef OPENSSL_HAS_SHA3 + case DIGEST_SHA3_256: /* Fall through */ + case DIGEST_SHA3_512: + return END_OF_FIELD(d.md); +#else + case DIGEST_SHA3_256: /* Fall through */ + case DIGEST_SHA3_512: + return END_OF_FIELD(d.sha3); +#endif + default: + tor_assert(0); // LCOV_EXCL_LINE + return 0; // LCOV_EXCL_LINE + } +#undef END_OF_FIELD +#undef STRUCT_FIELD_SIZE +} + +/** + * Internal function: create and return a new digest object for 'algorithm'. + * Does not typecheck the algorithm. + */ +static crypto_digest_t * +crypto_digest_new_internal(digest_algorithm_t algorithm) +{ + crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm)); + r->algorithm = algorithm; + + switch (algorithm) + { + case DIGEST_SHA1: + SHA1_Init(&r->d.sha1); + break; + case DIGEST_SHA256: + SHA256_Init(&r->d.sha2); + break; + case DIGEST_SHA512: + SHA512_Init(&r->d.sha512); + break; +#ifdef OPENSSL_HAS_SHA3 + case DIGEST_SHA3_256: + r->d.md = EVP_MD_CTX_new(); + if (!EVP_DigestInit(r->d.md, EVP_sha3_256())) { + crypto_digest_free(r); + return NULL; + } + break; + case DIGEST_SHA3_512: + r->d.md = EVP_MD_CTX_new(); + if (!EVP_DigestInit(r->d.md, EVP_sha3_512())) { + crypto_digest_free(r); + return NULL; + } + break; +#else + case DIGEST_SHA3_256: + keccak_digest_init(&r->d.sha3, 256); + break; + case DIGEST_SHA3_512: + keccak_digest_init(&r->d.sha3, 512); + break; +#endif + default: + tor_assert_unreached(); + } + + return r; +} + +/** Allocate and return a new digest object to compute SHA1 digests. + */ +crypto_digest_t * +crypto_digest_new(void) +{ + return crypto_digest_new_internal(DIGEST_SHA1); +} + +/** Allocate and return a new digest object to compute 256-bit digests + * using algorithm. + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest256_new` + * C_RUST_COUPLED: `crypto::digest::Sha256::default` + */ +crypto_digest_t * +crypto_digest256_new(digest_algorithm_t algorithm) +{ + tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); + return crypto_digest_new_internal(algorithm); +} + +/** Allocate and return a new digest object to compute 512-bit digests + * using algorithm. */ +crypto_digest_t * +crypto_digest512_new(digest_algorithm_t algorithm) +{ + tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); + return crypto_digest_new_internal(algorithm); +} + +/** Deallocate a digest object. + */ +void +crypto_digest_free_(crypto_digest_t *digest) +{ + if (!digest) + return; +#ifdef OPENSSL_HAS_SHA3 + if (digest->algorithm == DIGEST_SHA3_256 || + digest->algorithm == DIGEST_SHA3_512) { + if (digest->d.md) { + EVP_MD_CTX_free(digest->d.md); + } + } +#endif + size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); + memwipe(digest, 0, bytes); + tor_free(digest); +} + +/** Add len bytes from data to the digest object. + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_add_bytess` + * C_RUST_COUPLED: `crypto::digest::Sha256::process` + */ +void +crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, + size_t len) +{ + tor_assert(digest); + tor_assert(data); + /* Using the SHA*_*() calls directly means we don't support doing + * SHA in hardware. But so far the delay of getting the question + * to the hardware, and hearing the answer, is likely higher than + * just doing it ourselves. Hashes are fast. + */ + switch (digest->algorithm) { + case DIGEST_SHA1: + SHA1_Update(&digest->d.sha1, (void*)data, len); + break; + case DIGEST_SHA256: + SHA256_Update(&digest->d.sha2, (void*)data, len); + break; + case DIGEST_SHA512: + SHA512_Update(&digest->d.sha512, (void*)data, len); + break; +#ifdef OPENSSL_HAS_SHA3 + case DIGEST_SHA3_256: /* FALLSTHROUGH */ + case DIGEST_SHA3_512: { + int r = EVP_DigestUpdate(digest->d.md, data, len); + tor_assert(r); + } + break; +#else + case DIGEST_SHA3_256: /* FALLSTHROUGH */ + case DIGEST_SHA3_512: + keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len); + break; +#endif + default: + /* LCOV_EXCL_START */ + tor_fragile_assert(); + break; + /* LCOV_EXCL_STOP */ + } +} + +/** Compute the hash of the data that has been passed to the digest + * object; write the first out_len bytes of the result to out. + * out_len must be \<= DIGEST512_LEN. + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_get_digest` + * C_RUST_COUPLED: `impl digest::FixedOutput for Sha256` + */ +void +crypto_digest_get_digest(crypto_digest_t *digest, + char *out, size_t out_len) +{ + unsigned char r[DIGEST512_LEN]; + tor_assert(digest); + tor_assert(out); + tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm)); + + /* The SHA-3 code handles copying into a temporary ctx, and also can handle + * short output buffers by truncating appropriately. */ + if (digest->algorithm == DIGEST_SHA3_256 || + digest->algorithm == DIGEST_SHA3_512) { +#ifdef OPENSSL_HAS_SHA3 + unsigned dlen = (unsigned) + crypto_digest_algorithm_get_length(digest->algorithm); + EVP_MD_CTX *tmp = EVP_MD_CTX_new(); + EVP_MD_CTX_copy(tmp, digest->d.md); + memset(r, 0xff, sizeof(r)); + int res = EVP_DigestFinal(tmp, r, &dlen); + EVP_MD_CTX_free(tmp); + tor_assert(res == 1); + goto done; +#else + /* Tiny-Keccak handles copying into a temporary ctx, and also can handle + * short output buffers by truncating appropriately. */ + keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len); + return; +#endif + } + + const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); + crypto_digest_t tmpenv; + /* memcpy into a temporary ctx, since SHA*_Final clears the context */ + memcpy(&tmpenv, digest, alloc_bytes); + switch (digest->algorithm) { + case DIGEST_SHA1: + SHA1_Final(r, &tmpenv.d.sha1); + break; + case DIGEST_SHA256: + SHA256_Final(r, &tmpenv.d.sha2); + break; + case DIGEST_SHA512: + SHA512_Final(r, &tmpenv.d.sha512); + break; +//LCOV_EXCL_START + case DIGEST_SHA3_256: /* FALLSTHROUGH */ + case DIGEST_SHA3_512: + default: + log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm); + /* This is fatal, because it should never happen. */ + tor_assert_unreached(); + break; +//LCOV_EXCL_STOP + } +#ifdef OPENSSL_HAS_SHA3 + done: +#endif + memcpy(out, r, out_len); + memwipe(r, 0, sizeof(r)); +} + +/** Allocate and return a new digest object with the same state as + * digest + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_dup` + * C_RUST_COUPLED: `impl Clone for crypto::digest::Sha256` + */ +crypto_digest_t * +crypto_digest_dup(const crypto_digest_t *digest) +{ + tor_assert(digest); + const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); + crypto_digest_t *result = tor_memdup(digest, alloc_bytes); + +#ifdef OPENSSL_HAS_SHA3 + if (digest->algorithm == DIGEST_SHA3_256 || + digest->algorithm == DIGEST_SHA3_512) { + result->d.md = EVP_MD_CTX_new(); + EVP_MD_CTX_copy(result->d.md, digest->d.md); + } +#endif + return result; +} + +/** Temporarily save the state of digest in checkpoint. + * Asserts that digest is a SHA1 digest object. + */ +void +crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint, + const crypto_digest_t *digest) +{ + const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); + tor_assert(bytes <= sizeof(checkpoint->mem)); + memcpy(checkpoint->mem, digest, bytes); +} + +/** Restore the state of digest from checkpoint. + * Asserts that digest is a SHA1 digest object. Requires that the + * state was previously stored with crypto_digest_checkpoint() */ +void +crypto_digest_restore(crypto_digest_t *digest, + const crypto_digest_checkpoint_t *checkpoint) +{ + const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); + memcpy(digest, checkpoint->mem, bytes); +} + +/** Replace the state of the digest object into with the state + * of the digest object from. Requires that 'into' and 'from' + * have the same digest type. + */ +void +crypto_digest_assign(crypto_digest_t *into, + const crypto_digest_t *from) +{ + tor_assert(into); + tor_assert(from); + tor_assert(into->algorithm == from->algorithm); + const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm); + +#ifdef OPENSSL_HAS_SHA3 + if (from->algorithm == DIGEST_SHA3_256 || + from->algorithm == DIGEST_SHA3_512) { + EVP_MD_CTX_copy(into->d.md, from->d.md); + return; + } +#endif + + memcpy(into,from,alloc_bytes); +} + +/** Given a list of strings in lst, set the len_out-byte digest + * at digest_out to the hash of the concatenation of those strings, + * plus the optional string append, computed with the algorithm + * alg. + * out_len must be \<= DIGEST512_LEN. */ +void +crypto_digest_smartlist(char *digest_out, size_t len_out, + const smartlist_t *lst, + const char *append, + digest_algorithm_t alg) +{ + crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg); +} + +/** Given a list of strings in lst, set the len_out-byte digest + * at digest_out to the hash of the concatenation of: the + * optional string prepend, those strings, + * and the optional string append, computed with the algorithm + * alg. + * len_out must be \<= DIGEST512_LEN. */ +void +crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, + const char *prepend, + const smartlist_t *lst, + const char *append, + digest_algorithm_t alg) +{ + crypto_digest_t *d = crypto_digest_new_internal(alg); + if (prepend) + crypto_digest_add_bytes(d, prepend, strlen(prepend)); + SMARTLIST_FOREACH(lst, const char *, cp, + crypto_digest_add_bytes(d, cp, strlen(cp))); + if (append) + crypto_digest_add_bytes(d, append, strlen(append)); + crypto_digest_get_digest(d, digest_out, len_out); + crypto_digest_free(d); +} + +/** Compute the HMAC-SHA-256 of the msg_len bytes in msg, using + * the key of length key_len. Store the DIGEST256_LEN-byte + * result in hmac_out. Asserts on failure. + */ +void +crypto_hmac_sha256(char *hmac_out, + const char *key, size_t key_len, + const char *msg, size_t msg_len) +{ + /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */ + tor_assert(key_len < INT_MAX); + tor_assert(msg_len < INT_MAX); + tor_assert(hmac_out); + unsigned char *rv = NULL; + rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len, + (unsigned char*)hmac_out, NULL); + tor_assert(rv); +} + diff --git a/src/lib/crypt_ops/include.am b/src/lib/crypt_ops/include.am index 4730440143..c90ef6eca8 100644 --- a/src/lib/crypt_ops/include.am +++ b/src/lib/crypt_ops/include.am @@ -27,12 +27,14 @@ src_lib_libtor_crypt_ops_a_SOURCES = \ if USE_NSS src_lib_libtor_crypt_ops_a_SOURCES += \ src/lib/crypt_ops/aes_nss.c \ + src/lib/crypt_ops/crypto_digest_nss.c \ src/lib/crypt_ops/crypto_dh_nss.c \ src/lib/crypt_ops/crypto_nss_mgt.c \ src/lib/crypt_ops/crypto_rsa_nss.c else src_lib_libtor_crypt_ops_a_SOURCES += \ src/lib/crypt_ops/aes_openssl.c \ + src/lib/crypt_ops/crypto_digest_openssl.c \ src/lib/crypt_ops/crypto_rsa_openssl.c endif -- cgit v1.2.3-54-g00ecf From 27eec505270ba6378e8ff732da5432b30ac107f7 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sun, 3 Mar 2019 11:51:08 +0200 Subject: manpage: fix formatting of example on quoting options with spaces --- changes/ticket29635 | 3 +++ doc/tor.1.txt | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 changes/ticket29635 (limited to 'changes') diff --git a/changes/ticket29635 b/changes/ticket29635 new file mode 100644 index 0000000000..cbadbf648a --- /dev/null +++ b/changes/ticket29635 @@ -0,0 +1,3 @@ + o Minor bugfixes (documentation, manpage): + - Use proper formatting when providing an example on quoting options that + contain whitespace. Fixes bug 29635; bugfix on 0.2.3.18-rc. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 52f5bfa0c3..ee91976066 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -147,8 +147,8 @@ instance, you can tell Tor to start listening for SOCKS connections on port 9999 by passing --SocksPort 9999 or SocksPort 9999 to it on the command line, or by putting "SocksPort 9999" in the configuration file. You will need to quote options with spaces in them: if you want Tor to log all debugging -messages to debug.log, you will probably need to say --Log 'debug file -debug.log'. +messages to debug.log, you will probably need to say **--Log** `"debug file +debug.log"`. Options on the command line override those in configuration files. See the next section for more information. -- cgit v1.2.3-54-g00ecf From e52d725977ffc7d47992375772b5936d36bb9d7d Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 4 Mar 2019 11:21:15 +1000 Subject: doc: Improve the monotonic time module and function documentation Explain what "monotonic" actually means, and document some results that have surprised people. Fixes bug 29640; bugfix on 0.2.9.1-alpha. --- changes/bug29640 | 4 ++++ src/lib/time/compat_time.c | 10 +++++++++- src/lib/time/compat_time.h | 50 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 changes/bug29640 (limited to 'changes') diff --git a/changes/bug29640 b/changes/bug29640 new file mode 100644 index 0000000000..81adeae32a --- /dev/null +++ b/changes/bug29640 @@ -0,0 +1,4 @@ + o Minor bugfixes (documentation): + - Improve the monotonic time module and function documentation. Explain + what "monotonic" actually means, and document some results that have + surprised people. Fixes bug 29640; bugfix on 0.2.9.1-alpha. diff --git a/src/lib/time/compat_time.c b/src/lib/time/compat_time.c index 33e077a587..94823b8a0a 100644 --- a/src/lib/time/compat_time.c +++ b/src/lib/time/compat_time.c @@ -164,6 +164,8 @@ static int64_t last_tick_count = 0; * to be monotonic; increments them as appropriate so that they actually * _are_ monotonic. * + * The returned time may be the same as the previous returned time. + * * Caller must hold lock. */ STATIC int64_t ratchet_performance_counter(int64_t count_raw) @@ -202,6 +204,8 @@ static struct timeval timeofday_offset = { 0, 0 }; * supposed to be monotonic; increments them as appropriate so that they * actually _are_ monotonic. * + * The returned time may be the same as the previous returned time. + * * Caller must hold lock. */ STATIC void ratchet_timeval(const struct timeval *timeval_raw, struct timeval *out) @@ -270,7 +274,9 @@ monotime_init_internal(void) } /** - * Set "out" to the most recent monotonic time value + * Set "out" to the most recent monotonic time value. + * + * The returned time may be the same as the previous returned time. */ void monotime_get(monotime_t *out) @@ -302,6 +308,8 @@ monotime_coarse_get(monotime_coarse_t *out) /** * Return the number of nanoseconds between start and end. + * + * The returned value may be equal to zero. */ int64_t monotime_diff_nsec(const monotime_t *start, diff --git a/src/lib/time/compat_time.h b/src/lib/time/compat_time.h index 2cd4b3bee3..360d92e5c9 100644 --- a/src/lib/time/compat_time.h +++ b/src/lib/time/compat_time.h @@ -15,11 +15,29 @@ * of tens of milliseconds. */ -/* Q: Should you use monotime or monotime_coarse as your source? +/* Q: When should I use monotonic time? + * + * A: If you need a time that never decreases, use monotonic time. If you need + * to send a time to a user or another process, or store a time, use the + * wall-clock time. + * + * Q: Should you use monotime or monotime_coarse as your source? * * A: Generally, you get better precision with monotime, but better * performance with monotime_coarse. * + * Q: What is a "monotonic" time, exactly? + * + * A: Monotonic times are strictly non-decreasing. The difference between any + * previous monotonic time, and the current monotonic time, is always greater + * than *or equal to* zero. + * Zero deltas happen more often: + * - on Windows (due to an OS bug), + * - when using monotime_coarse, or on systems with low-resolution timers, + * - on platforms where we emulate monotonic time using wall-clock time, and + * - when using time units that are larger than nanoseconds (due to + * truncation on division). + * * Q: Should you use monotime_t or monotime_coarse_t directly? Should you use * usec? msec? "stamp units?" * @@ -95,7 +113,7 @@ * All, "timestamp units": Cheap everywhere: it never divides. * * Q: This is only somewhat related, but how much precision could I hope for - * from a libevent time.? + * from a libevent time? * * A: Actually, it's _very_ related if you're timing in order to have a * timeout happen. @@ -182,26 +200,36 @@ void monotime_init(void); void monotime_get(monotime_t *out); /** * Return the number of nanoseconds between start and end. + * The returned value may be equal to zero. */ int64_t monotime_diff_nsec(const monotime_t *start, const monotime_t *end); /** * Return the number of microseconds between start and end. + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ int64_t monotime_diff_usec(const monotime_t *start, const monotime_t *end); /** * Return the number of milliseconds between start and end. + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ int64_t monotime_diff_msec(const monotime_t *start, const monotime_t *end); /** * Return the number of nanoseconds since the timer system was initialized. + * The returned value may be equal to zero. */ uint64_t monotime_absolute_nsec(void); /** * Return the number of microseconds since the timer system was initialized. + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ MOCK_DECL(uint64_t, monotime_absolute_usec,(void)); /** * Return the number of milliseconds since the timer system was initialized. + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ uint64_t monotime_absolute_msec(void); @@ -225,6 +253,9 @@ void monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec); * Set out to the current coarse time. */ void monotime_coarse_get(monotime_coarse_t *out); +/** + * Like monotime_absolute_*(), but faster on some platforms. + */ uint64_t monotime_coarse_absolute_nsec(void); uint64_t monotime_coarse_absolute_usec(void); uint64_t monotime_coarse_absolute_msec(void); @@ -248,18 +279,27 @@ uint32_t monotime_coarse_to_stamp(const monotime_coarse_t *t); /** * Convert a difference, expressed in the units of monotime_coarse_to_stamp, * into an approximate number of milliseconds. + * + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ uint64_t monotime_coarse_stamp_units_to_approx_msec(uint64_t units); uint64_t monotime_msec_to_approx_coarse_stamp_units(uint64_t msec); uint32_t monotime_coarse_get_stamp(void); #if defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT) +/** + * Like monotime_diff_*(), but faster on some platforms. + */ int64_t monotime_coarse_diff_nsec(const monotime_coarse_t *start, const monotime_coarse_t *end); int64_t monotime_coarse_diff_usec(const monotime_coarse_t *start, const monotime_coarse_t *end); int64_t monotime_coarse_diff_msec(const monotime_coarse_t *start, const monotime_coarse_t *end); +/** + * Like monotime_*(), but faster on some platforms. + */ void monotime_coarse_zero(monotime_coarse_t *out); int monotime_coarse_is_zero(const monotime_coarse_t *val); void monotime_coarse_add_msec(monotime_coarse_t *out, @@ -278,6 +318,9 @@ void monotime_coarse_add_msec(monotime_coarse_t *out, * * Requires that the difference fit into an int32_t; not for use with * large time differences. + * + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ int32_t monotime_coarse_diff_msec32_(const monotime_coarse_t *start, const monotime_coarse_t *end); @@ -287,6 +330,9 @@ int32_t monotime_coarse_diff_msec32_(const monotime_coarse_t *start, * * Requires that the difference fit into an int32_t; not for use with * large time differences. + * + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ static inline int32_t monotime_coarse_diff_msec32(const monotime_coarse_t *start, -- cgit v1.2.3-54-g00ecf From 4578c3eb219e93da9b1aaa37c4f3c5f61c7106f5 Mon Sep 17 00:00:00 2001 From: David Fifield Date: Fri, 22 Feb 2019 23:54:17 -0700 Subject: Set TOR_PT_EXIT_ON_STDIN_CLOSE=1 for client transports too. Closes #25614. --- changes/ticket25614 | 3 +++ src/feature/client/transports.c | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 changes/ticket25614 (limited to 'changes') diff --git a/changes/ticket25614 b/changes/ticket25614 new file mode 100644 index 0000000000..ad05549021 --- /dev/null +++ b/changes/ticket25614 @@ -0,0 +1,3 @@ + o Minor bugfixes (pluggable transports): + - Tor now sets TOR_PT_EXIT_ON_STDIN_CLOSE=1 for client transports as + well as servers. Closes ticket 25614. diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c index e7ff3bf34a..6fb357b466 100644 --- a/src/feature/client/transports.c +++ b/src/feature/client/transports.c @@ -1424,11 +1424,6 @@ create_managed_proxy_environment(const managed_proxy_t *mp) } else { smartlist_add_asprintf(envs, "TOR_PT_EXTENDED_SERVER_PORT="); } - - /* All new versions of tor will keep stdin open, so PTs can use it - * as a reliable termination detection mechanism. - */ - smartlist_add_asprintf(envs, "TOR_PT_EXIT_ON_STDIN_CLOSE=1"); } else { /* If ClientTransportPlugin has a HTTPS/SOCKS proxy configured, set the * TOR_PT_PROXY line. @@ -1439,6 +1434,11 @@ create_managed_proxy_environment(const managed_proxy_t *mp) } } + /* All new versions of tor will keep stdin open, so PTs can use it + * as a reliable termination detection mechanism. + */ + smartlist_add_asprintf(envs, "TOR_PT_EXIT_ON_STDIN_CLOSE=1"); + SMARTLIST_FOREACH_BEGIN(envs, const char *, env_var) { set_environment_variable_in_smartlist(merged_env_vars, env_var, tor_free_, 1); -- cgit v1.2.3-54-g00ecf From c9a9de120f4287ccb5cd3998916cbe7b81dba89a Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Tue, 5 Mar 2019 15:50:30 +0100 Subject: Fix changelog for ticket 25614 to make it pass check-changes. Yawning's commit in fda61e030e12cbd66a2be9905e6855ec6c6a3c63 was used to find which version this is a bugfix on. --- changes/ticket25614 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'changes') diff --git a/changes/ticket25614 b/changes/ticket25614 index ad05549021..82988eeace 100644 --- a/changes/ticket25614 +++ b/changes/ticket25614 @@ -1,3 +1,3 @@ o Minor bugfixes (pluggable transports): - Tor now sets TOR_PT_EXIT_ON_STDIN_CLOSE=1 for client transports as - well as servers. Closes ticket 25614. + well as servers. Fixes bug 25614; bugfix on 0.2.7.1-alpha. -- cgit v1.2.3-54-g00ecf From a999cb43df3dc4e64820347486a2d861636bfc2e Mon Sep 17 00:00:00 2001 From: David Goulet Date: Fri, 1 Mar 2019 13:50:00 -0500 Subject: protover: Add missing Padding to translate_to_rust This commit also explicitly set the value of the PRT enum so we can match/pin the C enum values to the Rust one in protover/ffi.rs. Fixes #29631 Signed-off-by: David Goulet --- changes/ticket29631 | 4 ++++ src/core/or/protover.h | 22 +++++++++++----------- src/rust/protover/ffi.rs | 1 + 3 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 changes/ticket29631 (limited to 'changes') diff --git a/changes/ticket29631 b/changes/ticket29631 new file mode 100644 index 0000000000..9fc194ba96 --- /dev/null +++ b/changes/ticket29631 @@ -0,0 +1,4 @@ + o Minor bugfixes (Rust, protover): + - The Rust implementation of protover was missing the "Padding" value in + the translate function from C to Rust. Fixes bug 29631; bugfix on + 0.4.0.1-alpha. diff --git a/src/core/or/protover.h b/src/core/or/protover.h index 27106d4bec..567b94a168 100644 --- a/src/core/or/protover.h +++ b/src/core/or/protover.h @@ -33,17 +33,17 @@ struct smartlist_t; /// C_RUST_COUPLED: src/rust/protover/ffi.rs `translate_to_rust` /// C_RUST_COUPLED: src/rust/protover/protover.rs `Proto` typedef enum protocol_type_t { - PRT_LINK, - PRT_LINKAUTH, - PRT_RELAY, - PRT_DIRCACHE, - PRT_HSDIR, - PRT_HSINTRO, - PRT_HSREND, - PRT_DESC, - PRT_MICRODESC, - PRT_CONS, - PRT_PADDING, + PRT_LINK = 0, + PRT_LINKAUTH = 1, + PRT_RELAY = 2, + PRT_DIRCACHE = 3, + PRT_HSDIR = 4, + PRT_HSINTRO = 5, + PRT_HSREND = 6, + PRT_DESC = 7, + PRT_MICRODESC = 8, + PRT_CONS = 9, + PRT_PADDING = 10, } protocol_type_t; bool protover_contains_long_protocol_names(const char *s); diff --git a/src/rust/protover/ffi.rs b/src/rust/protover/ffi.rs index 6ee63adb10..066b08eddb 100644 --- a/src/rust/protover/ffi.rs +++ b/src/rust/protover/ffi.rs @@ -30,6 +30,7 @@ fn translate_to_rust(c_proto: uint32_t) -> Result { 7 => Ok(Protocol::Desc), 8 => Ok(Protocol::Microdesc), 9 => Ok(Protocol::Cons), + 10 => Ok(Protocol::Padding), _ => Err(ProtoverError::UnknownProtocol), } } -- cgit v1.2.3-54-g00ecf From ae5a0f39cd3d0098ca684c7dfb83ebfe3acca8b6 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Wed, 20 Feb 2019 09:35:27 +0200 Subject: Update git pre-push hook so that only upstream branches can get pushed to origin --- changes/feature29532 | 4 ++++ scripts/maint/pre-push.git-hook | 21 ++++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 changes/feature29532 (limited to 'changes') diff --git a/changes/feature29532 b/changes/feature29532 new file mode 100644 index 0000000000..4d95e6bca8 --- /dev/null +++ b/changes/feature29532 @@ -0,0 +1,4 @@ + o Minor features (developer tooling): + - Modify git pre-push hook script to disallow pushing branches other than + master, release-* and maint-* to origin remote. Implements feature + 29532. diff --git a/scripts/maint/pre-push.git-hook b/scripts/maint/pre-push.git-hook index 26296023fb..78d62527e0 100755 --- a/scripts/maint/pre-push.git-hook +++ b/scripts/maint/pre-push.git-hook @@ -1,17 +1,32 @@ #!/bin/bash +# git pre-push hook script to prevent "fixup!" and "squash!" commit +# from ending up in master, or in any branch if CUR_BRANCH check is removed. +# Furthermore, it disallows pushing branches other than master, release-* +# and maint-* to origin (e.g. gitweb.torproject.org). +# # To install this script, copy it into .git/hooks/pre-push path in your # local copy of git repository. Make sure it has permission to execute. # -# This is git pre-push hook script to prevent "fixup!" and "squash!" commits -# from ending up in upstream branches (master, release-* or maint-*). -# # The following sample script was used as starting point: # https://github.com/git/git/blob/master/templates/hooks--pre-push.sample z40=0000000000000000000000000000000000000000 +remote="$1" CUR_BRANCH=$(git rev-parse --abbrev-ref HEAD) + +# Only allow pushing master, release-* and maint-* branches to origin. +if [ "$remote" == "origin" ] +then + if [ "$CUR_BRANCH" != "master" ] && [[ $CUR_BRANCH != release-* ]] && + [[ $CUR_BRANCH != maint-* ]] + then + echo >&2 "Not pushing $CUR_BRANCH to origin" + exit 1 + fi +fi + if [ "$CUR_BRANCH" != "master" ] && [[ $CUR_BRANCH != release-* ]] && [[ $CUR_BRANCH != maint-* ]] then -- cgit v1.2.3-54-g00ecf From cd67911033e83e9b83a5bb5d62832fb0c6077ca7 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Thu, 21 Feb 2019 01:34:55 +0000 Subject: Bug 29204: Inspect circuit queues before sending padding. Mitigates OOM conditions at relays. --- changes/bug29204 | 4 ++++ src/core/or/circuitpadding.c | 21 +++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 changes/bug29204 (limited to 'changes') diff --git a/changes/bug29204 b/changes/bug29204 new file mode 100644 index 0000000000..ec2cf67b2f --- /dev/null +++ b/changes/bug29204 @@ -0,0 +1,4 @@ + o Minor bugfixes (circuitpadding): + - Inspect circuit-level cell queue before sending padding, to avoid + sending padding while too much data is queued. Fixes bug 29204; + bugfix on 0.4.0.1-alpha. diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c index 0dadc52139..ba6bfe1f53 100644 --- a/src/core/or/circuitpadding.c +++ b/src/core/or/circuitpadding.c @@ -61,6 +61,7 @@ #include "core/or/crypt_path_st.h" #include "core/or/circuit_st.h" #include "core/or/origin_circuit_st.h" +#include "core/or/or_circuit_st.h" #include "feature/nodelist/routerstatus_st.h" #include "feature/nodelist/node_st.h" #include "core/or/cell_st.h" @@ -81,6 +82,7 @@ static double circpad_distribution_sample(circpad_distribution_t dist); /** Cached consensus params */ static uint8_t circpad_global_max_padding_percent; static uint16_t circpad_global_allowed_cells; +static uint16_t circpad_max_circ_queued_cells; /** Global cell counts, for rate limiting */ static uint64_t circpad_global_padding_sent; @@ -1027,10 +1029,17 @@ circpad_send_padding_cell_for_callback(circpad_machine_state_t *mi) } else { // If we're a non-origin circ, we can just send from here as if we're the // edge. - log_fn(LOG_INFO,LD_CIRC, - "Callback: Sending padding to non-origin circuit."); - relay_send_command_from_edge(0, mi->on_circ, RELAY_COMMAND_DROP, NULL, - 0, NULL); + if (TO_OR_CIRCUIT(circ)->p_chan_cells.n <= circpad_max_circ_queued_cells) { + log_fn(LOG_INFO,LD_CIRC, + "Callback: Sending padding to non-origin circuit."); + relay_send_command_from_edge(0, mi->on_circ, RELAY_COMMAND_DROP, NULL, + 0, NULL); + } else { + static ratelim_t cell_lim = RATELIM_INIT(600); + log_fn_ratelim(&cell_lim,LOG_NOTICE,LD_CIRC, + "Too many cells (%d) in circ queue to send padding.", + TO_OR_CIRCUIT(circ)->p_chan_cells.n); + } } rep_hist_padding_count_write(PADDING_TYPE_DROP); @@ -1093,6 +1102,10 @@ circpad_new_consensus_params(const networkstatus_t *ns) circpad_global_max_padding_percent = networkstatus_get_param(ns, "circpad_global_max_padding_pct", 0, 0, 100); + + circpad_max_circ_queued_cells = + networkstatus_get_param(ns, "circpad_max_circ_queued_cells", + CIRCWINDOW_START_MAX, 0, 50*CIRCWINDOW_START_MAX); } /** -- cgit v1.2.3-54-g00ecf From ff410edec04793d6d72f9961acd2f13a5ee3b9b5 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Thu, 21 Feb 2019 01:34:55 +0000 Subject: Bug 29204: Inspect circuit queues before sending padding. Mitigates OOM conditions at relays. --- changes/bug29204 | 4 ++++ src/core/or/circuitpadding.c | 21 +++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 changes/bug29204 (limited to 'changes') diff --git a/changes/bug29204 b/changes/bug29204 new file mode 100644 index 0000000000..ec2cf67b2f --- /dev/null +++ b/changes/bug29204 @@ -0,0 +1,4 @@ + o Minor bugfixes (circuitpadding): + - Inspect circuit-level cell queue before sending padding, to avoid + sending padding while too much data is queued. Fixes bug 29204; + bugfix on 0.4.0.1-alpha. diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c index 0dadc52139..ba6bfe1f53 100644 --- a/src/core/or/circuitpadding.c +++ b/src/core/or/circuitpadding.c @@ -61,6 +61,7 @@ #include "core/or/crypt_path_st.h" #include "core/or/circuit_st.h" #include "core/or/origin_circuit_st.h" +#include "core/or/or_circuit_st.h" #include "feature/nodelist/routerstatus_st.h" #include "feature/nodelist/node_st.h" #include "core/or/cell_st.h" @@ -81,6 +82,7 @@ static double circpad_distribution_sample(circpad_distribution_t dist); /** Cached consensus params */ static uint8_t circpad_global_max_padding_percent; static uint16_t circpad_global_allowed_cells; +static uint16_t circpad_max_circ_queued_cells; /** Global cell counts, for rate limiting */ static uint64_t circpad_global_padding_sent; @@ -1027,10 +1029,17 @@ circpad_send_padding_cell_for_callback(circpad_machine_state_t *mi) } else { // If we're a non-origin circ, we can just send from here as if we're the // edge. - log_fn(LOG_INFO,LD_CIRC, - "Callback: Sending padding to non-origin circuit."); - relay_send_command_from_edge(0, mi->on_circ, RELAY_COMMAND_DROP, NULL, - 0, NULL); + if (TO_OR_CIRCUIT(circ)->p_chan_cells.n <= circpad_max_circ_queued_cells) { + log_fn(LOG_INFO,LD_CIRC, + "Callback: Sending padding to non-origin circuit."); + relay_send_command_from_edge(0, mi->on_circ, RELAY_COMMAND_DROP, NULL, + 0, NULL); + } else { + static ratelim_t cell_lim = RATELIM_INIT(600); + log_fn_ratelim(&cell_lim,LOG_NOTICE,LD_CIRC, + "Too many cells (%d) in circ queue to send padding.", + TO_OR_CIRCUIT(circ)->p_chan_cells.n); + } } rep_hist_padding_count_write(PADDING_TYPE_DROP); @@ -1093,6 +1102,10 @@ circpad_new_consensus_params(const networkstatus_t *ns) circpad_global_max_padding_percent = networkstatus_get_param(ns, "circpad_global_max_padding_pct", 0, 0, 100); + + circpad_max_circ_queued_cells = + networkstatus_get_param(ns, "circpad_max_circ_queued_cells", + CIRCWINDOW_START_MAX, 0, 50*CIRCWINDOW_START_MAX); } /** -- cgit v1.2.3-54-g00ecf From 26e6f56023e749800d95bbc5669c60197d481314 Mon Sep 17 00:00:00 2001 From: teor Date: Sat, 9 Mar 2019 10:50:55 +1000 Subject: sr: Free SRVs before replacing them in state_query_put_() Refactor the shared random state's memory management so that it actually takes ownership of the shared random value pointers. Fixes bug 29706; bugfix on 0.2.9.1-alpha. --- changes/bug29706_refactor | 4 ++++ src/or/shared_random.c | 2 +- src/or/shared_random.h | 3 ++- src/or/shared_random_state.c | 20 ++++++++++++++------ src/test/test_shared_random.c | 25 +++++++++++++++---------- 5 files changed, 36 insertions(+), 18 deletions(-) create mode 100644 changes/bug29706_refactor (limited to 'changes') diff --git a/changes/bug29706_refactor b/changes/bug29706_refactor new file mode 100644 index 0000000000..ba1d0c7edd --- /dev/null +++ b/changes/bug29706_refactor @@ -0,0 +1,4 @@ + o Minor bugfixes (memory management): + - Refactor the shared random state's memory management so that it actually + takes ownership of the shared random value pointers. + Fixes bug 29706; bugfix on 0.2.9.1-alpha. diff --git a/src/or/shared_random.c b/src/or/shared_random.c index 5f6b03f1ba..c3e6409771 100644 --- a/src/or/shared_random.c +++ b/src/or/shared_random.c @@ -112,7 +112,7 @@ static const char sr_flag_ns_str[] = "shared-rand-participate"; static int32_t num_srv_agreements_from_vote; /* Return a heap allocated copy of the SRV orig. */ -STATIC sr_srv_t * +sr_srv_t * srv_dup(const sr_srv_t *orig) { sr_srv_t *duplicate = NULL; diff --git a/src/or/shared_random.h b/src/or/shared_random.h index 9885934cc7..68a1019794 100644 --- a/src/or/shared_random.h +++ b/src/or/shared_random.h @@ -129,6 +129,8 @@ const char *sr_commit_get_rsa_fpr(const sr_commit_t *commit) void sr_compute_srv(void); sr_commit_t *sr_generate_our_commit(time_t timestamp, const authority_cert_t *my_rsa_cert); +sr_srv_t *srv_dup(const sr_srv_t *orig); + #ifdef SHARED_RANDOM_PRIVATE /* Encode */ @@ -146,7 +148,6 @@ STATIC sr_srv_t *get_majority_srv_from_votes(const smartlist_t *votes, int current); STATIC void save_commit_to_state(sr_commit_t *commit); -STATIC sr_srv_t *srv_dup(const sr_srv_t *orig); STATIC int commitments_are_the_same(const sr_commit_t *commit_one, const sr_commit_t *commit_two); STATIC int commit_is_authoritative(const sr_commit_t *commit, diff --git a/src/or/shared_random_state.c b/src/or/shared_random_state.c index f27eccafc7..e99817106c 100644 --- a/src/or/shared_random_state.c +++ b/src/or/shared_random_state.c @@ -92,6 +92,8 @@ static const config_format_t state_format = { &state_extra_var, }; +static void state_query_del_(sr_state_object_t obj_type, void *data); + /* Return a string representation of a protocol phase. */ STATIC const char * get_phase_str(sr_phase_t phase) @@ -883,7 +885,8 @@ state_query_get_(sr_state_object_t obj_type, const void *data) } /* Helper function: This handles the PUT state action using an - * obj_type and data needed for the action. */ + * obj_type and data needed for the action. + * PUT frees the previous data before replacing it, if needed. */ static void state_query_put_(sr_state_object_t obj_type, void *data) { @@ -892,13 +895,18 @@ state_query_put_(sr_state_object_t obj_type, void *data) { sr_commit_t *commit = data; tor_assert(commit); + /* commit_add_to_state() frees the old commit, if there is one */ commit_add_to_state(commit, sr_state); break; } case SR_STATE_OBJ_CURSRV: + /* Always free the old SRV */ + state_query_del_(SR_STATE_OBJ_CURSRV, NULL); sr_state->current_srv = (sr_srv_t *) data; break; case SR_STATE_OBJ_PREVSRV: + /* Always free the old SRV */ + state_query_del_(SR_STATE_OBJ_PREVSRV, NULL); sr_state->previous_srv = (sr_srv_t *) data; break; case SR_STATE_OBJ_VALID_AFTER: @@ -1021,16 +1029,16 @@ state_del_previous_srv(void) state_query(SR_STATE_ACTION_DEL, SR_STATE_OBJ_PREVSRV, NULL, NULL); } -/* Rotate SRV value by freeing the previous value, assigning the current - * value to the previous one and nullifying the current one. */ +/* Rotate SRV value by setting the previous SRV to the current SRV, and + * clearing the current SRV. */ STATIC void state_rotate_srv(void) { /* First delete previous SRV from the state. Object will be freed. */ state_del_previous_srv(); - /* Set previous SRV with the current one. */ - sr_state_set_previous_srv(sr_state_get_current_srv()); - /* Nullify the current srv. */ + /* Set previous SRV to a copy of the current one. */ + sr_state_set_previous_srv(srv_dup(sr_state_get_current_srv())); + /* Free and NULL the current srv. */ sr_state_set_current_srv(NULL); } diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c index 0a3c2e119b..5d3e574fac 100644 --- a/src/test/test_shared_random.c +++ b/src/test/test_shared_random.c @@ -1013,6 +1013,7 @@ test_state_transition(void *arg) { sr_state_t *state = NULL; time_t now = time(NULL); + sr_srv_t *cur = NULL; (void) arg; @@ -1051,44 +1052,47 @@ test_state_transition(void *arg) /* Test SRV rotation in our state. */ { - const sr_srv_t *cur, *prev; test_sr_setup_srv(1); - cur = sr_state_get_current_srv(); + tt_assert(sr_state_get_current_srv()); + /* Take a copy of the data, because the state owns the pointer */ + cur = srv_dup(sr_state_get_current_srv()); tt_assert(cur); - /* After, current srv should be the previous and then set to NULL. */ + /* After, the previous SRV should be the same as the old current SRV, and + * the current SRV should be set to NULL */ state_rotate_srv(); - prev = sr_state_get_previous_srv(); - tt_assert(prev == cur); + tt_mem_op(sr_state_get_previous_srv(), OP_EQ, cur, sizeof(sr_srv_t)); tt_assert(!sr_state_get_current_srv()); sr_state_clean_srvs(); + tor_free(cur); } /* New protocol run. */ { - const sr_srv_t *cur; /* Setup some new SRVs so we can confirm that a new protocol run * actually makes them rotate and compute new ones. */ test_sr_setup_srv(1); - cur = sr_state_get_current_srv(); - tt_assert(cur); + tt_assert(sr_state_get_current_srv()); + /* Take a copy of the data, because the state owns the pointer */ + cur = srv_dup(sr_state_get_current_srv()); set_sr_phase(SR_PHASE_REVEAL); MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m); new_protocol_run(now); UNMOCK(get_my_v3_authority_cert); /* Rotation happened. */ - tt_assert(sr_state_get_previous_srv() == cur); + tt_mem_op(sr_state_get_previous_srv(), OP_EQ, cur, sizeof(sr_srv_t)); /* We are going into COMMIT phase so we had to rotate our SRVs. Usually * our current SRV would be NULL but a new protocol run should make us * compute a new SRV. */ tt_assert(sr_state_get_current_srv()); /* Also, make sure we did change the current. */ - tt_assert(sr_state_get_current_srv() != cur); + tt_mem_op(sr_state_get_current_srv(), OP_NE, cur, sizeof(sr_srv_t)); /* We should have our commitment alone. */ tt_int_op(digestmap_size(state->commits), ==, 1); tt_int_op(state->n_reveal_rounds, ==, 0); tt_int_op(state->n_commit_rounds, ==, 0); /* 46 here since we were at 45 just before. */ tt_u64_op(state->n_protocol_runs, ==, 46); + tor_free(cur); } /* Cleanup of SRVs. */ @@ -1099,6 +1103,7 @@ test_state_transition(void *arg) } done: + tor_free(cur); sr_state_free(); } -- cgit v1.2.3-54-g00ecf From 73fed3ee1c93b9a49ce474fdaac74fd10ec4bd55 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Fri, 1 Mar 2019 18:01:24 +0200 Subject: Add changes file --- changes/ticket29588 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket29588 (limited to 'changes') diff --git a/changes/ticket29588 b/changes/ticket29588 new file mode 100644 index 0000000000..c81bccb00d --- /dev/null +++ b/changes/ticket29588 @@ -0,0 +1,4 @@ + o Minor features (developer tools): + - Introduce a post-merge git hook script to check if we're pulling in any + changes to our git workspace management scripts from upstream. Resolves + issue 29588. -- cgit v1.2.3-54-g00ecf From 134a640a91117e1f45fba49839e6ecb10f9729a0 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sun, 10 Mar 2019 19:12:47 +0200 Subject: Remove linux-tor-prio.sh script --- changes/ticket29434 | 3 + contrib/operator-tools/linux-tor-prio.sh | 192 ------------------------------- 2 files changed, 3 insertions(+), 192 deletions(-) create mode 100644 changes/ticket29434 delete mode 100644 contrib/operator-tools/linux-tor-prio.sh (limited to 'changes') diff --git a/changes/ticket29434 b/changes/ticket29434 new file mode 100644 index 0000000000..8037044f0b --- /dev/null +++ b/changes/ticket29434 @@ -0,0 +1,3 @@ + o Removed features: + - Remove linux-tor-prio.sh script from contrib/operator-tools directory. + Resolves issue 29434. diff --git a/contrib/operator-tools/linux-tor-prio.sh b/contrib/operator-tools/linux-tor-prio.sh deleted file mode 100644 index 30ea5fc659..0000000000 --- a/contrib/operator-tools/linux-tor-prio.sh +++ /dev/null @@ -1,192 +0,0 @@ -#!/bin/bash -# Written by Marco Bonetti & Mike Perry -# Based on instructions from Dan Singletary's ADSL BW Management HOWTO: -# http://www.faqs.org/docs/Linux-HOWTO/ADSL-Bandwidth-Management-HOWTO.html -# This script is Public Domain. - -############################### README ################################# - -# This script provides prioritization of Tor traffic below other -# traffic on a Linux server. It has two modes of operation: UID based -# and IP based. - -# UID BASED PRIORITIZATION -# -# The UID based method requires that Tor be launched from -# a specific user ID. The "User" Tor config setting is -# insufficient, as it sets the UID after the socket is created. -# Here is a C wrapper you can use to execute Tor and drop privs before -# it creates any sockets. -# -# Compile with: -# gcc -DUID=`id -u tor` -DGID=`id -g tor` tor_wrap.c -o tor_wrap -# -# #include -# int main(int argc, char **argv) { -# if(initgroups("tor", GID) == -1) { perror("initgroups"); return 1; } -# if(setresgid(GID, GID, GID) == -1) { perror("setresgid"); return 1; } -# if(setresuid(UID, UID, UID) == -1) { perror("setresuid"); return 1; } -# execl("/bin/tor", "/bin/tor", "-f", "/etc/tor/torrc", NULL); -# perror("execl"); return 1; -# } - -# IP BASED PRIORITIZATION -# -# The IP setting requires that a separate IP address be dedicated to Tor. -# Your Torrc should be set to bind to this IP for "OutboundBindAddress", -# "ListenAddress", and "Address". - -# GENERAL USAGE -# -# You should also tune the individual connection rate parameters below -# to your individual connection. In particular, you should leave *some* -# minimum amount of bandwidth for Tor, so that Tor users are not -# completely choked out when you use your server's bandwidth. 30% is -# probably a reasonable choice. More is better of course. -# -# To start the shaping, run it as: -# ./linux-tor-prio.sh -# -# To get status information (useful to verify packets are getting marked -# and prioritized), run: -# ./linux-tor-prio.sh status -# -# And to stop prioritization: -# ./linux-tor-prio.sh stop -# -######################################################################## - -# BEGIN USER TUNABLE PARAMETERS - -DEV=eth0 - -# NOTE! You must START Tor under this UID. Using the Tor User -# config setting is NOT sufficient. See above. -TOR_UID=$(id -u tor) - -# If the UID mechanism doesn't work for you, you can set this parameter -# instead. If set, it will take precedence over the UID setting. Note that -# you need multiple IPs with one specifically devoted to Tor for this to -# work. -#TOR_IP="42.42.42.42" - -# Average ping to most places on the net, milliseconds -RTT_LATENCY=40 - -# RATE_UP must be less than your connection's upload capacity in -# kbits/sec. If it is larger, then the bottleneck will be at your -# router's queue, which you do not control. This will cause congestion -# and a revert to normal TCP fairness no matter what the queing -# priority is. -RATE_UP=5000 - -# RATE_UP_TOR is the minimum speed your Tor connections will have in -# kbits/sec. They will have at least this much bandwidth for upload. -# In general, you probably shouldn't set this too low, or else Tor -# users who use your node will be completely choked out whenever your -# machine does any other network activity. That is not very fun. -RATE_UP_TOR=1500 - -# RATE_UP_TOR_CEIL is the maximum rate allowed for all Tor traffic in -# kbits/sec. -RATE_UP_TOR_CEIL=5000 - -CHAIN=OUTPUT -#CHAIN=PREROUTING -#CHAIN=POSTROUTING - -MTU=1500 -AVG_PKT=900 # should be more like 600 for non-exit nodes - -# END USER TUNABLE PARAMETERS - - - -# The queue size should be no larger than your bandwidth-delay -# product. This is RT latency*bandwidth/MTU/2 - -BDP=$(expr $RTT_LATENCY \* $RATE_UP / $AVG_PKT) - -# Further research indicates that the BDP calculations should use -# RTT/sqrt(n) where n is the expected number of active connections.. - -BDP=$(expr $BDP / 4) - -if [ "$1" = "status" ] -then - echo "[qdisc]" - tc -s qdisc show dev $DEV - tc -s qdisc show dev imq0 - echo "[class]" - tc -s class show dev $DEV - tc -s class show dev imq0 - echo "[filter]" - tc -s filter show dev $DEV - tc -s filter show dev imq0 - echo "[iptables]" - iptables -t mangle -L TORSHAPER-OUT -v -x 2> /dev/null - exit -fi - - -# Reset everything to a known state (cleared) -tc qdisc del dev $DEV root 2> /dev/null > /dev/null -tc qdisc del dev imq0 root 2> /dev/null > /dev/null -iptables -t mangle -D POSTROUTING -o $DEV -j TORSHAPER-OUT 2> /dev/null > /dev/null -iptables -t mangle -D PREROUTING -o $DEV -j TORSHAPER-OUT 2> /dev/null > /dev/null -iptables -t mangle -D OUTPUT -o $DEV -j TORSHAPER-OUT 2> /dev/null > /dev/null -iptables -t mangle -F TORSHAPER-OUT 2> /dev/null > /dev/null -iptables -t mangle -X TORSHAPER-OUT 2> /dev/null > /dev/null -ip link set imq0 down 2> /dev/null > /dev/null -rmmod imq 2> /dev/null > /dev/null - -if [ "$1" = "stop" ] -then - echo "Shaping removed on $DEV." - exit -fi - -# Outbound Shaping (limits total bandwidth to RATE_UP) - -ip link set dev $DEV qlen $BDP - -# Add HTB root qdisc, default is high prio -tc qdisc add dev $DEV root handle 1: htb default 20 - -# Add main rate limit class -tc class add dev $DEV parent 1: classid 1:1 htb rate ${RATE_UP}kbit - -# Create the two classes, giving Tor at least RATE_UP_TOR kbit and capping -# total upstream at RATE_UP so the queue is under our control. -tc class add dev $DEV parent 1:1 classid 1:20 htb rate $(expr $RATE_UP - $RATE_UP_TOR)kbit ceil ${RATE_UP}kbit prio 0 -tc class add dev $DEV parent 1:1 classid 1:21 htb rate $[$RATE_UP_TOR]kbit ceil ${RATE_UP_TOR_CEIL}kbit prio 10 - -# Start up pfifo -tc qdisc add dev $DEV parent 1:20 handle 20: pfifo limit $BDP -tc qdisc add dev $DEV parent 1:21 handle 21: pfifo limit $BDP - -# filter traffic into classes by fwmark -tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 20 fw flowid 1:20 -tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 21 fw flowid 1:21 - -# add TORSHAPER-OUT chain to the mangle table in iptables -iptables -t mangle -N TORSHAPER-OUT -iptables -t mangle -I $CHAIN -o $DEV -j TORSHAPER-OUT - - -# Set firewall marks -# Low priority to Tor -if [ ""$TOR_IP == "" ] -then - echo "Using UID-based QoS. UID $TOR_UID marked as low priority." - iptables -t mangle -A TORSHAPER-OUT -m owner --uid-owner $TOR_UID -j MARK --set-mark 21 -else - echo "Using IP-based QoS. $TOR_IP marked as low priority." - iptables -t mangle -A TORSHAPER-OUT -s $TOR_IP -j MARK --set-mark 21 -fi - -# High prio for everything else -iptables -t mangle -A TORSHAPER-OUT -m mark --mark 0 -j MARK --set-mark 20 - -echo "Outbound shaping added to $DEV. Rate for Tor upload at least: ${RATE_UP_TOR}Kbyte/sec." - -- cgit v1.2.3-54-g00ecf From bb98bc8562c59c0357e8911fa8952ed5ee20206d Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 23 Aug 2018 19:21:26 +1000 Subject: hs: abolish hs_desc_link_specifier_t The previous commits for 23576 confused hs_desc_link_specifier_t and link_specifier_t. Removing hs_desc_link_specifier_t fixes this confusion. Fixes bug 22781; bugfix on 0.3.2.1-alpha. --- changes/bug22781 | 4 + src/feature/hs/hs_cell.c | 9 ++- src/feature/hs/hs_client.c | 21 ++--- src/feature/hs/hs_common.c | 39 +++++++++ src/feature/hs/hs_common.h | 2 + src/feature/hs/hs_descriptor.c | 178 ++++------------------------------------- src/feature/hs/hs_descriptor.h | 29 +------ src/feature/hs/hs_intropoint.c | 4 +- src/feature/hs/hs_service.c | 50 ++++++------ src/test/hs_test_helpers.c | 85 ++++++++++++++------ src/test/test_hs_client.c | 4 + src/test/test_hs_descriptor.c | 111 ------------------------- src/test/test_hs_service.c | 20 ++--- 13 files changed, 175 insertions(+), 381 deletions(-) create mode 100644 changes/bug22781 (limited to 'changes') diff --git a/changes/bug22781 b/changes/bug22781 new file mode 100644 index 0000000000..5606dfa5e2 --- /dev/null +++ b/changes/bug22781 @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Replace hs_desc_link_specifier_t with link_specifier_t, + and remove all hs_desc_link_specifier_t-specific code. + Fixes bug 22781; bugfix on 0.3.2.1-alpha. diff --git a/src/feature/hs/hs_cell.c b/src/feature/hs/hs_cell.c index 597982b34e..e24520da47 100644 --- a/src/feature/hs/hs_cell.c +++ b/src/feature/hs/hs_cell.c @@ -756,7 +756,14 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, idx < trn_cell_introduce_encrypted_get_nspec(enc_cell); idx++) { link_specifier_t *lspec = trn_cell_introduce_encrypted_get_nspecs(enc_cell, idx); - smartlist_add(data->link_specifiers, hs_link_specifier_dup(lspec)); + if (BUG(!lspec)) { + goto done; + } + link_specifier_t *lspec_dup = hs_link_specifier_dup(lspec); + if (BUG(!lspec_dup)) { + goto done; + } + smartlist_add(data->link_specifiers, lspec_dup); } /* Success. */ diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c index d4eee50bb7..9d0dee7124 100644 --- a/src/feature/hs/hs_client.c +++ b/src/feature/hs/hs_client.c @@ -528,13 +528,15 @@ find_desc_intro_point_by_legacy_id(const char *legacy_id, SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points, hs_desc_intro_point_t *, ip) { SMARTLIST_FOREACH_BEGIN(ip->link_specifiers, - const hs_desc_link_specifier_t *, lspec) { + const link_specifier_t *, lspec) { /* Not all tor node have an ed25519 identity key so we still rely on the * legacy identity digest. */ - if (lspec->type != LS_LEGACY_ID) { + if (link_specifier_get_ls_type(lspec) != LS_LEGACY_ID) { continue; } - if (fast_memneq(legacy_id, lspec->u.legacy_id, DIGEST_LEN)) { + if (fast_memneq(legacy_id, + link_specifier_getconstarray_un_legacy_id(lspec), + DIGEST_LEN)) { break; } /* Found it. */ @@ -753,24 +755,13 @@ STATIC extend_info_t * desc_intro_point_to_extend_info(const hs_desc_intro_point_t *ip) { extend_info_t *ei; - smartlist_t *lspecs = smartlist_new(); tor_assert(ip); - /* We first encode the descriptor link specifiers into the binary - * representation which is a trunnel object. */ - SMARTLIST_FOREACH_BEGIN(ip->link_specifiers, - const hs_desc_link_specifier_t *, desc_lspec) { - link_specifier_t *lspec = hs_desc_lspec_to_trunnel(desc_lspec); - smartlist_add(lspecs, lspec); - } SMARTLIST_FOREACH_END(desc_lspec); - /* Explicitly put the direct connection option to 0 because this is client * side and there is no such thing as a non anonymous client. */ - ei = hs_get_extend_info_from_lspecs(lspecs, &ip->onion_key, 0); + ei = hs_get_extend_info_from_lspecs(ip->link_specifiers, &ip->onion_key, 0); - SMARTLIST_FOREACH(lspecs, link_specifier_t *, ls, link_specifier_free(ls)); - smartlist_free(lspecs); return ei; } diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c index 5d8f54230f..a1dc0a6290 100644 --- a/src/feature/hs/hs_common.c +++ b/src/feature/hs/hs_common.c @@ -1843,3 +1843,42 @@ hs_inc_rdv_stream_counter(origin_circuit_t *circ) tor_assert_nonfatal_unreached(); } } + +/* Return a newly allocated link specifier object that is a copy of dst. */ +link_specifier_t * +link_specifier_dup(const link_specifier_t *src) +{ + link_specifier_t *dup = NULL; + uint8_t *buf = NULL; + + if (BUG(!src)) { + goto err; + } + + ssize_t encoded_len_alloc = link_specifier_encoded_len(src); + if (BUG(encoded_len_alloc < 0)) { + goto err; + } + + buf = tor_malloc_zero(encoded_len_alloc); + ssize_t encoded_len_data = link_specifier_encode(buf, + encoded_len_alloc, + src); + if (BUG(encoded_len_data < 0)) { + goto err; + } + + ssize_t parsed_len = link_specifier_parse(&dup, buf, encoded_len_alloc); + if (BUG(parsed_len < 0)) { + goto err; + } + + goto done; + + err: + dup = NULL; + + done: + tor_free(buf); + return dup; +} diff --git a/src/feature/hs/hs_common.h b/src/feature/hs/hs_common.h index a44505930a..544e63e596 100644 --- a/src/feature/hs/hs_common.h +++ b/src/feature/hs/hs_common.h @@ -262,6 +262,8 @@ extend_info_t *hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, const struct curve25519_public_key_t *onion_key, int direct_conn); +link_specifier_t *link_specifier_dup(const link_specifier_t *src); + #ifdef HS_COMMON_PRIVATE STATIC void get_disaster_srv(uint64_t time_period_num, uint8_t *srv_out); diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c index b09d50e010..8f7bdf86ef 100644 --- a/src/feature/hs/hs_descriptor.c +++ b/src/feature/hs/hs_descriptor.c @@ -324,12 +324,11 @@ encode_link_specifiers(const smartlist_t *specs) link_specifier_list_set_n_spec(lslist, smartlist_len(specs)); - SMARTLIST_FOREACH_BEGIN(specs, const hs_desc_link_specifier_t *, + SMARTLIST_FOREACH_BEGIN(specs, const link_specifier_t *, spec) { - link_specifier_t *ls = hs_desc_lspec_to_trunnel(spec); - if (ls) { - link_specifier_list_add_spec(lslist, ls); - } + link_specifier_t *ls = link_specifier_dup(spec); + tor_assert(ls); + link_specifier_list_add_spec(lslist, ls); } SMARTLIST_FOREACH_END(spec); { @@ -1190,52 +1189,22 @@ decode_link_specifiers(const char *encoded) results = smartlist_new(); for (i = 0; i < link_specifier_list_getlen_spec(specs); i++) { - hs_desc_link_specifier_t *hs_spec; link_specifier_t *ls = link_specifier_list_get_spec(specs, i); - tor_assert(ls); - - hs_spec = tor_malloc_zero(sizeof(*hs_spec)); - hs_spec->type = link_specifier_get_ls_type(ls); - switch (hs_spec->type) { - case LS_IPV4: - tor_addr_from_ipv4h(&hs_spec->u.ap.addr, - link_specifier_get_un_ipv4_addr(ls)); - hs_spec->u.ap.port = link_specifier_get_un_ipv4_port(ls); - break; - case LS_IPV6: - tor_addr_from_ipv6_bytes(&hs_spec->u.ap.addr, (const char *) - link_specifier_getarray_un_ipv6_addr(ls)); - hs_spec->u.ap.port = link_specifier_get_un_ipv6_port(ls); - break; - case LS_LEGACY_ID: - /* Both are known at compile time so let's make sure they are the same - * else we can copy memory out of bound. */ - tor_assert(link_specifier_getlen_un_legacy_id(ls) == - sizeof(hs_spec->u.legacy_id)); - memcpy(hs_spec->u.legacy_id, link_specifier_getarray_un_legacy_id(ls), - sizeof(hs_spec->u.legacy_id)); - break; - case LS_ED25519_ID: - /* Both are known at compile time so let's make sure they are the same - * else we can copy memory out of bound. */ - tor_assert(link_specifier_getlen_un_ed25519_id(ls) == - sizeof(hs_spec->u.ed25519_id)); - memcpy(hs_spec->u.ed25519_id, - link_specifier_getconstarray_un_ed25519_id(ls), - sizeof(hs_spec->u.ed25519_id)); - break; - default: - tor_free(hs_spec); + if (BUG(!ls)) { goto err; } - - smartlist_add(results, hs_spec); + link_specifier_t *ls_dup = link_specifier_dup(ls); + if (BUG(!ls_dup)) { + goto err; + } + smartlist_add(results, ls_dup); } goto done; err: if (results) { - SMARTLIST_FOREACH(results, hs_desc_link_specifier_t *, s, tor_free(s)); + SMARTLIST_FOREACH(results, link_specifier_t *, s, + link_specifier_free(s)); smartlist_free(results); results = NULL; } @@ -2878,8 +2847,8 @@ hs_desc_intro_point_free_(hs_desc_intro_point_t *ip) return; } if (ip->link_specifiers) { - SMARTLIST_FOREACH(ip->link_specifiers, hs_desc_link_specifier_t *, - ls, hs_desc_link_specifier_free(ls)); + SMARTLIST_FOREACH(ip->link_specifiers, link_specifier_t *, + ls, link_specifier_free(ls)); smartlist_free(ip->link_specifiers); } tor_cert_free(ip->auth_key_cert); @@ -2972,69 +2941,6 @@ hs_desc_authorized_client_free_(hs_desc_authorized_client_t *client) tor_free(client); } -/* Free the given descriptor link specifier. */ -void -hs_desc_link_specifier_free_(hs_desc_link_specifier_t *ls) -{ - if (ls == NULL) { - return; - } - tor_free(ls); -} - -/* Return a newly allocated descriptor link specifier using the given extend - * info and requested type. Return NULL on error. */ -hs_desc_link_specifier_t * -hs_desc_link_specifier_new(const extend_info_t *info, uint8_t type) -{ - hs_desc_link_specifier_t *ls = NULL; - - tor_assert(info); - - ls = tor_malloc_zero(sizeof(*ls)); - ls->type = type; - switch (ls->type) { - case LS_IPV4: - if (info->addr.family != AF_INET) { - goto err; - } - tor_addr_copy(&ls->u.ap.addr, &info->addr); - ls->u.ap.port = info->port; - break; - case LS_IPV6: - if (info->addr.family != AF_INET6) { - goto err; - } - tor_addr_copy(&ls->u.ap.addr, &info->addr); - ls->u.ap.port = info->port; - break; - case LS_LEGACY_ID: - /* Bug out if the identity digest is not set */ - if (BUG(tor_mem_is_zero(info->identity_digest, - sizeof(info->identity_digest)))) { - goto err; - } - memcpy(ls->u.legacy_id, info->identity_digest, sizeof(ls->u.legacy_id)); - break; - case LS_ED25519_ID: - /* ed25519 keys are optional for intro points */ - if (ed25519_public_key_is_zero(&info->ed_identity)) { - goto err; - } - memcpy(ls->u.ed25519_id, info->ed_identity.pubkey, - sizeof(ls->u.ed25519_id)); - break; - default: - /* Unknown type is code flow error. */ - tor_assert(0); - } - - return ls; - err: - tor_free(ls); - return NULL; -} - /* From the given descriptor, remove and free every introduction point. */ void hs_descriptor_clear_intro_points(hs_descriptor_t *desc) @@ -3050,59 +2956,3 @@ hs_descriptor_clear_intro_points(hs_descriptor_t *desc) smartlist_clear(ips); } } - -/* From a descriptor link specifier object spec, returned a newly allocated - * link specifier object that is the encoded representation of spec. Return - * NULL on error. */ -link_specifier_t * -hs_desc_lspec_to_trunnel(const hs_desc_link_specifier_t *spec) -{ - tor_assert(spec); - - link_specifier_t *ls = link_specifier_new(); - link_specifier_set_ls_type(ls, spec->type); - - switch (spec->type) { - case LS_IPV4: - link_specifier_set_un_ipv4_addr(ls, - tor_addr_to_ipv4h(&spec->u.ap.addr)); - link_specifier_set_un_ipv4_port(ls, spec->u.ap.port); - /* Four bytes IPv4 and two bytes port. */ - link_specifier_set_ls_len(ls, sizeof(spec->u.ap.addr.addr.in_addr) + - sizeof(spec->u.ap.port)); - break; - case LS_IPV6: - { - size_t addr_len = link_specifier_getlen_un_ipv6_addr(ls); - const uint8_t *in6_addr = tor_addr_to_in6_addr8(&spec->u.ap.addr); - uint8_t *ipv6_array = link_specifier_getarray_un_ipv6_addr(ls); - memcpy(ipv6_array, in6_addr, addr_len); - link_specifier_set_un_ipv6_port(ls, spec->u.ap.port); - /* Sixteen bytes IPv6 and two bytes port. */ - link_specifier_set_ls_len(ls, addr_len + sizeof(spec->u.ap.port)); - break; - } - case LS_LEGACY_ID: - { - size_t legacy_id_len = link_specifier_getlen_un_legacy_id(ls); - uint8_t *legacy_id_array = link_specifier_getarray_un_legacy_id(ls); - memcpy(legacy_id_array, spec->u.legacy_id, legacy_id_len); - link_specifier_set_ls_len(ls, legacy_id_len); - break; - } - case LS_ED25519_ID: - { - size_t ed25519_id_len = link_specifier_getlen_un_ed25519_id(ls); - uint8_t *ed25519_id_array = link_specifier_getarray_un_ed25519_id(ls); - memcpy(ed25519_id_array, spec->u.ed25519_id, ed25519_id_len); - link_specifier_set_ls_len(ls, ed25519_id_len); - break; - } - default: - tor_assert_nonfatal_unreached(); - link_specifier_free(ls); - ls = NULL; - } - - return ls; -} diff --git a/src/feature/hs/hs_descriptor.h b/src/feature/hs/hs_descriptor.h index 04a8e16d63..dbe0cb1c94 100644 --- a/src/feature/hs/hs_descriptor.h +++ b/src/feature/hs/hs_descriptor.h @@ -69,28 +69,10 @@ typedef enum { HS_DESC_AUTH_ED25519 = 1 } hs_desc_auth_type_t; -/* Link specifier object that contains information on how to extend to the - * relay that is the address, port and handshake type. */ -typedef struct hs_desc_link_specifier_t { - /* Indicate the type of link specifier. See trunnel ed25519_cert - * specification. */ - uint8_t type; - - /* It must be one of these types, can't be more than one. */ - union { - /* IP address and port of the relay use to extend. */ - tor_addr_port_t ap; - /* Legacy identity. A 20-byte SHA1 identity fingerprint. */ - uint8_t legacy_id[DIGEST_LEN]; - /* ed25519 identity. A 32-byte key. */ - uint8_t ed25519_id[ED25519_PUBKEY_LEN]; - } u; -} hs_desc_link_specifier_t; - /* Introduction point information located in a descriptor. */ typedef struct hs_desc_intro_point_t { /* Link specifier(s) which details how to extend to the relay. This list - * contains hs_desc_link_specifier_t object. It MUST have at least one. */ + * contains link_specifier_t objects. It MUST have at least one. */ smartlist_t *link_specifiers; /* Onion key of the introduction point used to extend to it for the ntor @@ -261,12 +243,6 @@ void hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc); #define hs_desc_encrypted_data_free(desc) \ FREE_AND_NULL(hs_desc_encrypted_data_t, hs_desc_encrypted_data_free_, (desc)) -void hs_desc_link_specifier_free_(hs_desc_link_specifier_t *ls); -#define hs_desc_link_specifier_free(ls) \ - FREE_AND_NULL(hs_desc_link_specifier_t, hs_desc_link_specifier_free_, (ls)) - -hs_desc_link_specifier_t *hs_desc_link_specifier_new( - const extend_info_t *info, uint8_t type); void hs_descriptor_clear_intro_points(hs_descriptor_t *desc); MOCK_DECL(int, @@ -299,9 +275,6 @@ void hs_desc_authorized_client_free_(hs_desc_authorized_client_t *client); FREE_AND_NULL(hs_desc_authorized_client_t, \ hs_desc_authorized_client_free_, (client)) -link_specifier_t *hs_desc_lspec_to_trunnel( - const hs_desc_link_specifier_t *spec); - hs_desc_authorized_client_t *hs_desc_build_fake_authorized_client(void); void hs_desc_build_authorized_client(const uint8_t *subcredential, const curve25519_public_key_t * diff --git a/src/feature/hs/hs_intropoint.c b/src/feature/hs/hs_intropoint.c index b28a5c2b80..c9cd3a0419 100644 --- a/src/feature/hs/hs_intropoint.c +++ b/src/feature/hs/hs_intropoint.c @@ -601,8 +601,8 @@ hs_intropoint_clear(hs_intropoint_t *ip) return; } tor_cert_free(ip->auth_key_cert); - SMARTLIST_FOREACH(ip->link_specifiers, hs_desc_link_specifier_t *, ls, - hs_desc_link_specifier_free(ls)); + SMARTLIST_FOREACH(ip->link_specifiers, link_specifier_t *, ls, + link_specifier_free(ls)); smartlist_free(ip->link_specifiers); memset(ip, 0, sizeof(hs_intropoint_t)); } diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index 6e4da8856a..8cd863eef4 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -280,9 +280,10 @@ describe_intro_point(const hs_service_intro_point_t *ip) const char *legacy_id = NULL; SMARTLIST_FOREACH_BEGIN(ip->base.link_specifiers, - const hs_desc_link_specifier_t *, lspec) { - if (lspec->type == LS_LEGACY_ID) { - legacy_id = (const char *) lspec->u.legacy_id; + const link_specifier_t *, lspec) { + if (link_specifier_get_ls_type(lspec) == LS_LEGACY_ID) { + legacy_id = (const char *) + link_specifier_getconstarray_un_legacy_id(lspec); break; } } SMARTLIST_FOREACH_END(lspec); @@ -623,16 +624,16 @@ get_objects_from_ident(const hs_ident_circuit_t *ident, * encountered in the link specifier list. Return NULL if it can't be found. * * The caller does NOT have ownership of the object, the intro point does. */ -static hs_desc_link_specifier_t * +static link_specifier_t * get_link_spec_by_type(const hs_service_intro_point_t *ip, uint8_t type) { - hs_desc_link_specifier_t *lnk_spec = NULL; + link_specifier_t *lnk_spec = NULL; tor_assert(ip); SMARTLIST_FOREACH_BEGIN(ip->base.link_specifiers, - hs_desc_link_specifier_t *, ls) { - if (ls->type == type) { + link_specifier_t *, ls) { + if (link_specifier_get_ls_type(ls) == type) { lnk_spec = ls; goto end; } @@ -648,7 +649,7 @@ get_link_spec_by_type(const hs_service_intro_point_t *ip, uint8_t type) STATIC const node_t * get_node_from_intro_point(const hs_service_intro_point_t *ip) { - const hs_desc_link_specifier_t *ls; + const link_specifier_t *ls; tor_assert(ip); @@ -657,7 +658,8 @@ get_node_from_intro_point(const hs_service_intro_point_t *ip) return NULL; } /* XXX In the future, we want to only use the ed25519 ID (#22173). */ - return node_get_by_id((const char *) ls->u.legacy_id); + return node_get_by_id( + (const char *) link_specifier_getconstarray_un_legacy_id(ls)); } /* Given a service intro point, return the extend_info_t for it. This can @@ -1523,7 +1525,7 @@ remember_failing_intro_point(const hs_service_intro_point_t *ip, hs_service_descriptor_t *desc, time_t now) { time_t *time_of_failure, *prev_ptr; - const hs_desc_link_specifier_t *legacy_ls; + const link_specifier_t *legacy_ls; tor_assert(ip); tor_assert(desc); @@ -1532,22 +1534,13 @@ remember_failing_intro_point(const hs_service_intro_point_t *ip, *time_of_failure = now; legacy_ls = get_link_spec_by_type(ip, LS_LEGACY_ID); tor_assert(legacy_ls); - prev_ptr = digestmap_set(desc->intro_points.failed_id, - (const char *) legacy_ls->u.legacy_id, - time_of_failure); + prev_ptr = digestmap_set( + desc->intro_points.failed_id, + (const char *) link_specifier_getconstarray_un_legacy_id(legacy_ls), + time_of_failure); tor_free(prev_ptr); } -/* Copy the descriptor link specifier object from src to dst. */ -static void -link_specifier_copy(hs_desc_link_specifier_t *dst, - const hs_desc_link_specifier_t *src) -{ - tor_assert(dst); - tor_assert(src); - memcpy(dst, src, sizeof(hs_desc_link_specifier_t)); -} - /* Using a given descriptor signing keypair signing_kp, a service intro point * object ip and the time now, setup the content of an already allocated * descriptor intro desc_ip. @@ -1582,9 +1575,14 @@ setup_desc_intro_point(const ed25519_keypair_t *signing_kp, /* Copy link specifier(s). */ SMARTLIST_FOREACH_BEGIN(ip->base.link_specifiers, - const hs_desc_link_specifier_t *, ls) { - hs_desc_link_specifier_t *copy = tor_malloc_zero(sizeof(*copy)); - link_specifier_copy(copy, ls); + const link_specifier_t *, ls) { + if (BUG(!ls)) { + goto done; + } + link_specifier_t *copy = link_specifier_dup(ls); + if (BUG(!copy)) { + goto done; + } smartlist_add(desc_ip->link_specifiers, copy); } SMARTLIST_FOREACH_END(ls); diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c index f2ae8398df..1c47c7d7d4 100644 --- a/src/test/hs_test_helpers.c +++ b/src/test/hs_test_helpers.c @@ -21,22 +21,33 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now, /* For a usable intro point we need at least two link specifiers: One legacy * keyid and one ipv4 */ { - hs_desc_link_specifier_t *ls_legacy = tor_malloc_zero(sizeof(*ls_legacy)); - hs_desc_link_specifier_t *ls_v4 = tor_malloc_zero(sizeof(*ls_v4)); - ls_legacy->type = LS_LEGACY_ID; - memcpy(ls_legacy->u.legacy_id, "0299F268FCA9D55CD157976D39AE92B4B455B3A8", - DIGEST_LEN); - ls_v4->u.ap.port = 9001; - int family = tor_addr_parse(&ls_v4->u.ap.addr, addr); + tor_addr_t a; + tor_addr_make_unspec(&a); + link_specifier_t *ls_legacy = link_specifier_new(); + /* TODO: this name is wrong: it is sometimes an IPv6 address */ + link_specifier_t *ls_v4 = link_specifier_new(); + link_specifier_set_ls_type(ls_legacy, LS_LEGACY_ID); + memcpy(link_specifier_getarray_un_legacy_id(ls_legacy), + /* TODO: this code is wrong: it copies hex into binary */ + "0299F268FCA9D55CD157976D39AE92B4B455B3A8", + link_specifier_getlen_un_legacy_id(ls_legacy)); + int family = tor_addr_parse(&a, addr); switch (family) { case AF_INET: - ls_v4->type = LS_IPV4; + link_specifier_set_ls_type(ls_v4, LS_IPV4); + link_specifier_set_un_ipv4_addr(ls_v4, tor_addr_to_ipv4h(&a)); + link_specifier_set_un_ipv4_port(ls_v4, 9001); break; case AF_INET6: - ls_v4->type = LS_IPV6; + link_specifier_set_ls_type(ls_v4, LS_IPV6); + memcpy(link_specifier_getarray_un_ipv6_addr(ls_v4), + tor_addr_to_in6_addr8(&a), + link_specifier_getlen_un_ipv6_addr(ls_v4)); + link_specifier_set_un_ipv6_port(ls_v4, 9001); break; default: /* Stop the test, not suppose to have an error. */ + /* TODO: just tt_fail(), because this code is confusing */ tt_int_op(family, OP_EQ, AF_INET); } smartlist_add(ip->link_specifiers, ls_legacy); @@ -153,8 +164,11 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip, /* Add four intro points. */ smartlist_add(desc->encrypted_data.intro_points, hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0)); +/* IPv6-only introduction points are not supported yet, see #23588 */ +#if 0 smartlist_add(desc->encrypted_data.intro_points, hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0)); +#endif smartlist_add(desc->encrypted_data.intro_points, hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1)); smartlist_add(desc->encrypted_data.intro_points, @@ -202,7 +216,6 @@ void hs_helper_desc_equal(const hs_descriptor_t *desc1, const hs_descriptor_t *desc2) { - char *addr1 = NULL, *addr2 = NULL; /* Plaintext data section. */ tt_int_op(desc1->plaintext_data.version, OP_EQ, desc2->plaintext_data.version); @@ -291,35 +304,57 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1, tt_int_op(smartlist_len(ip1->link_specifiers), ==, smartlist_len(ip2->link_specifiers)); for (int j = 0; j < smartlist_len(ip1->link_specifiers); j++) { - hs_desc_link_specifier_t *ls1 = smartlist_get(ip1->link_specifiers, j), - *ls2 = smartlist_get(ip2->link_specifiers, j); - tt_int_op(ls1->type, ==, ls2->type); - switch (ls1->type) { + link_specifier_t *ls1 = smartlist_get(ip1->link_specifiers, j), + *ls2 = smartlist_get(ip2->link_specifiers, j); + tt_int_op(link_specifier_get_ls_type(ls1), ==, + link_specifier_get_ls_type(ls2)); + switch (link_specifier_get_ls_type(ls1)) { case LS_IPV4: + { + uint32_t addr1 = link_specifier_get_un_ipv4_addr(ls1); + uint32_t addr2 = link_specifier_get_un_ipv4_addr(ls2); + tt_int_op(addr1, OP_EQ, addr2); + uint16_t port1 = link_specifier_get_un_ipv4_port(ls1); + uint16_t port2 = link_specifier_get_un_ipv4_port(ls2); + tt_int_op(port1, ==, port2); + } + break; case LS_IPV6: { - addr1 = tor_addr_to_str_dup(&ls1->u.ap.addr); - addr2 = tor_addr_to_str_dup(&ls2->u.ap.addr); - tt_str_op(addr1, OP_EQ, addr2); - tor_free(addr1); - tor_free(addr2); - tt_int_op(ls1->u.ap.port, ==, ls2->u.ap.port); + const uint8_t *addr1 = + link_specifier_getconstarray_un_ipv6_addr(ls1); + const uint8_t *addr2 = + link_specifier_getconstarray_un_ipv6_addr(ls2); + tt_int_op(link_specifier_getlen_un_ipv6_addr(ls1), OP_EQ, + link_specifier_getlen_un_ipv6_addr(ls2)); + tt_mem_op(addr1, OP_EQ, addr2, + link_specifier_getlen_un_ipv6_addr(ls1)); + uint16_t port1 = link_specifier_get_un_ipv6_port(ls1); + uint16_t port2 = link_specifier_get_un_ipv6_port(ls2); + tt_int_op(port1, ==, port2); } break; case LS_LEGACY_ID: - tt_mem_op(ls1->u.legacy_id, OP_EQ, ls2->u.legacy_id, - sizeof(ls1->u.legacy_id)); + { + const uint8_t *id1 = + link_specifier_getconstarray_un_legacy_id(ls1); + const uint8_t *id2 = + link_specifier_getconstarray_un_legacy_id(ls2); + tt_int_op(link_specifier_getlen_un_legacy_id(ls1), OP_EQ, + link_specifier_getlen_un_legacy_id(ls2)); + tt_mem_op(id1, OP_EQ, id2, + link_specifier_getlen_un_legacy_id(ls1)); + } break; default: /* Unknown type, caught it and print its value. */ - tt_int_op(ls1->type, OP_EQ, -1); + tt_int_op(link_specifier_get_ls_type(ls1), OP_EQ, -1); } } } } done: - tor_free(addr1); - tor_free(addr2); + ; } diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c index 2f2bb45581..8362b6cbda 100644 --- a/src/test/test_hs_client.c +++ b/src/test/test_hs_client.c @@ -403,6 +403,9 @@ test_client_pick_intro(void *arg) /* 2) Mark all intro points except _the chosen one_ as failed. Then query the * desc and get a random intro: check that we got _the chosen one_. */ { + /* Tell hs_get_extend_info_from_lspecs() to skip the private address check. + */ + get_options_mutable()->ExtendAllowPrivateAddresses = 1; /* Pick the chosen intro point and get its ei */ hs_desc_intro_point_t *chosen_intro_point = smartlist_get(desc->encrypted_data.intro_points, 0); @@ -476,6 +479,7 @@ test_client_pick_intro(void *arg) SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points, hs_desc_intro_point_t *, ip) { extend_info_t *intro_ei = desc_intro_point_to_extend_info(ip); + tt_assert(intro_ei); if (intro_ei) { const char *ptr; char ip_addr[TOR_ADDR_BUF_LEN]; diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c index de584ed47a..09c6c3e700 100644 --- a/src/test/test_hs_descriptor.c +++ b/src/test/test_hs_descriptor.c @@ -178,115 +178,6 @@ test_descriptor_padding(void *arg) return; } -static void -test_link_specifier(void *arg) -{ - ssize_t ret; - hs_desc_link_specifier_t spec; - smartlist_t *link_specifiers = smartlist_new(); - char buf[256]; - char *b64 = NULL; - link_specifier_t *ls = NULL; - - (void) arg; - - /* Always this port. */ - spec.u.ap.port = 42; - smartlist_add(link_specifiers, &spec); - - /* Test IPv4 for starter. */ - { - uint32_t ipv4; - - spec.type = LS_IPV4; - ret = tor_addr_parse(&spec.u.ap.addr, "1.2.3.4"); - tt_int_op(ret, OP_EQ, AF_INET); - b64 = encode_link_specifiers(link_specifiers); - tt_assert(b64); - - /* Decode it and validate the format. */ - ret = base64_decode(buf, sizeof(buf), b64, strlen(b64)); - tt_int_op(ret, OP_GT, 0); - /* First byte is the number of link specifier. */ - tt_int_op(get_uint8(buf), OP_EQ, 1); - ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1); - tt_int_op(ret, OP_EQ, 8); - /* Should be 2 bytes for port and 4 bytes for IPv4. */ - tt_int_op(link_specifier_get_ls_len(ls), OP_EQ, 6); - ipv4 = link_specifier_get_un_ipv4_addr(ls); - tt_int_op(tor_addr_to_ipv4h(&spec.u.ap.addr), OP_EQ, ipv4); - tt_int_op(link_specifier_get_un_ipv4_port(ls), OP_EQ, spec.u.ap.port); - - link_specifier_free(ls); - ls = NULL; - tor_free(b64); - } - - /* Test IPv6. */ - { - uint8_t ipv6[16]; - - spec.type = LS_IPV6; - ret = tor_addr_parse(&spec.u.ap.addr, "[1:2:3:4::]"); - tt_int_op(ret, OP_EQ, AF_INET6); - b64 = encode_link_specifiers(link_specifiers); - tt_assert(b64); - - /* Decode it and validate the format. */ - ret = base64_decode(buf, sizeof(buf), b64, strlen(b64)); - tt_int_op(ret, OP_GT, 0); - /* First byte is the number of link specifier. */ - tt_int_op(get_uint8(buf), OP_EQ, 1); - ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1); - tt_int_op(ret, OP_EQ, 20); - /* Should be 2 bytes for port and 16 bytes for IPv6. */ - tt_int_op(link_specifier_get_ls_len(ls), OP_EQ, 18); - for (unsigned int i = 0; i < sizeof(ipv6); i++) { - ipv6[i] = link_specifier_get_un_ipv6_addr(ls, i); - } - tt_mem_op(tor_addr_to_in6_addr8(&spec.u.ap.addr), OP_EQ, ipv6, - sizeof(ipv6)); - tt_int_op(link_specifier_get_un_ipv6_port(ls), OP_EQ, spec.u.ap.port); - - link_specifier_free(ls); - ls = NULL; - tor_free(b64); - } - - /* Test legacy. */ - { - uint8_t *id; - - spec.type = LS_LEGACY_ID; - memset(spec.u.legacy_id, 'Y', sizeof(spec.u.legacy_id)); - b64 = encode_link_specifiers(link_specifiers); - tt_assert(b64); - - /* Decode it and validate the format. */ - ret = base64_decode(buf, sizeof(buf), b64, strlen(b64)); - tt_int_op(ret, OP_GT, 0); - /* First byte is the number of link specifier. */ - tt_int_op(get_uint8(buf), OP_EQ, 1); - ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1); - /* 20 bytes digest + 1 byte type + 1 byte len. */ - tt_int_op(ret, OP_EQ, 22); - tt_int_op(link_specifier_getlen_un_legacy_id(ls), OP_EQ, DIGEST_LEN); - /* Digest length is 20 bytes. */ - tt_int_op(link_specifier_get_ls_len(ls), OP_EQ, DIGEST_LEN); - id = link_specifier_getarray_un_legacy_id(ls); - tt_mem_op(spec.u.legacy_id, OP_EQ, id, DIGEST_LEN); - - link_specifier_free(ls); - ls = NULL; - tor_free(b64); - } - - done: - link_specifier_free(ls); - tor_free(b64); - smartlist_free(link_specifiers); -} - static void test_encode_descriptor(void *arg) { @@ -932,8 +823,6 @@ struct testcase_t hs_descriptor[] = { /* Encoding tests. */ { "cert_encoding", test_cert_encoding, TT_FORK, NULL, NULL }, - { "link_specifier", test_link_specifier, TT_FORK, - NULL, NULL }, { "encode_descriptor", test_encode_descriptor, TT_FORK, NULL, NULL }, { "descriptor_padding", test_descriptor_padding, TT_FORK, diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c index e8bdcd86e2..57132e6197 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -328,17 +328,18 @@ helper_create_service_with_clients(int num_clients) static hs_service_intro_point_t * helper_create_service_ip(void) { - hs_desc_link_specifier_t *ls; + link_specifier_t *ls; hs_service_intro_point_t *ip = service_intro_point_new(NULL); tor_assert(ip); /* Add a first unused link specifier. */ - ls = tor_malloc_zero(sizeof(*ls)); - ls->type = LS_IPV4; + ls = link_specifier_new(); + link_specifier_set_ls_type(ls, LS_IPV4); smartlist_add(ip->base.link_specifiers, ls); /* Add a second link specifier used by a test. */ - ls = tor_malloc_zero(sizeof(*ls)); - ls->type = LS_LEGACY_ID; - memset(ls->u.legacy_id, 'A', sizeof(ls->u.legacy_id)); + ls = link_specifier_new(); + link_specifier_set_ls_type(ls, LS_LEGACY_ID); + memset(link_specifier_getarray_un_legacy_id(ls), 'A', + link_specifier_getlen_un_legacy_id(ls)); smartlist_add(ip->base.link_specifiers, ls); return ip; @@ -811,10 +812,11 @@ test_helper_functions(void *arg) const node_t *node = get_node_from_intro_point(ip); tt_ptr_op(node, OP_EQ, &mock_node); SMARTLIST_FOREACH_BEGIN(ip->base.link_specifiers, - hs_desc_link_specifier_t *, ls) { - if (ls->type == LS_LEGACY_ID) { + link_specifier_t *, ls) { + if (link_specifier_get_ls_type(ls) == LS_LEGACY_ID) { /* Change legacy id in link specifier which is not the mock node. */ - memset(ls->u.legacy_id, 'B', sizeof(ls->u.legacy_id)); + memset(link_specifier_getarray_un_legacy_id(ls), 'B', + link_specifier_getlen_un_legacy_id(ls)); } } SMARTLIST_FOREACH_END(ls); node = get_node_from_intro_point(ip); -- cgit v1.2.3-54-g00ecf From 257cea8876e00b18c6791f86ebe5c24bab3b72bf Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 30 Jan 2019 21:52:19 +0100 Subject: test/hs: minor hs test fixes Cleanup some bugs discovered during 23576: * stop copying the first 20 characters of a 40-character hex string to a binary fingerprint * stop putting IPv6 addresses in a variable called "ipv4" * explain why we do a duplicate tt_int_op() to deliberately fail and print a value Fixes bug 29243; bugfix on 0.3.2.1-alpha. --- changes/bug29243 | 3 +++ src/test/hs_test_helpers.c | 30 ++++++++++++++---------------- 2 files changed, 17 insertions(+), 16 deletions(-) create mode 100644 changes/bug29243 (limited to 'changes') diff --git a/changes/bug29243 b/changes/bug29243 new file mode 100644 index 0000000000..b5694f7568 --- /dev/null +++ b/changes/bug29243 @@ -0,0 +1,3 @@ + o Minor bugfixes (testing, v3 onion services): + - Fix some incorrect code in the v3 onion service unit tests. + Fixes bug 29243; bugfix on 0.3.2.1-alpha. diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c index 1c47c7d7d4..c57bdc730b 100644 --- a/src/test/hs_test_helpers.c +++ b/src/test/hs_test_helpers.c @@ -24,34 +24,32 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now, tor_addr_t a; tor_addr_make_unspec(&a); link_specifier_t *ls_legacy = link_specifier_new(); - /* TODO: this name is wrong: it is sometimes an IPv6 address */ - link_specifier_t *ls_v4 = link_specifier_new(); + link_specifier_t *ls_ip = link_specifier_new(); link_specifier_set_ls_type(ls_legacy, LS_LEGACY_ID); - memcpy(link_specifier_getarray_un_legacy_id(ls_legacy), - /* TODO: this code is wrong: it copies hex into binary */ - "0299F268FCA9D55CD157976D39AE92B4B455B3A8", + memset(link_specifier_getarray_un_legacy_id(ls_legacy), 'C', link_specifier_getlen_un_legacy_id(ls_legacy)); int family = tor_addr_parse(&a, addr); switch (family) { case AF_INET: - link_specifier_set_ls_type(ls_v4, LS_IPV4); - link_specifier_set_un_ipv4_addr(ls_v4, tor_addr_to_ipv4h(&a)); - link_specifier_set_un_ipv4_port(ls_v4, 9001); + link_specifier_set_ls_type(ls_ip, LS_IPV4); + link_specifier_set_un_ipv4_addr(ls_ip, tor_addr_to_ipv4h(&a)); + link_specifier_set_un_ipv4_port(ls_ip, 9001); break; case AF_INET6: - link_specifier_set_ls_type(ls_v4, LS_IPV6); - memcpy(link_specifier_getarray_un_ipv6_addr(ls_v4), + link_specifier_set_ls_type(ls_ip, LS_IPV6); + memcpy(link_specifier_getarray_un_ipv6_addr(ls_ip), tor_addr_to_in6_addr8(&a), - link_specifier_getlen_un_ipv6_addr(ls_v4)); - link_specifier_set_un_ipv6_port(ls_v4, 9001); + link_specifier_getlen_un_ipv6_addr(ls_ip)); + link_specifier_set_un_ipv6_port(ls_ip, 9001); break; default: - /* Stop the test, not suppose to have an error. */ - /* TODO: just tt_fail(), because this code is confusing */ - tt_int_op(family, OP_EQ, AF_INET); + /* Stop the test, not supposed to have an error. + * Compare with -1 to show the actual family. + */ + tt_int_op(family, OP_EQ, -1); } smartlist_add(ip->link_specifiers, ls_legacy); - smartlist_add(ip->link_specifiers, ls_v4); + smartlist_add(ip->link_specifiers, ls_ip); } ret = ed25519_keypair_generate(&auth_kp, 0); -- cgit v1.2.3-54-g00ecf From ec2a2a6b7afd5f37cfdc147eb12fb0c64d9ae0cf Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 12 Mar 2019 20:11:51 +0200 Subject: Fix #28525 changes file that is breaking CI. --- changes/bug28525 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'changes') diff --git a/changes/bug28525 b/changes/bug28525 index 392a9265e5..988ffb2192 100644 --- a/changes/bug28525 +++ b/changes/bug28525 @@ -1,8 +1,7 @@ - o Minor bugfixes (address selection): + o Minor features (address selection): - Make Tor aware of the RFC 6598 (Carrier Grade NAT) IP range, which is the subnet 100.64.0.0/10. This is deployed by many ISPs as an alternative to RFC 1918 that does not break existing internal networks. This patch fixes security issues caused by RFC 6518 by blocking control ports on these addresses and warns users if client ports or ExtORPorts are listening on - a RFC 6598 address. Fixes bug 28525; bugfix on 0.4.1.1-alpha. Patch by - Neel Chauhan. + a RFC 6598 address. Closes ticket 28525. Patch by Neel Chauhan. -- cgit v1.2.3-54-g00ecf From 95209be861738d15fdb8d3f8da9a6164ed5f3903 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 12 Mar 2019 15:19:28 -0400 Subject: Make checkSpace.pl check guard macros: - every .h file needs an #ifndef/#define pair. - They must refer to the same macro. - The guard macros that they refer to must be unique across all headers. --- changes/ticket29756 | 3 +++ scripts/maint/checkSpace.pl | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 changes/ticket29756 (limited to 'changes') diff --git a/changes/ticket29756 b/changes/ticket29756 new file mode 100644 index 0000000000..79995b4995 --- /dev/null +++ b/changes/ticket29756 @@ -0,0 +1,3 @@ + o Minor features (developer tools): + - Add a script to check that each header has a well-formed and unique + guard marco. Closes ticket 29756. diff --git a/scripts/maint/checkSpace.pl b/scripts/maint/checkSpace.pl index 633b47e314..433ae62807 100755 --- a/scripts/maint/checkSpace.pl +++ b/scripts/maint/checkSpace.pl @@ -18,6 +18,8 @@ if ($ARGV[0] =~ /^-/) { our %basenames = (); +our %guardnames = (); + for my $fn (@ARGV) { open(F, "$fn"); my $lastnil = 0; @@ -31,6 +33,10 @@ for my $fn (@ARGV) { } else { $basenames{$basename} = $fn; } + my $isheader = ($fn =~ /\.h/); + my $seenguard = 0; + my $guardname = ""; + while () { ## Warn about windows-style newlines. # (We insist on lines that end with a single LF character, not @@ -112,6 +118,23 @@ for my $fn (@ARGV) { next; } } + + if ($isheader) { + if ($seenguard == 0) { + if (/ifndef\s+(\S+)/) { + ++$seenguard; + $guardname = $1; + } + } elsif ($seenguard == 1) { + if (/^\#define (\S+)/) { + ++$seenguard; + if ($1 ne $guardname) { + msg "GUARD:$fn:$.: Header guard macro mismatch.\n"; + } + } + } + } + if (m!/\*.*?\*/!) { s!\s*/\*.*?\*/!!; } elsif (m!/\*!) { @@ -201,6 +224,15 @@ for my $fn (@ARGV) { } } } + if ($isheader && $C) { + if ($seenguard < 2) { + msg "$fn:No #ifndef/#define header guard pair found.\n"; + } elsif ($guardnames{$guardname}) { + msg "$fn:Guard macro $guardname also used in $guardnames{$guardname}\n"; + } else { + $guardnames{$guardname} = $fn; + } + } close(F); } -- cgit v1.2.3-54-g00ecf From 504aef6228d3a8460f43b9c9cf2cd4175ce4e1f7 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 13 Mar 2019 09:29:10 -0400 Subject: Changes file for practracker (29221) --- changes/bug29221 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/bug29221 (limited to 'changes') diff --git a/changes/bug29221 b/changes/bug29221 new file mode 100644 index 0000000000..fbe08aa9a0 --- /dev/null +++ b/changes/bug29221 @@ -0,0 +1,5 @@ + o Minor features (development tools): + - Tor's test scripts now check for files and functions that seem + too long and complicated. Existing overlong functions and files are + accepted for now, but should eventually be refactored. Closes + ticket 29221. -- cgit v1.2.3-54-g00ecf From cfcf6de1a83ebb192374836a8c35a317fc2894e1 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 20 Mar 2019 18:07:00 +1000 Subject: Changes file for bug 29527 The previous commit introduces these changes: Stop warning about undefined behavior in the probability distribution tests. Float division by zero may technically be undefined behaviour in C, but it's well-defined in IEEE 754. Partial backport of 29298. Closes ticket 29527; bugfix on 0.4.0.1-alpha. --- changes/bug29527 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/bug29527 (limited to 'changes') diff --git a/changes/bug29527 b/changes/bug29527 new file mode 100644 index 0000000000..6f36a9e1a0 --- /dev/null +++ b/changes/bug29527 @@ -0,0 +1,5 @@ + o Minor features (circuit padding): + - Stop warning about undefined behavior in the probability distribution + tests. Float division by zero may technically be undefined behaviour in + C, but it's well-defined in IEEE 754. Partial backport of 29298. + Closes ticket 29527; bugfix on 0.4.0.1-alpha. -- cgit v1.2.3-54-g00ecf From 846d379b50b4f4790a9fe2ec88746748e0fab2b7 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 13 Mar 2019 15:15:03 +0200 Subject: circpad/prob_distr: Use crypto_fast_rng() instead of the old RNG. --- changes/bug28636 | 8 ++++++++ src/core/or/circuitpadding.c | 9 +++++---- src/lib/crypt_ops/crypto_rand.h | 3 +++ src/lib/crypt_ops/crypto_rand_numeric.c | 30 +++++++++++++++++++++++++++++- src/lib/math/prob_distr.c | 16 ++++++++-------- 5 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 changes/bug28636 (limited to 'changes') diff --git a/changes/bug28636 b/changes/bug28636 new file mode 100644 index 0000000000..240655cbea --- /dev/null +++ b/changes/bug28636 @@ -0,0 +1,8 @@ + o Minor bugfixes (circuit padding): + - The circuit padding subsystem does not schedule padding if dormant mode + is enabled. Fixes bug 28636; bugfix on 0.4.0.1-alpha. + + o Minor feature (circuit padding): + - We now use a fast RNG when scheduling circuit padding. Part of ticket + 28636. + diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c index 599d88f493..4514111a96 100644 --- a/src/core/or/circuitpadding.c +++ b/src/core/or/circuitpadding.c @@ -449,7 +449,8 @@ circpad_machine_sample_delay(circpad_machine_state_t *mi) histogram_total_tokens = state->histogram_total_tokens; } - bin_choice = crypto_rand_uint64(histogram_total_tokens); + bin_choice = crypto_fast_rng_get_uint64(get_thread_fast_rng(), + histogram_total_tokens); /* Skip all the initial zero bins */ while (!histogram[curr_bin]) { @@ -498,12 +499,12 @@ circpad_machine_sample_delay(circpad_machine_state_t *mi) bin_end = circpad_histogram_bin_to_usec(mi, curr_bin+1); /* Bin edges are monotonically increasing so this is a bug. Handle it. */ - if (BUG(bin_start > bin_end)) { + if (BUG(bin_start >= bin_end)) { return bin_start; } - /* Sample randomly from within the bin width */ - return (circpad_delay_t)crypto_rand_uint64_range(bin_start, bin_end); + return (circpad_delay_t)crypto_fast_rng_uint64_range(get_thread_fast_rng(), + bin_start, bin_end); } /** diff --git a/src/lib/crypt_ops/crypto_rand.h b/src/lib/crypt_ops/crypto_rand.h index 6f09aedf6a..c51d6a4480 100644 --- a/src/lib/crypt_ops/crypto_rand.h +++ b/src/lib/crypt_ops/crypto_rand.h @@ -66,6 +66,9 @@ void crypto_fast_rng_free_(crypto_fast_rng_t *); unsigned crypto_fast_rng_get_uint(crypto_fast_rng_t *rng, unsigned limit); uint64_t crypto_fast_rng_get_uint64(crypto_fast_rng_t *rng, uint64_t limit); +uint32_t crypto_fast_rng_get_u32(crypto_fast_rng_t *rng); +uint64_t crypto_fast_rng_uint64_range(crypto_fast_rng_t *rng, + uint64_t min, uint64_t max); double crypto_fast_rng_get_double(crypto_fast_rng_t *rng); /** diff --git a/src/lib/crypt_ops/crypto_rand_numeric.c b/src/lib/crypt_ops/crypto_rand_numeric.c index d02c5cdcfa..ffbfa2d56c 100644 --- a/src/lib/crypt_ops/crypto_rand_numeric.c +++ b/src/lib/crypt_ops/crypto_rand_numeric.c @@ -155,7 +155,34 @@ crypto_fast_rng_get_uint64(crypto_fast_rng_t *rng, uint64_t limit) } /** - * As crypto_rand_, but extract the result from a crypto_fast_rng_t. + * As crypto_rand_u32, but extract the result from a crypto_fast_rng_t. + */ +uint32_t +crypto_fast_rng_get_u32(crypto_fast_rng_t *rng) +{ + uint32_t val; + crypto_fast_rng_getbytes(rng, (void*)&val, sizeof(val)); + return val; +} + +/** + * As crypto_rand_uint64_range(), but extract the result from a + * crypto_fast_rng_t. + */ +uint64_t +crypto_fast_rng_uint64_range(crypto_fast_rng_t *rng, + uint64_t min, uint64_t max) +{ + /* Handle corrupted input */ + if (BUG(min >= max)) { + return min; + } + + return min + crypto_fast_rng_get_uint64(rng, max - min); +} + +/** + * As crypto_rand_get_double() but extract the result from a crypto_fast_rng_t. */ double crypto_fast_rng_get_double(crypto_fast_rng_t *rng) @@ -164,3 +191,4 @@ crypto_fast_rng_get_double(crypto_fast_rng_t *rng) crypto_fast_rng_getbytes(rng, (void*)&u, sizeof(u)); return ((double)u) / UINT_MAX_AS_DOUBLE; } + diff --git a/src/lib/math/prob_distr.c b/src/lib/math/prob_distr.c index bfad06963d..d44dc28265 100644 --- a/src/lib/math/prob_distr.c +++ b/src/lib/math/prob_distr.c @@ -459,7 +459,7 @@ random_uniform_01(void) * system is broken. */ z = 0; - while ((x = crypto_rand_u32()) == 0) { + while ((x = crypto_fast_rng_get_u32(get_thread_fast_rng())) == 0) { if (z >= 1088) /* Your bit sampler is broken. Go home. */ return 0; @@ -473,8 +473,8 @@ random_uniform_01(void) * occur only with measure zero in the uniform distribution on * [0, 1]. */ - hi = crypto_rand_u32() | UINT32_C(0x80000000); - lo = crypto_rand_u32() | UINT32_C(0x00000001); + hi = crypto_fast_rng_get_u32(get_thread_fast_rng()) | UINT32_C(0x80000000); + lo = crypto_fast_rng_get_u32(get_thread_fast_rng()) | UINT32_C(0x00000001); /* Round to nearest scaled significand in [2^63, 2^64]. */ s = hi*(double)4294967296 + lo; @@ -1437,7 +1437,7 @@ static double logistic_sample(const struct dist *dist) { const struct logistic *L = dist_to_const_logistic(dist); - uint32_t s = crypto_rand_u32(); + uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng()); double t = random_uniform_01(); double p0 = random_uniform_01(); @@ -1487,7 +1487,7 @@ static double log_logistic_sample(const struct dist *dist) { const struct log_logistic *LL = dist_to_const_log_logistic(dist); - uint32_t s = crypto_rand_u32(); + uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng()); double p0 = random_uniform_01(); return sample_log_logistic_scaleshape(s, p0, LL->alpha, LL->beta); @@ -1536,7 +1536,7 @@ static double weibull_sample(const struct dist *dist) { const struct weibull *W = dist_to_const_weibull(dist); - uint32_t s = crypto_rand_u32(); + uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng()); double p0 = random_uniform_01(); return sample_weibull(s, p0, W->lambda, W->k); @@ -1585,7 +1585,7 @@ static double genpareto_sample(const struct dist *dist) { const struct genpareto *GP = dist_to_const_genpareto(dist); - uint32_t s = crypto_rand_u32(); + uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng()); double p0 = random_uniform_01(); return sample_genpareto_locscale(s, p0, GP->mu, GP->sigma, GP->xi); @@ -1634,7 +1634,7 @@ static double geometric_sample(const struct dist *dist) { const struct geometric *G = dist_to_const_geometric(dist); - uint32_t s = crypto_rand_u32(); + uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng()); double p0 = random_uniform_01(); return sample_geometric(s, p0, G->p); -- cgit v1.2.3-54-g00ecf From a5df9402b611f9fcfcbd22e486ae0ae16246ecd0 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 21 Mar 2019 16:49:56 +0200 Subject: prob-distr: Decrease false positive rate of stochastic tests. --- changes/bug29693 | 3 +++ src/test/test_prob_distr.c | 15 +++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 changes/bug29693 (limited to 'changes') diff --git a/changes/bug29693 b/changes/bug29693 new file mode 100644 index 0000000000..33ce051c40 --- /dev/null +++ b/changes/bug29693 @@ -0,0 +1,3 @@ + o Minor bugfixes (unit tests): + - Decrease the false positive rate of stochastic probability distribution + tests. Fixes bug 29693; bugfix on 0.4.0.1-alpha. \ No newline at end of file diff --git a/src/test/test_prob_distr.c b/src/test/test_prob_distr.c index 42cc6d70f6..37cfdae7d9 100644 --- a/src/test/test_prob_distr.c +++ b/src/test/test_prob_distr.c @@ -878,11 +878,14 @@ test_uniform_interval(void *arg) * is higher: 1 - Binom(0; n, alpha) = 1 - (1 - alpha)^n. For n = 10, * this is about 10%, and for n = 100 it is well over 50%. * - * We can drive it down by running each test twice, and accepting it if - * it passes at least once; in that case, it is as if we used Binom(2; - * 2, alpha) = alpha^2 as the false positive rate for each test, and - * for n = 10 tests, it would be 0.1%, and for n = 100 tests, still - * only 1%. + * Given that these tests will run with every CI job, we want to drive down the + * false positive rate. We can drive it down by running each test four times, + * and accepting it if it passes at least once; in that case, it is as if we + * used Binom(4; 2, alpha) = alpha^4 as the false positive rate for each test, + * and for n = 10 tests, it would be 9.99999959506e-08. If each CI build has 14 + * jobs, then the chance of a CI build failing is 1.39999903326e-06, which + * means that a CI build will break with probability 50% after about 495106 + * builds. * * The critical value for a chi^2 distribution with 100 degrees of * freedom and false positive rate alpha = 1% was taken from: @@ -895,7 +898,7 @@ test_uniform_interval(void *arg) static const size_t NSAMPLES = 100000; /* Number of chances we give to the test to succeed. */ -static const unsigned NTRIALS = 2; +static const unsigned NTRIALS = 4; /* Number of times we want the test to pass per NTRIALS. */ static const unsigned NPASSES_MIN = 1; -- cgit v1.2.3-54-g00ecf From 9529d99982eb64998e12db7704fa977bf02f541c Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sun, 24 Mar 2019 09:25:30 +0200 Subject: Tweak changes file --- changes/ticket29537 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'changes') diff --git a/changes/ticket29537 b/changes/ticket29537 index 048e13c65f..afe2308205 100644 --- a/changes/ticket29537 +++ b/changes/ticket29537 @@ -1,3 +1,3 @@ o Testing: - - Check that all valid values of `int` and `unsigned int` can be - represented by `void *`. Resolves issue 29537. + - Check that representative subsets of values of `int` and `unsigned int` + can be represented by `void *`. Resolves issue 29537. -- cgit v1.2.3-54-g00ecf From f09205ef5384175f5d222f3137e42ae44486a30b Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sun, 24 Mar 2019 10:10:52 +0200 Subject: Refactor test_utils_general() to fix Coverity warnings --- changes/bug29823 | 5 ++ src/test/test_shared_random.c | 134 ++++++++++++++++++++++++------------------ 2 files changed, 82 insertions(+), 57 deletions(-) create mode 100644 changes/bug29823 (limited to 'changes') diff --git a/changes/bug29823 b/changes/bug29823 new file mode 100644 index 0000000000..d856cf1fef --- /dev/null +++ b/changes/bug29823 @@ -0,0 +1,5 @@ + o Minor bugfixes (unit tests): + - Split test_utils_general() to several smaller test functions in + test_utils_general(). This makes it easier to perform resource + deallocation on assert failure and fixes Coverity warnings CID 1444117 + and CID 1444118. Fixes bug 29823; bugfix on 0.2.9.1-alpha. diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c index 5fa7e80d07..480799383b 100644 --- a/src/test/test_shared_random.c +++ b/src/test/test_shared_random.c @@ -1081,70 +1081,85 @@ test_sr_get_majority_srv_from_votes(void *arg) smartlist_free(votes); } -/* Test utils that don't depend on authority state */ +/* Testing sr_srv_dup(). */ static void -test_utils_general(void *arg) +test_sr_svr_dup(void *arg) { - (void) arg; + (void)arg; - /* Testing sr_srv_dup(). */ - { - sr_srv_t *srv = NULL, *dup_srv = NULL; - const char *srv_value = - "1BDB7C3E973936E4D13A49F37C859B3DC69C429334CF9412E3FEF6399C52D47A"; - srv = tor_malloc_zero(sizeof(*srv)); - srv->num_reveals = 42; - memcpy(srv->value, srv_value, sizeof(srv->value)); - dup_srv = sr_srv_dup(srv); - tt_assert(dup_srv); - tt_u64_op(dup_srv->num_reveals, OP_EQ, srv->num_reveals); - tt_mem_op(dup_srv->value, OP_EQ, srv->value, sizeof(srv->value)); - tor_free(srv); - tor_free(dup_srv); - } + sr_srv_t *srv = NULL, *dup_srv = NULL; + const char *srv_value = + "1BDB7C3E973936E4D13A49F37C859B3DC69C429334CF9412E3FEF6399C52D47A"; + srv = tor_malloc_zero(sizeof(*srv)); + srv->num_reveals = 42; + memcpy(srv->value, srv_value, sizeof(srv->value)); + dup_srv = sr_srv_dup(srv); + tt_assert(dup_srv); + tt_u64_op(dup_srv->num_reveals, OP_EQ, srv->num_reveals); + tt_mem_op(dup_srv->value, OP_EQ, srv->value, sizeof(srv->value)); - /* Testing commitments_are_the_same(). Currently, the check is to test the - * value of the encoded commit so let's make sure that actually works. */ - { - /* Payload of 57 bytes that is the length of sr_commit_t->encoded_commit. - * 56 bytes of payload and a NUL terminated byte at the end ('\x00') - * which comes down to SR_COMMIT_BASE64_LEN + 1. */ - const char *payload = - "\x5d\xb9\x60\xb6\xcc\x51\x68\x52\x31\xd9\x88\x88\x71\x71\xe0\x30" - "\x59\x55\x7f\xcd\x61\xc0\x4b\x05\xb8\xcd\xc1\x48\xe9\xcd\x16\x1f" - "\x70\x15\x0c\xfc\xd3\x1a\x75\xd0\x93\x6c\xc4\xe0\x5c\xbe\xe2\x18" - "\xc7\xaf\x72\xb6\x7c\x9b\x52\x00"; - sr_commit_t commit1, commit2; - memcpy(commit1.encoded_commit, payload, sizeof(commit1.encoded_commit)); - memcpy(commit2.encoded_commit, payload, sizeof(commit2.encoded_commit)); - tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 1); - /* Let's corrupt one of them. */ - memset(commit1.encoded_commit, 'A', sizeof(commit1.encoded_commit)); - tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 0); - } + done: + tor_free(srv); + tor_free(dup_srv); +} - /* Testing commit_is_authoritative(). */ - { - crypto_pk_t *k = crypto_pk_new(); - char digest[DIGEST_LEN]; - sr_commit_t commit; +/* Testing commitments_are_the_same(). Currently, the check is to test the + * value of the encoded commit so let's make sure that actually works. */ +static void +test_commitments_are_the_same(void *arg) +{ + (void)arg; - tt_assert(!crypto_pk_generate_key(k)); + /* Payload of 57 bytes that is the length of sr_commit_t->encoded_commit. + * 56 bytes of payload and a NUL terminated byte at the end ('\x00') + * which comes down to SR_COMMIT_BASE64_LEN + 1. */ + const char *payload = + "\x5d\xb9\x60\xb6\xcc\x51\x68\x52\x31\xd9\x88\x88\x71\x71\xe0\x30" + "\x59\x55\x7f\xcd\x61\xc0\x4b\x05\xb8\xcd\xc1\x48\xe9\xcd\x16\x1f" + "\x70\x15\x0c\xfc\xd3\x1a\x75\xd0\x93\x6c\xc4\xe0\x5c\xbe\xe2\x18" + "\xc7\xaf\x72\xb6\x7c\x9b\x52\x00"; + sr_commit_t commit1, commit2; + memcpy(commit1.encoded_commit, payload, sizeof(commit1.encoded_commit)); + memcpy(commit2.encoded_commit, payload, sizeof(commit2.encoded_commit)); + tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 1); + /* Let's corrupt one of them. */ + memset(commit1.encoded_commit, 'A', sizeof(commit1.encoded_commit)); + tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 0); - tt_int_op(0, OP_EQ, crypto_pk_get_digest(k, digest)); - memcpy(commit.rsa_identity, digest, sizeof(commit.rsa_identity)); - tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 1); - /* Change the pubkey. */ - memset(commit.rsa_identity, 0, sizeof(commit.rsa_identity)); - tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 0); - crypto_pk_free(k); - } + done: + return; +} - /* Testing get_phase_str(). */ - { - tt_str_op(get_phase_str(SR_PHASE_REVEAL), OP_EQ, "reveal"); - tt_str_op(get_phase_str(SR_PHASE_COMMIT), OP_EQ, "commit"); - } +/* Testing commit_is_authoritative(). */ +static void +test_commit_is_authoritative(void *arg) +{ + (void)arg; + + crypto_pk_t *k = crypto_pk_new(); + char digest[DIGEST_LEN]; + sr_commit_t commit; + + tt_assert(!crypto_pk_generate_key(k)); + + tt_int_op(0, OP_EQ, crypto_pk_get_digest(k, digest)); + memcpy(commit.rsa_identity, digest, sizeof(commit.rsa_identity)); + tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 1); + /* Change the pubkey. */ + memset(commit.rsa_identity, 0, sizeof(commit.rsa_identity)); + tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 0); + + done: + crypto_pk_free(k); +} + +static void +test_get_phase_str(void *arg) +{ + (void)arg; + + tt_str_op(get_phase_str(SR_PHASE_REVEAL), OP_EQ, "reveal"); + tt_str_op(get_phase_str(SR_PHASE_COMMIT), OP_EQ, "commit"); done: return; @@ -1649,7 +1664,12 @@ struct testcase_t sr_tests[] = { { "sr_compute_srv", test_sr_compute_srv, TT_FORK, NULL, NULL }, { "sr_get_majority_srv_from_votes", test_sr_get_majority_srv_from_votes, TT_FORK, NULL, NULL }, - { "utils_general", test_utils_general, TT_FORK, NULL, NULL }, + { "sr_svr_dup", test_sr_svr_dup, TT_FORK, NULL, NULL }, + { "commitments_are_the_same", test_commitments_are_the_same, TT_FORK, NULL, + NULL }, + { "commit_is_authoritative", test_commit_is_authoritative, TT_FORK, NULL, + NULL }, + { "get_phase_str", test_get_phase_str, TT_FORK, NULL, NULL }, { "utils_auth", test_utils_auth, TT_FORK, NULL, NULL }, { "state_transition", test_state_transition, TT_FORK, NULL, NULL }, { "state_update", test_state_update, TT_FORK, -- cgit v1.2.3-54-g00ecf From 4be522b2e6eb634b141d7876234acf40a931cab6 Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Mon, 25 Mar 2019 03:00:53 +0100 Subject: Pass NULL to lpApplicationName in CreateProcessA(). When NULL is given to lpApplicationName we enable Windows' "magical" path interpretation logic, which makes Tor 0.4.x behave in the same way as previous Tor versions did when it comes to executing binaries in different system paths. For more information about this have a look at the CreateProcessA() documentation on MSDN -- especially the string interpretation example is useful to understand this issue. This bug was introduced in commit bfb94dd2ca8. See: https://bugs.torproject.org/29874 --- changes/bug29874 | 4 ++++ src/lib/process/process_win32.c | 7 +------ 2 files changed, 5 insertions(+), 6 deletions(-) create mode 100644 changes/bug29874 (limited to 'changes') diff --git a/changes/bug29874 b/changes/bug29874 new file mode 100644 index 0000000000..8534753b51 --- /dev/null +++ b/changes/bug29874 @@ -0,0 +1,4 @@ + o Minor bugfixes (pluggable transports): + - Restore old behaviour when it comes to discovering the path of a given + Pluggable Transport exe-file. Fixes bug 29874; bugfix on 0.4.0.1-alpha. + diff --git a/src/lib/process/process_win32.c b/src/lib/process/process_win32.c index 21d0b23476..ddbe76bfd9 100644 --- a/src/lib/process/process_win32.c +++ b/src/lib/process/process_win32.c @@ -152,11 +152,6 @@ process_win32_exec(process_t *process) HANDLE stdin_pipe_read = NULL; HANDLE stdin_pipe_write = NULL; BOOL ret = FALSE; - const char *filename = process_get_command(process); - - /* Not much we can do if we haven't been told what to start. */ - if (BUG(filename == NULL)) - return PROCESS_STATUS_ERROR; /* Setup our security attributes. */ SECURITY_ATTRIBUTES security_attributes; @@ -211,7 +206,7 @@ process_win32_exec(process_t *process) char *joined_argv = tor_join_win_cmdline((const char **)argv); /* Create the child process */ - ret = CreateProcessA(filename, + ret = CreateProcessA(NULL, joined_argv, NULL, NULL, -- cgit v1.2.3-54-g00ecf From 5d2f5e482e9985ad00f517ac3725b2336fbb930b Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Wed, 20 Mar 2019 20:51:12 -0500 Subject: Correctly report PT vs proxy during bootstrap Previously, or_connection_t did not record whether or not the connection uses a pluggable transport. Instead, it stored the underlying proxy protocol of the pluggable transport in proxy_type. This made bootstrap reporting treat pluggable transport connections as plain proxy connections. Store a separate bit indicating whether a pluggable transport is in use, and decode this during bootstrap reporting. Fixes bug 28925; bugfix on 0.4.0.1-alpha. --- changes/bug28925 | 4 ++++ src/core/mainloop/connection.c | 16 +++++++++++----- src/core/mainloop/connection.h | 2 +- src/core/or/connection_or.c | 16 +++++++++++++--- src/core/or/or_connection_st.h | 2 ++ 5 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 changes/bug28925 (limited to 'changes') diff --git a/changes/bug28925 b/changes/bug28925 new file mode 100644 index 0000000000..a867443885 --- /dev/null +++ b/changes/bug28925 @@ -0,0 +1,4 @@ + o Minor bugfixes (bootstrap reporting): + - During bootstrap reporting, correctly distinguish pluggable + transports from plain proxies. Fixes bug 28925; bugfix on + 0.4.0.1-alpha. diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c index 41be3833ab..c8b19344bd 100644 --- a/src/core/mainloop/connection.c +++ b/src/core/mainloop/connection.c @@ -5361,17 +5361,20 @@ assert_connection_ok(connection_t *conn, time_t now) } /** Fills addr and port with the details of the global - * proxy server we are using. - * conn contains the connection we are using the proxy for. + * proxy server we are using. Store a 1 to the int pointed to by + * is_put_out if the connection is using a pluggable + * transport; store 0 otherwise. conn contains the connection + * we are using the proxy for. * * Return 0 on success, -1 on failure. */ int get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, - const connection_t *conn) + int *is_pt_out, const connection_t *conn) { const or_options_t *options = get_options(); + *is_pt_out = 0; /* Client Transport Plugins can use another proxy, but that should be hidden * from the rest of tor (as the plugin is responsible for dealing with the * proxy), check it first, then check the rest of the proxy types to allow @@ -5387,6 +5390,7 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, tor_addr_copy(addr, &transport->addr); *port = transport->port; *proxy_type = transport->socks_version; + *is_pt_out = 1; return 0; } @@ -5423,11 +5427,13 @@ log_failed_proxy_connection(connection_t *conn) { tor_addr_t proxy_addr; uint16_t proxy_port; - int proxy_type; + int proxy_type, is_pt; - if (get_proxy_addrport(&proxy_addr, &proxy_port, &proxy_type, conn) != 0) + if (get_proxy_addrport(&proxy_addr, &proxy_port, &proxy_type, &is_pt, + conn) != 0) return; /* if we have no proxy set up, leave this function. */ + (void)is_pt; log_warn(LD_NET, "The connection to the %s proxy server at %s just failed. " "Make sure that the proxy server is up and running.", diff --git a/src/core/mainloop/connection.h b/src/core/mainloop/connection.h index f4f0e839ae..411f13a8b8 100644 --- a/src/core/mainloop/connection.h +++ b/src/core/mainloop/connection.h @@ -187,7 +187,7 @@ int connection_proxy_connect(connection_t *conn, int type); int connection_read_proxy_handshake(connection_t *conn); void log_failed_proxy_connection(connection_t *conn); int get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, - const connection_t *conn); + int *is_pt_out, const connection_t *conn); int retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol); diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c index 55047da167..debf482cb3 100644 --- a/src/core/or/connection_or.c +++ b/src/core/or/connection_or.c @@ -437,7 +437,15 @@ connection_or_state_publish(const or_connection_t *conn, uint8_t state) msg.type = ORCONN_MSGTYPE_STATE; msg.u.state.gid = conn->base_.global_identifier; - msg.u.state.proxy_type = conn->proxy_type; + if (conn->is_pt) { + /* Do extra decoding because conn->proxy_type indicates the proxy + * protocol that tor uses to talk with the transport plugin, + * instead of PROXY_PLUGGABLE. */ + tor_assert_nonfatal(conn->proxy_type != PROXY_NONE); + msg.u.state.proxy_type = PROXY_PLUGGABLE; + } else { + msg.u.state.proxy_type = conn->proxy_type; + } msg.u.state.state = state; if (conn->chan) { msg.u.state.chan = TLS_CHAN_TO_BASE(conn->chan)->global_identifier; @@ -1472,7 +1480,7 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port, int r; tor_addr_t proxy_addr; uint16_t proxy_port; - int proxy_type; + int proxy_type, is_pt = 0; tor_assert(_addr); tor_assert(id_digest); @@ -1516,13 +1524,15 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port, conn->is_outgoing = 1; /* If we are using a proxy server, find it and use it. */ - r = get_proxy_addrport(&proxy_addr, &proxy_port, &proxy_type, TO_CONN(conn)); + r = get_proxy_addrport(&proxy_addr, &proxy_port, &proxy_type, &is_pt, + TO_CONN(conn)); if (r == 0) { conn->proxy_type = proxy_type; if (proxy_type != PROXY_NONE) { tor_addr_copy(&addr, &proxy_addr); port = proxy_port; conn->base_.proxy_state = PROXY_INFANT; + conn->is_pt = is_pt; } connection_or_change_state(conn, OR_CONN_STATE_CONNECTING); connection_or_event_status(conn, OR_CONN_EVENT_LAUNCHED, 0); diff --git a/src/core/or/or_connection_st.h b/src/core/or/or_connection_st.h index d5db5e8694..a5ce844bff 100644 --- a/src/core/or/or_connection_st.h +++ b/src/core/or/or_connection_st.h @@ -67,6 +67,8 @@ struct or_connection_t { * geoip cache and handled by the DoS mitigation subsystem. We use this to * insure we have a coherent count of concurrent connection. */ unsigned int tracked_for_dos_mitigation : 1; + /** True iff this connection is using a pluggable transport */ + unsigned int is_pt : 1; uint16_t link_proto; /**< What protocol version are we using? 0 for * "none negotiated yet." */ -- cgit v1.2.3-54-g00ecf From b71febcea809f154f65e6e00825724b3fbeccb10 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 25 Mar 2019 15:08:36 -0400 Subject: changes file for control.c splitup --- changes/ticket29894 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket29894 (limited to 'changes') diff --git a/changes/ticket29894 b/changes/ticket29894 new file mode 100644 index 0000000000..6392598ec6 --- /dev/null +++ b/changes/ticket29894 @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Split up the control.c file into several submodules, in preparation + for distributing its current responsibilities throughout the codebase. + Closes ticket 29894. -- cgit v1.2.3-54-g00ecf From 6ecf9590eae8cac125705d2f99b284de998d5649 Mon Sep 17 00:00:00 2001 From: juga0 Date: Fri, 21 Dec 2018 17:10:19 +0000 Subject: changes: add file for #21377 --- changes/ticket21377 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket21377 (limited to 'changes') diff --git a/changes/ticket21377 b/changes/ticket21377 new file mode 100644 index 0000000000..2bf5149a0a --- /dev/null +++ b/changes/ticket21377 @@ -0,0 +1,4 @@ + o Minor features (dircache): + - When a directory authority is using a bandwidth file to obtain the + bandwidth values that will be included in the next vote, serve this + bandwidth file at /tor/status-vote/next/bandwidth. Closes ticket 21377. \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 08176c239651656bf691f9414d037ab803be0fc0 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 21 Mar 2019 20:57:42 +0200 Subject: prob-distr: Silence some coverity warnings. --- changes/bug29805 | 3 +++ src/lib/math/prob_distr.h | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 changes/bug29805 (limited to 'changes') diff --git a/changes/bug29805 b/changes/bug29805 new file mode 100644 index 0000000000..00c846e9af --- /dev/null +++ b/changes/bug29805 @@ -0,0 +1,3 @@ + o Minor bugfixes (probability distributions): + - Refactor and improve parts of the probability distribution code that made + Coverity complain. Fixes bug 29805; bugfix on 0.4.0.1-alpha. \ No newline at end of file diff --git a/src/lib/math/prob_distr.h b/src/lib/math/prob_distr.h index 66acb796fd..9b2ce41240 100644 --- a/src/lib/math/prob_distr.h +++ b/src/lib/math/prob_distr.h @@ -19,9 +19,22 @@ struct dist { const struct dist_ops *ops; }; +/** Assign the right ops to dist.dist_ops */ #define DIST_BASE(OPS) { .ops = (OPS) } + +/** A compile-time type-checking macro for use with DIST_BASE_TYPED. */ +#ifdef __COVERITY___ +/* Disable type-checking if coverity is enabled, since they don't like it */ +#define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) 0 +#else +#define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) \ + (0*sizeof(&(OBJ) - (const TYPE *)&(OBJ))) +#endif + +/** Macro to initialize a distribution with the right OPS, while making sure + * that OBJ is of the right TYPE */ #define DIST_BASE_TYPED(OPS, OBJ, TYPE) \ - DIST_BASE((OPS) + 0*sizeof(&(OBJ) - (const TYPE *)&(OBJ))) + DIST_BASE((OPS) + TYPE_CHECK_OBJ(OPS,OBJ,TYPE)) const char *dist_name(const struct dist *); double dist_sample(const struct dist *); -- cgit v1.2.3-54-g00ecf From 3767eff9bb712bccc86718647c7dc84998a7f95f Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 26 Mar 2019 20:07:26 -0400 Subject: changes file for pubsub code --- changes/pubsub | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/pubsub (limited to 'changes') diff --git a/changes/pubsub b/changes/pubsub new file mode 100644 index 0000000000..f67b36b988 --- /dev/null +++ b/changes/pubsub @@ -0,0 +1,5 @@ + o Major features (code organization): + - Tor now includes a generic publish-subscribe message-passing subsystem + that we can use to organize intermodule dependencies. We hope to use + this to reduce dependencies between modules that don't need to be + related, and to generally simplify our codebase. Closes ticket 28226. -- cgit v1.2.3-54-g00ecf From a10d4adc25500e160c71d0d3f32a6f3ebbf3c9fd Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 27 Mar 2019 11:07:55 +1000 Subject: Stop assuming that /usr/bin/python3 exists For scripts that work with python2, use /usr/bin/python. Otherwise, use /usr/bin/env python3. Fixes bug 29913; bugfix on 0.2.5.3-alpha. --- changes/ticket29913 | 4 ++++ scripts/maint/checkIncludes.py | 2 +- scripts/maint/practracker/practracker.py | 2 +- scripts/maint/rectify_include_paths.py | 2 +- src/config/mmdb-convert.py | 2 +- src/test/ope_ref.py | 2 +- 6 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 changes/ticket29913 (limited to 'changes') diff --git a/changes/ticket29913 b/changes/ticket29913 new file mode 100644 index 0000000000..a713b0ccef --- /dev/null +++ b/changes/ticket29913 @@ -0,0 +1,4 @@ + o Minor bugfixes (python): + - Stop assuming that /usr/bin/python3 exists. For scripts that work with + python2, use /usr/bin/python. Otherwise, use /usr/bin/env python3. + Fixes bug 29913; bugfix on 0.2.5.3-alpha. diff --git a/scripts/maint/checkIncludes.py b/scripts/maint/checkIncludes.py index 3afd9bbebe..ec9350b9b1 100755 --- a/scripts/maint/checkIncludes.py +++ b/scripts/maint/checkIncludes.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/python # Copyright 2018 The Tor Project, Inc. See LICENSE file for licensing info. """This script looks through all the directories for files matching *.c or diff --git a/scripts/maint/practracker/practracker.py b/scripts/maint/practracker/practracker.py index 22cb46c749..febb14639d 100755 --- a/scripts/maint/practracker/practracker.py +++ b/scripts/maint/practracker/practracker.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/python """ Best-practices tracker for Tor source code. diff --git a/scripts/maint/rectify_include_paths.py b/scripts/maint/rectify_include_paths.py index 401fadae6d..d1a2328ca6 100755 --- a/scripts/maint/rectify_include_paths.py +++ b/scripts/maint/rectify_include_paths.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/python import os import os.path diff --git a/src/config/mmdb-convert.py b/src/config/mmdb-convert.py index 706a8b03cc..b861e9433e 100644 --- a/src/config/mmdb-convert.py +++ b/src/config/mmdb-convert.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/python # This software has been dedicated to the public domain under the CC0 # public domain dedication. diff --git a/src/test/ope_ref.py b/src/test/ope_ref.py index f9bd97c546..b2f7012563 100644 --- a/src/test/ope_ref.py +++ b/src/test/ope_ref.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # Copyright 2018-2019, The Tor Project, Inc. See LICENSE for licensing info. # Reference implementation for our rudimentary OPE code, used to -- cgit v1.2.3-54-g00ecf From 283ee0ba0a1540a9e8e8d68625d89315a5356162 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Wed, 27 Mar 2019 19:27:57 +0200 Subject: Fix SC2086 warnings in asciidoc-helper.sh --- changes/bug29926 | 2 ++ doc/asciidoc-helper.sh | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 changes/bug29926 (limited to 'changes') diff --git a/changes/bug29926 b/changes/bug29926 new file mode 100644 index 0000000000..ab1417c603 --- /dev/null +++ b/changes/bug29926 @@ -0,0 +1,2 @@ + o Code simplification and refactoring (shell scripts): + - Fix shellcheck warnings in asciidoc-helper.sh. Resolves issue 29926. diff --git a/doc/asciidoc-helper.sh b/doc/asciidoc-helper.sh index a3ef53f884..765850a125 100755 --- a/doc/asciidoc-helper.sh +++ b/doc/asciidoc-helper.sh @@ -19,7 +19,7 @@ if [ "$1" = "html" ]; then base=${output%%.html.in} if [ "$2" != none ]; then - TZ=UTC "$2" -d manpage -o $output $input; + TZ=UTC "$2" -d manpage -o "$output" "$input"; else echo "=================================="; echo; @@ -44,8 +44,8 @@ elif [ "$1" = "man" ]; then echo "=================================="; exit 1; fi - if "$2" -f manpage $input; then - mv $base.1 $output; + if "$2" -f manpage "$input"; then + mv "$base.1" "$output"; else cat< Date: Thu, 28 Mar 2019 09:29:00 -0400 Subject: test_routerkeys.c: Always check mkdir() return value After this fix, we have no more unchecked mkdir() calls. Bug 29939; CID 144254. Bugfix on 0.2.7.2-alpha. --- changes/bug29939 | 4 ++++ src/test/test_routerkeys.c | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 changes/bug29939 (limited to 'changes') diff --git a/changes/bug29939 b/changes/bug29939 new file mode 100644 index 0000000000..0e9b46c075 --- /dev/null +++ b/changes/bug29939 @@ -0,0 +1,4 @@ + o Minor bugfixes (unit tests): + - In the "routerkeys/*" tests, check the return values of mkdir() for + possible failures. Fixes bug 29939; bugfix on 0.2.7.2-alpha. Found by + Coverity as CID 1444254. diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c index 727fa5660f..102d9334a1 100644 --- a/src/test/test_routerkeys.c +++ b/src/test/test_routerkeys.c @@ -455,11 +455,11 @@ test_routerkeys_ed_keys_init_all(void *arg) options->TestingLinkKeySlop = 2*3600; #ifdef _WIN32 - mkdir(dir); - mkdir(keydir); + tt_int_op(0, OP_EQ, mkdir(dir)); + tt_int_op(0, OP_EQ, mkdir(keydir)); #else - mkdir(dir, 0700); - mkdir(keydir, 0700); + tt_int_op(0, OP_EQ, mkdir(dir, 0700)); + tt_int_op(0, OP_EQ, mkdir(keydir, 0700)); #endif /* defined(_WIN32) */ options->DataDirectory = dir; -- cgit v1.2.3-54-g00ecf From c2222ba169a059e1a6ce04cb9014fe8870674d87 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sat, 9 Feb 2019 16:56:54 +0200 Subject: Add changes file --- changes/ticket28816 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket28816 (limited to 'changes') diff --git a/changes/ticket28816 b/changes/ticket28816 new file mode 100644 index 0000000000..02878ccfdc --- /dev/null +++ b/changes/ticket28816 @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Introduce a connection_dir_buf_add() helper function that checks for + compress_state of dir_connection_t and automatically writes a string to + directory connection with or without compression. Resolves issue 28816. -- cgit v1.2.3-54-g00ecf From 194b25f0c7043b2485bb90da6fb24c0e96957875 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 26 Mar 2019 18:12:16 +1000 Subject: dircache: Refactor handle_get_next_bandwidth() to use connection_dir_buf_add() Implements ticket 29897. --- changes/ticket29897 | 3 +++ src/feature/dircache/dircache.c | 5 +---- 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 changes/ticket29897 (limited to 'changes') diff --git a/changes/ticket29897 b/changes/ticket29897 new file mode 100644 index 0000000000..232a79fbce --- /dev/null +++ b/changes/ticket29897 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Refactor handle_get_next_bandwidth() to use connection_dir_buf_add(). + Implements ticket 29897. diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c index caa085dd63..62eb4c86c2 100644 --- a/src/feature/dircache/dircache.c +++ b/src/feature/dircache/dircache.c @@ -1486,13 +1486,10 @@ handle_get_next_bandwidth(dir_connection_t *conn, conn->compress_state = tor_compress_new(1, compress_method, choose_compression_level(len/2)); log_debug(LD_DIR, "Compressing bandwidth file."); - connection_buf_add_compress(bandwidth, len, conn, 0); - /* Flush the compression state. */ - connection_buf_add_compress("", 0, conn, 1); } else { log_debug(LD_DIR, "Not compressing bandwidth file."); - connection_buf_add(bandwidth, len, TO_CONN(conn)); } + connection_dir_buf_add((const char*)bandwidth, len, conn, 1); tor_free(bandwidth); return 0; } -- cgit v1.2.3-54-g00ecf From bf953fe602a973259723dacb4389d3c4bee7e0a4 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Tue, 5 Mar 2019 18:02:24 +0200 Subject: Add changes file --- changes/ticket29662 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/ticket29662 (limited to 'changes') diff --git a/changes/ticket29662 b/changes/ticket29662 new file mode 100644 index 0000000000..872df9ad82 --- /dev/null +++ b/changes/ticket29662 @@ -0,0 +1,5 @@ + o Minor features (debugging): + - Introduce tor_assertf() and tor_assertf_nonfatal() to enable logging of + additional information during assert failure. Now we can use format + strings to include pieces of information that are relevant for trouble + shooting. Resolves ticket 29662. -- cgit v1.2.3-54-g00ecf From 367dd9cf0226c087d49225a20415e9a199d2d71f Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 3 Apr 2019 10:16:18 -0400 Subject: 30001: Fix a race condition in test_dir_handle_get.c Previously we used time(NULL) to set the Expires: header in our HTTP responses. This made the actual contents of that header untestable, since the unit tests have no good way to override time(), or to see what time() was at the exact moment of the call to time() in dircache.c. This gave us a race in dir_handle_get/status_vote_next_bandwidth, where the time() call in dircache.c got one value, and the call in the tests got another value. I'm applying our regular solution here: using approx_time() so that the value stays the same between the code and the test. Since approx_time() is updated on every event callback, we shouldn't be losing any accuracy here. Fixes bug 30001. Bug introduced in fb4a40c32c4a7e5; not in any released Tor. --- changes/bug30001 | 4 ++++ src/feature/dircache/dircache.c | 2 +- src/test/test_dir_handle_get.c | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 changes/bug30001 (limited to 'changes') diff --git a/changes/bug30001 b/changes/bug30001 new file mode 100644 index 0000000000..e3304701e7 --- /dev/null +++ b/changes/bug30001 @@ -0,0 +1,4 @@ + o Minor features (testing): + - Use the approx_time() function when setting the "Expires" header + in directory replies, to make them more testable. Needed for + ticket 30001. diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c index caa085dd63..1123d034e0 100644 --- a/src/feature/dircache/dircache.c +++ b/src/feature/dircache/dircache.c @@ -124,7 +124,7 @@ write_http_response_header_impl(dir_connection_t *conn, ssize_t length, long cache_lifetime) { char date[RFC1123_TIME_LEN+1]; - time_t now = time(NULL); + time_t now = approx_time(); buf_t *buf = buf_new_with_capacity(1024); tor_assert(conn); diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c index c3a17e7309..e57bd02584 100644 --- a/src/test/test_dir_handle_get.c +++ b/src/test/test_dir_handle_get.c @@ -2526,7 +2526,7 @@ test_dir_handle_get_status_vote_next_bandwidth(void* data) /* Check cache lifetime */ char expbuf[RFC1123_TIME_LEN+1]; - time_t now = time(NULL); + time_t now = approx_time(); /* BANDWIDTH_CACHE_LIFETIME is defined in dircache.c. */ format_rfc1123_time(expbuf, (time_t)(now + 30*60)); char *expires = NULL; -- cgit v1.2.3-54-g00ecf From b2eced6c0747159ab7b3942a45c1a147a5ecfc96 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Wed, 3 Apr 2019 18:05:23 +0300 Subject: Add changes file --- changes/bug30002 | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 changes/bug30002 (limited to 'changes') diff --git a/changes/bug30002 b/changes/bug30002 new file mode 100644 index 0000000000..da61c9e4b2 --- /dev/null +++ b/changes/bug30002 @@ -0,0 +1,2 @@ + o Code simplification and refactoring (shell scripts): + - Fix shellcheck warnings in test_key_expiration.sh. Resolves issue 30002. -- cgit v1.2.3-54-g00ecf From 99b87d7ca48c5ed80aec5f24902843f72975bfea Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 3 Apr 2019 13:53:06 -0400 Subject: Even more diagnostic messages for bug 28223. Try to figure out _where exactly_ we are first encountering NULs in microdescriptors, and what we are doing when that happens. --- changes/diagnostic_28223_redux | 4 ++++ src/feature/dirparse/microdesc_parse.c | 17 ++++++++++++++++- src/feature/nodelist/microdesc.c | 21 +++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 changes/diagnostic_28223_redux (limited to 'changes') diff --git a/changes/diagnostic_28223_redux b/changes/diagnostic_28223_redux new file mode 100644 index 0000000000..0d7499832e --- /dev/null +++ b/changes/diagnostic_28223_redux @@ -0,0 +1,4 @@ + o Minor features (diagnostic): + - Add more diagnostic log messages in an attempt to solve + the issue of NUL bytes appearing in a microdescriptor cache. + Related to ticket 28223. diff --git a/src/feature/dirparse/microdesc_parse.c b/src/feature/dirparse/microdesc_parse.c index 5a75af3994..1e26901ce8 100644 --- a/src/feature/dirparse/microdesc_parse.c +++ b/src/feature/dirparse/microdesc_parse.c @@ -159,7 +159,22 @@ microdescs_parse_from_string(const char *s, const char *eos, if (tokenize_string(area, s, start_of_next_microdesc, tokens, microdesc_token_table, flags)) { - log_warn(LD_DIR, "Unparseable microdescriptor"); + const char *location; + switch (where) { + case SAVED_NOWHERE: + location = "download or generated string"; + break; + case SAVED_IN_CACHE: + location = "cache"; + break; + case SAVED_IN_JOURNAL: + location = "journal"; + break; + default: + location = "unknown location"; + break; + } + log_warn(LD_DIR, "Unparseable microdescriptor found in %s", location); goto next; } diff --git a/src/feature/nodelist/microdesc.c b/src/feature/nodelist/microdesc.c index dafaabb5e5..af4f608d2f 100644 --- a/src/feature/nodelist/microdesc.c +++ b/src/feature/nodelist/microdesc.c @@ -221,6 +221,13 @@ dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out) } md->off = tor_fd_getpos(fd); + const char *nulpos = memchr(md->body, 0, md->bodylen); + if (BUG(nulpos)) { + log_warn(LD_BUG, "About to dump a NUL into a microdescriptor file. " + "offset %"PRId64", bodylen %zu, nul position %zu", + (int64_t)md->off, md->bodylen, + (size_t)(nulpos - md->body)); + } written = write_all_to_fd(fd, md->body, md->bodylen); if (written != (ssize_t)md->bodylen) { written = written < 0 ? 0 : written; @@ -480,6 +487,17 @@ microdesc_cache_clear(microdesc_cache_t *cache) cache->bytes_dropped = 0; } +static void +warn_if_nul_found(const char *inp, size_t len, const char *description) +{ + const char *nul_found = memchr(inp, 0, len); + if (BUG(nul_found)) { + log_warn(LD_BUG, "Found unexpected NUL while reading %s, at " + "position %zu/%zu.", + description, (nul_found - inp), len); + } +} + /** Reload the contents of cache from disk. If it is empty, load it * for the first time. Return 0 on success, -1 on failure. */ int @@ -497,6 +515,7 @@ microdesc_cache_reload(microdesc_cache_t *cache) mm = cache->cache_content = tor_mmap_file(cache->cache_fname); if (mm) { + warn_if_nul_found(mm->data, mm->size, "microdesc cache"); added = microdescs_add_to_cache(cache, mm->data, mm->data+mm->size, SAVED_IN_CACHE, 0, -1, NULL); if (added) { @@ -509,6 +528,8 @@ microdesc_cache_reload(microdesc_cache_t *cache) RFTS_IGNORE_MISSING, &st); if (journal_content) { cache->journal_len = (size_t) st.st_size; + warn_if_nul_found(journal_content, cache->journal_len, + "microdesc journal"); added = microdescs_add_to_cache(cache, journal_content, journal_content+st.st_size, SAVED_IN_JOURNAL, 0, -1, NULL); -- cgit v1.2.3-54-g00ecf From 5613968d57cb07cc5a66e97c58bd39c22b86a50a Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 3 Apr 2019 14:30:56 -0400 Subject: Improve logging for 28614. When we fixed 28614, our answer was "if we failed to load the consensus on windows and it had a CRLF, retry it." But we logged the failure at "warn", and we only logged the retry at "info". Now we log the retry at "notice", with more useful information. Fixes bug 30004. --- changes/bug28614_better_logging | 6 ++++++ src/feature/nodelist/networkstatus.c | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 changes/bug28614_better_logging (limited to 'changes') diff --git a/changes/bug28614_better_logging b/changes/bug28614_better_logging new file mode 100644 index 0000000000..26d19c3c11 --- /dev/null +++ b/changes/bug28614_better_logging @@ -0,0 +1,6 @@ + o Minor bugfixes (logging): + - On Windows, when errors cause us to reload a consensus from disk, tell + the user that we are retrying at log level "notice". Previously we only + logged this information at "info", which was confusing because the + errors themselves were logged at "warning". Improves previous fix for + 28614. Fixes bug 30004; bugfix on 0.4.0.2-alpha. diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index 023115978c..a988f700f3 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -1761,8 +1761,11 @@ reload_consensus_from_file(const char *fname, flavor, flags, source_dir); #ifdef _WIN32 if (rv < 0 && tor_memstr(map->data, map->size, "\r\n")) { - log_info(LD_GENERAL, "Found CRLF in consensus file %s; falling back to " - "read_file_to_string.", escaped(fname)); + log_notice(LD_GENERAL, "Looks like the above failures are probably " + "because of a CRLF in consensus file %s; falling back to " + "read_file_to_string. Nothing to worry about: this file " + "was probably saved by an earlier version of Tor.", + escaped(fname)); char *content = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); rv = networkstatus_set_current_consensus(content, strlen(content), flavor, flags, source_dir); -- cgit v1.2.3-54-g00ecf From d4d77b277e72c74a47bd724531426d7f561607e4 Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Wed, 3 Apr 2019 11:36:52 -0400 Subject: Stop setting bridges running in networkstatus_getinfo_by_purpose() --- changes/bug24490 | 5 +++++ scripts/maint/practracker/exceptions.txt | 6 +++--- src/core/mainloop/mainloop.c | 25 +++++++++++++++++++++++++ src/feature/nodelist/networkstatus.c | 4 ---- 4 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 changes/bug24490 (limited to 'changes') diff --git a/changes/bug24490 b/changes/bug24490 new file mode 100644 index 0000000000..9ae09dbd17 --- /dev/null +++ b/changes/bug24490 @@ -0,0 +1,5 @@ + o Minor bugfixes (bridge authority): + - We set bridges as running in a callback which runs every 5 minutes. + Previously, we set bridges as running in a GETINFO controller as + these shouldn't modify vital data structures. Fixes bug 24490; + bugfix on 0.2.0.13-alpha. Patch by Neel Chauhan diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index ad5d3e9725..a9fcf9095a 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -67,11 +67,11 @@ problem function-size /src/core/mainloop/connection.c:connection_handle_read_imp problem function-size /src/core/mainloop/connection.c:connection_buf_read_from_socket() 177 problem function-size /src/core/mainloop/connection.c:connection_handle_write_impl() 241 problem function-size /src/core/mainloop/connection.c:assert_connection_ok() 143 -problem file-size /src/core/mainloop/mainloop.c 3051 -problem include-count /src/core/mainloop/mainloop.c 66 +problem file-size /src/core/mainloop/mainloop.c 3076 +problem include-count /src/core/mainloop/mainloop.c 68 problem function-size /src/core/mainloop/mainloop.c:conn_close_if_marked() 108 problem function-size /src/core/mainloop/mainloop.c:run_connection_housekeeping() 123 -problem function-size /src/core/mainloop/mainloop.c:CALLBACK() 116 +problem function-size /src/core/mainloop/mainloop.c:CALLBACK() 118 problem file-size /src/core/or/channel.c 3476 problem function-size /src/core/or/channeltls.c:channel_tls_handle_var_cell() 160 problem function-size /src/core/or/channeltls.c:channel_tls_process_versions_cell() 170 diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c index c9f2b0d896..800304a736 100644 --- a/src/core/mainloop/mainloop.c +++ b/src/core/mainloop/mainloop.c @@ -76,6 +76,7 @@ #include "feature/control/control_events.h" #include "feature/dirauth/authmode.h" #include "feature/dirauth/reachability.h" +#include "feature/dirauth/voteflags.h" #include "feature/dircache/consdiffmgr.h" #include "feature/dircache/dirserv.h" #include "feature/dircommon/directory.h" @@ -87,6 +88,7 @@ #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerlist_st.h" #include "feature/relay/dns.h" #include "feature/relay/routerkeys.h" #include "feature/relay/routermode.h" @@ -1375,6 +1377,7 @@ CALLBACK(rotate_onion_key); CALLBACK(rotate_x509_certificate); CALLBACK(save_stability); CALLBACK(save_state); +CALLBACK(set_bridge_running); CALLBACK(write_bridge_ns); CALLBACK(write_stats_file); CALLBACK(control_per_second_events); @@ -1453,6 +1456,7 @@ STATIC periodic_event_item_t periodic_events[] = { /* Bridge Authority only. */ CALLBACK(write_bridge_ns, BRIDGEAUTH, 0), + CALLBACK(set_bridge_running, BRIDGEAUTH, 0), /* Directory server only. */ CALLBACK(clean_consdiffmgr, DIRSERVER, 0), @@ -2583,6 +2587,27 @@ write_bridge_ns_callback(time_t now, const or_options_t *options) return PERIODIC_EVENT_NO_UPDATE; } +/** + * Periodic callback: if we're the bridge authority, set the running flag on + * bridges if they're reachable + */ +static int +set_bridge_running_callback(time_t now, const or_options_t *options) +{ + if (options->BridgeAuthoritativeDir) { + routerlist_t *rl = router_get_routerlist(); + + SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) { + if (ri->purpose == ROUTER_PURPOSE_BRIDGE) + dirserv_set_router_is_running(ri, now); + } SMARTLIST_FOREACH_END(ri); + +#define SET_BRIDGES_RUNNING_INTERVAL (3*60) + return SET_BRIDGES_RUNNING_INTERVAL; + } + return PERIODIC_EVENT_NO_UPDATE; +} + static int heartbeat_callback_first_time = 1; /** diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index ea9f12367f..bc12fa4075 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -2378,7 +2378,6 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now) smartlist_t *statuses; const uint8_t purpose = router_purpose_from_string(purpose_string); routerstatus_t rs; - const int bridge_auth = authdir_mode_bridge(get_options()); if (purpose == ROUTER_PURPOSE_UNKNOWN) { log_info(LD_DIR, "Unrecognized purpose '%s' when listing router statuses.", @@ -2395,9 +2394,6 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now) continue; if (ri->purpose != purpose) continue; - /* TODO: modifying the running flag in a getinfo is a bad idea */ - if (bridge_auth && ri->purpose == ROUTER_PURPOSE_BRIDGE) - dirserv_set_router_is_running(ri, now); /* then generate and write out status lines for each of them */ set_routerstatus_from_routerinfo(&rs, node, ri, now, 0); smartlist_add(statuses, networkstatus_getinfo_helper_single(&rs)); -- cgit v1.2.3-54-g00ecf From d194f6bedf48410132b03fdab06b679512c14db1 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sun, 17 Mar 2019 13:48:00 -0400 Subject: Implement an DormantCanceledByStartup option Closes ticket 29357, and comes with appropriate notions of caution. --- changes/ticket29357 | 7 +++++++ doc/tor.1.txt | 15 +++++++++++++++ src/app/config/config.c | 1 + src/app/config/or_options_st.h | 5 +++++ src/core/mainloop/netstatus.c | 4 ++++ src/test/test_mainloop.c | 8 ++++++++ 6 files changed, 40 insertions(+) create mode 100644 changes/ticket29357 (limited to 'changes') diff --git a/changes/ticket29357 b/changes/ticket29357 new file mode 100644 index 0000000000..3aab930cd4 --- /dev/null +++ b/changes/ticket29357 @@ -0,0 +1,7 @@ + o Minor features (dormant mode): + - Add a DormantCanceledByStartup option to tell Tor that it should + treat a startup event as cancelling any previous dormant state. + Integrators should use this option with caution: it should + only be used if Tor is being started because of something that the + user did, and not if Tor is being automatically started in the + background. Closes ticket 29357. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 52f5bfa0c3..ea9942a28d 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -1850,6 +1850,21 @@ The following options are useful only for clients (that is, if After the first time Tor starts, it begins in dormant mode if it was dormant before, and not otherwise. (Default: 0) +[[DormantCanceledByStartup]] **DormantCanceledByStartup** **0**|**1**:: + By default, Tor starts in active mode if it was active the last time + it was shut down, and in dormant mode if it was dormant. But if + this option is true, Tor treats every startup event as user + activity, and Tor will never start in Dormant mode, even if it has + been unused for a long time on previous runs. (Default: 0) + + + Note: Packagers and application developers should change the value of + this option only with great caution: it has the potential to + create spurious traffic on the network. This option should only + be used if Tor is started by an affirmative user activity (like + clicking on an applcation or running a command), and not if Tor + is launched for some other reason (for example, by a startup + process, or by an application that launches itself on every login.) + SERVER OPTIONS -------------- diff --git a/src/app/config/config.c b/src/app/config/config.c index 8e0bfbe797..dc213ce2fc 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -396,6 +396,7 @@ static config_var_t option_vars_[] = { V(DormantClientTimeout, INTERVAL, "24 hours"), V(DormantTimeoutDisabledByIdleStreams, BOOL, "1"), V(DormantOnFirstStartup, BOOL, "0"), + V(DormantCanceledByStartup, BOOL, "0"), /* DoS circuit creation options. */ V(DoSCircuitCreationEnabled, AUTOBOOL, "auto"), V(DoSCircuitCreationMinConnections, UINT, "0"), diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h index 06e11d3c75..bd707fd193 100644 --- a/src/app/config/or_options_st.h +++ b/src/app/config/or_options_st.h @@ -1092,6 +1092,11 @@ struct or_options_t { /** Boolean: true if Tor should be dormant the first time it starts with * a datadirectory; false otherwise. */ int DormantOnFirstStartup; + /** + * Boolean: true if Tor should treat every startup event as cancelling + * a possible previous dormant state. + **/ + int DormantCanceledByStartup; }; #endif diff --git a/src/core/mainloop/netstatus.c b/src/core/mainloop/netstatus.c index fc5a465ff7..4924888598 100644 --- a/src/core/mainloop/netstatus.c +++ b/src/core/mainloop/netstatus.c @@ -144,6 +144,10 @@ netstatus_load_from_state(const or_state_t *state, time_t now) last_activity = now - 60 * state->MinutesSinceUserActivity; participating_on_network = true; } + if (get_options()->DormantCanceledByStartup) { + last_activity = now; + participating_on_network = true; + } reset_user_activity(last_activity); } diff --git a/src/test/test_mainloop.c b/src/test/test_mainloop.c index 2c3449305a..ed6b8a9b66 100644 --- a/src/test/test_mainloop.c +++ b/src/test/test_mainloop.c @@ -317,6 +317,14 @@ test_mainloop_dormant_load_state(void *arg) tt_assert(is_participating_on_network()); tt_i64_op(get_last_user_activity_time(), OP_EQ, start - 123*60); + // If we would start dormant, but DormantCanceledByStartup is set, then + // we start up non-dormant. + state->Dormant = 1; + get_options_mutable()->DormantCanceledByStartup = 1; + netstatus_load_from_state(state, start); + tt_assert(is_participating_on_network()); + tt_i64_op(get_last_user_activity_time(), OP_EQ, start); + done: or_state_free(state); } -- cgit v1.2.3-54-g00ecf From 8e961b2174f6714fdff295f032abe993f864b81b Mon Sep 17 00:00:00 2001 From: teor Date: Sat, 30 Mar 2019 12:09:47 +1000 Subject: bwauth: Actually include the bandwidth-file-digest in authority votes Fixes bug 29959; bugfix on 0.4.0.2-alpha. --- changes/bug29959-040 | 3 +++ src/feature/dirauth/dirvote.c | 21 ++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 changes/bug29959-040 (limited to 'changes') diff --git a/changes/bug29959-040 b/changes/bug29959-040 new file mode 100644 index 0000000000..3740e0169a --- /dev/null +++ b/changes/bug29959-040 @@ -0,0 +1,3 @@ + o Minor bugfixes (directory authorities): + - Actually include the bandwidth-file-digest line in directory authority + votes. Fixes bug 29959; bugfix on 0.4.0.2-alpha. diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index ba7b2f1de6..29f5d04509 100644 --- a/src/feature/dirauth/dirvote.c +++ b/src/feature/dirauth/dirvote.c @@ -320,18 +320,17 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, if (!tor_digest256_is_zero((const char *)v3_ns->bw_file_digest256)) { /* Encode the digest. */ char b64_digest_bw_file[BASE64_DIGEST256_LEN+1] = {0}; - if (digest256_to_base64(b64_digest_bw_file, - (const char *)v3_ns->bw_file_digest256)>0) { - /* "bandwidth-file-digest" 1*(SP algorithm "=" digest) NL */ - char *digest_algo_b64_digest_bw_file = NULL; - tor_asprintf(&digest_algo_b64_digest_bw_file, "%s=%s", - crypto_digest_algorithm_get_name(DIGEST_ALG_BW_FILE), - b64_digest_bw_file); - /* No need for tor_strdup(""), format_line_if_present does it. */ - bw_file_digest = format_line_if_present( + digest256_to_base64(b64_digest_bw_file, + (const char *)v3_ns->bw_file_digest256); + /* "bandwidth-file-digest" 1*(SP algorithm "=" digest) NL */ + char *digest_algo_b64_digest_bw_file = NULL; + tor_asprintf(&digest_algo_b64_digest_bw_file, "%s=%s", + crypto_digest_algorithm_get_name(DIGEST_ALG_BW_FILE), + b64_digest_bw_file); + /* No need for tor_strdup(""), format_line_if_present does it. */ + bw_file_digest = format_line_if_present( "bandwidth-file-digest", digest_algo_b64_digest_bw_file); - tor_free(digest_algo_b64_digest_bw_file); - } + tor_free(digest_algo_b64_digest_bw_file); } smartlist_add_asprintf(chunks, -- cgit v1.2.3-54-g00ecf From 28db7646ba64673188be95d3204abb94ce890b86 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Mon, 4 Mar 2019 21:54:56 +0000 Subject: Changes file for bug 29500. --- changes/bug29500 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/bug29500 (limited to 'changes') diff --git a/changes/bug29500 b/changes/bug29500 new file mode 100644 index 0000000000..16550935b2 --- /dev/null +++ b/changes/bug29500 @@ -0,0 +1,3 @@ + o Minor bugfixes (circuitpadding testing): + - Minor tweaks to avoid very rare test failures related to timers and + monotime. Fixes bug 29500; bugfix on 0.4.0.1-alpha -- cgit v1.2.3-54-g00ecf From ac269d5c30d09194b6ab80232f72bfbd6fa69ed2 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 5 Apr 2019 15:16:49 +1000 Subject: changes: file for 29660 --- changes/ticket29660 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/ticket29660 (limited to 'changes') diff --git a/changes/ticket29660 b/changes/ticket29660 new file mode 100644 index 0000000000..84b8059106 --- /dev/null +++ b/changes/ticket29660 @@ -0,0 +1,5 @@ + o Code simplification and refactoring: + - Remove redundant return values in crypto_format, and the associated + return value checks elsewhere in the code. Make the implementations in + crypto_format consistent, and remove redundant code. + Resolves ticket 29660. -- cgit v1.2.3-54-g00ecf From e8e6931638a14a2c996e55d7c8342654fb546b34 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Fri, 5 Apr 2019 19:03:41 +0300 Subject: Add changes file --- changes/ticket30033 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket30033 (limited to 'changes') diff --git a/changes/ticket30033 b/changes/ticket30033 new file mode 100644 index 0000000000..3f66d049c8 --- /dev/null +++ b/changes/ticket30033 @@ -0,0 +1,4 @@ + o Minor features (developer tooling): + - Call pre-commit git hook from pre-push hook to make sure we're + running documentation and code style checks before pushing to remote + git repository. Implements feature 30033. -- cgit v1.2.3-54-g00ecf From 0e0a0b9802e7e7bf192df9c93f257913e926033a Mon Sep 17 00:00:00 2001 From: rl1987 Date: Mon, 8 Apr 2019 11:16:45 +0300 Subject: Fix SC2006 in minimize.sh --- changes/ticket30079 | 3 +++ src/test/fuzz/minimize.sh | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/ticket30079 (limited to 'changes') diff --git a/changes/ticket30079 b/changes/ticket30079 new file mode 100644 index 0000000000..56b88e7f53 --- /dev/null +++ b/changes/ticket30079 @@ -0,0 +1,3 @@ + o Code simplification and refactoring (shell scripts): + - Fix shellcheck warning SC2006 in src/test/fuzz/minimize.sh. Resolves + issue 30079. diff --git a/src/test/fuzz/minimize.sh b/src/test/fuzz/minimize.sh index 87d3dda13c..ce43812bb8 100755 --- a/src/test/fuzz/minimize.sh +++ b/src/test/fuzz/minimize.sh @@ -7,7 +7,7 @@ if [ ! -d "$1" ] ; then exit 1 fi -which=`basename "$1"` +which=$(basename "$1") mkdir "$1.out" afl-cmin -i "$1" -o "$1.out" -m none "./src/test/fuzz/fuzz-${which}" -- cgit v1.2.3-54-g00ecf From 61e6b217c5c83bc49e888f594f931c00c3e9b971 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Mon, 25 Mar 2019 15:40:46 +0200 Subject: manpage: Clarify that Tor does stream isolation between *Port listeners by default cherry-pick of tor-github/pr/841 to maint-0.4.0. --- changes/doc29121 | 3 +++ doc/tor.1.txt | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 changes/doc29121 (limited to 'changes') diff --git a/changes/doc29121 b/changes/doc29121 new file mode 100644 index 0000000000..dd31cc9c70 --- /dev/null +++ b/changes/doc29121 @@ -0,0 +1,3 @@ + o Documentation: + - Clarify that Tor performs stream isolation between *Port listeners by + default. Resolves issue 29121. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index ea9942a28d..c2df7687fe 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -1230,6 +1230,8 @@ The following options are useful only for clients (that is, if information to anybody watching your network, and allow anybody to use your computer as an open proxy. + + + If multiple entries of this option are present in your configuration + file, Tor will perform stream isolation between listeners by default. The _isolation flags_ arguments give Tor rules for which streams received on this SocksPort are allowed to share circuits with one another. Recognized isolation flags are: @@ -1472,14 +1474,18 @@ The following options are useful only for clients (that is, if protocol instead of SOCKS. Set this to 0 if you don't want to allow "HTTP CONNECT" connections. Set the port to "auto" to have Tor pick a port for you. This directive can be - specified multiple times to bind to multiple addresses/ports. See + specified multiple times to bind to multiple addresses/ports. If multiple + entries of this option are present in your configuration file, Tor will + perform stream isolation between listeners by default. See SOCKSPort for an explanation of isolation flags. (Default: 0) [[TransPort]] **TransPort** \['address':]__port__|**auto** [_isolation flags_]:: Open this port to listen for transparent proxy connections. Set this to 0 if you don't want to allow transparent proxy connections. Set the port to "auto" to have Tor pick a port for you. This directive can be - specified multiple times to bind to multiple addresses/ports. See + specified multiple times to bind to multiple addresses/ports. If multiple + entries of this option are present in your configuration file, Tor will + perform stream isolation between listeners by default. See SOCKSPort for an explanation of isolation flags. + + TransPort requires OS support for transparent proxies, such as BSDs' pf or @@ -1516,7 +1522,9 @@ The following options are useful only for clients (that is, if included in old versions of FreeBSD, etc) using the NATD protocol. Use 0 if you don't want to allow NATD connections. Set the port to "auto" to have Tor pick a port for you. This directive can be - specified multiple times to bind to multiple addresses/ports. See + specified multiple times to bind to multiple addresses/ports. If multiple + entries of this option are present in your configuration file, Tor will + perform stream isolation between listeners by default. See SocksPort for an explanation of isolation flags. + + This option is only for people who cannot use TransPort. (Default: 0) -- cgit v1.2.3-54-g00ecf From 8cfab3b7c3ed626b8f17018a627634de9b4502af Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 10 Apr 2019 16:12:56 +1000 Subject: doc: Improve the documentation for MapAddress .exit Fixes bug 30109; bugfix on 0.1.0.1-rc. --- changes/bug30109 | 3 +++ doc/tor.1.txt | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 changes/bug30109 (limited to 'changes') diff --git a/changes/bug30109 b/changes/bug30109 new file mode 100644 index 0000000000..b25aa803bb --- /dev/null +++ b/changes/bug30109 @@ -0,0 +1,3 @@ + o Minor bugfixes (documentation): + - Improve the documentation for MapAddress .exit. + Fixes bug 30109; bugfix on 0.1.0.1-rc. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index c2df7687fe..a80da23a03 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -1056,8 +1056,8 @@ The following options are useful only for clients (that is, if [[StrictNodes]] **StrictNodes** **0**|**1**:: If StrictNodes is set to 1, Tor will treat solely the ExcludeNodes option as a requirement to follow for all the circuits you generate, even if - doing so will break functionality for you (StrictNodes applies to neither - ExcludeExitNodes nor to ExitNodes, nor to MiddleNodes). If StrictNodes + doing so will break functionality for you (StrictNodes does not apply to + ExcludeExitNodes, ExitNodes, MiddleNodes, or MapAddress). If StrictNodes is set to 0, Tor will still try to avoid nodes in the ExcludeNodes list, but it will err on the side of avoiding unexpected errors. Specifically, StrictNodes 0 tells Tor that it is okay to use an excluded @@ -1153,7 +1153,9 @@ The following options are useful only for clients (that is, if "MapAddress \*.example.com \*.example.com.torserver.exit". (Note the leading "*." in each part of the directive.) You can also redirect all subdomains of a domain to a single address. For example, "MapAddress - *.example.com www.example.com". + + *.example.com www.example.com". If the specified exit is not available, + or the exit can not connect to the site, Tor will fail any connections + to the mapped address.+ + NOTES: @@ -1181,6 +1183,15 @@ The following options are useful only for clients (that is, if 4. Using a wildcard to match only part of a string (as in *ample.com) is also invalid. + 5. Tor maps hostnames and IP addresses separately. If you MapAddress + a DNS name, but use an IP address to connect, then Tor will ignore the + DNS name mapping. + + 6. MapAddress does not apply to redirects in the application protocol. + For example, HTTP redirects and alt-svc headers will ignore mappings + for the original address. You can use a wildcard mapping to handle + redirects within the same site. + [[NewCircuitPeriod]] **NewCircuitPeriod** __NUM__:: Every NUM seconds consider whether to build a new circuit. (Default: 30 seconds) -- cgit v1.2.3-54-g00ecf From 5722c6d12d75ad1ddb28c32a11aae7aed7ccf5db Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 10 Apr 2019 19:26:47 +1000 Subject: scripts: In git-pull-all.sh, also fetch the latest tor-github pull requests Implements ticket 30114. --- changes/ticket30114 | 3 +++ scripts/git/git-pull-all.sh | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 changes/ticket30114 (limited to 'changes') diff --git a/changes/ticket30114 b/changes/ticket30114 new file mode 100644 index 0000000000..a80f7f4dcf --- /dev/null +++ b/changes/ticket30114 @@ -0,0 +1,3 @@ + o Minor features (git scripts): + - In git-pull-all.sh, also fetch the latest tor-github pull requests. + Implements ticket 30114. diff --git a/scripts/git/git-pull-all.sh b/scripts/git/git-pull-all.sh index 0a4898a111..5d1d58e4bf 100755 --- a/scripts/git/git-pull-all.sh +++ b/scripts/git/git-pull-all.sh @@ -174,6 +174,19 @@ function fetch_origin fi } +# Fetch tor-github pull requests. No arguments. +function fetch_tor_github +{ + local cmd="git fetch tor-github" + printf " %s Fetching tor-github..." "$MARKER" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + ############### # Entry point # ############### @@ -188,8 +201,11 @@ while getopts "n" opt; do esac done -# First, fetch the origin. +# First, fetch tor-github. goto_repo "$ORIGIN_PATH" +fetch_tor_github + +# Then, fetch the origin. fetch_origin # Go over all configured worktree. -- cgit v1.2.3-54-g00ecf From 011307dd5fa608739456b98d259b013286320b91 Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Thu, 11 Apr 2019 15:20:31 -0400 Subject: Make repeated/rate limited HSFETCH queries fail with QUERY_RATE_LIMITED --- changes/bug28269 | 7 +++++++ src/feature/hs/hs_client.c | 2 +- src/feature/hs/hs_common.c | 20 ++++++++++++++++---- src/feature/hs/hs_common.h | 2 +- src/feature/rend/rendclient.c | 9 ++++++--- src/test/test_hs.c | 10 ++++++++++ 6 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 changes/bug28269 (limited to 'changes') diff --git a/changes/bug28269 b/changes/bug28269 new file mode 100644 index 0000000000..bdfe9e1aae --- /dev/null +++ b/changes/bug28269 @@ -0,0 +1,7 @@ + o Minor bugfixes (onion services): + - If we are launching repeated HSFETCH queries and are rate-limited, + we introduce a new controller response QUERY_RATE_LIMITED instead + of QUERY_NO_HSDIR, while keeping the latter for when onion service + directories are missing a descriptor. Previously, we returned + QUERY_NO_HSDIR for both cases. Fixes bug 28269; bugfix on + 0.3.1.1-alpha. Patch by Neel Chauhan diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c index c34271efca..b4b9f0a948 100644 --- a/src/feature/hs/hs_client.c +++ b/src/feature/hs/hs_client.c @@ -434,7 +434,7 @@ pick_hsdir_v3(const ed25519_public_key_t *onion_identity_pk) /* Pick an HSDir from the responsible ones. The ownership of * responsible_hsdirs is given to this function so no need to free it. */ - hsdir_rs = hs_pick_hsdir(responsible_hsdirs, base64_blinded_pubkey); + hsdir_rs = hs_pick_hsdir(responsible_hsdirs, base64_blinded_pubkey, NULL); return hsdir_rs; } diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c index b2227432d2..cffec2b878 100644 --- a/src/feature/hs/hs_common.c +++ b/src/feature/hs/hs_common.c @@ -1589,20 +1589,25 @@ hs_purge_last_hid_serv_requests(void) /** Given the list of responsible HSDirs in responsible_dirs, pick the * one that we should use to fetch a descriptor right now. Take into account * previous failed attempts at fetching this descriptor from HSDirs using the - * string identifier req_key_str. + * string identifier req_key_str. We return whether we are rate limited + * into *is_rate_limited if it is not NULL. * * Steals ownership of responsible_dirs. * * Return the routerstatus of the chosen HSDir if successful, otherwise return * NULL if no HSDirs are worth trying right now. */ routerstatus_t * -hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str) +hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str, + int *is_rate_limited) { smartlist_t *usable_responsible_dirs = smartlist_new(); const or_options_t *options = get_options(); routerstatus_t *hs_dir; time_t now = time(NULL); int excluded_some; + int rate_limited; + int rate_limited_count = 0; + int responsible_dirs_count = smartlist_len(responsible_dirs); tor_assert(req_key_str); @@ -1622,6 +1627,7 @@ hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str) if (last + hs_hsdir_requery_period(options) >= now || !node || !node_has_preferred_descriptor(node, 0)) { SMARTLIST_DEL_CURRENT(responsible_dirs, dir); + rate_limited_count++; continue; } if (!routerset_contains_node(options->ExcludeNodes, node)) { @@ -1629,6 +1635,7 @@ hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str) } } SMARTLIST_FOREACH_END(dir); + rate_limited = rate_limited_count == responsible_dirs_count; excluded_some = smartlist_len(usable_responsible_dirs) < smartlist_len(responsible_dirs); @@ -1640,9 +1647,10 @@ hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str) smartlist_free(responsible_dirs); smartlist_free(usable_responsible_dirs); if (!hs_dir) { + const char *warn_str = (rate_limited) ? "we are rate limited." : + "we requested them all recently without success"; log_info(LD_REND, "Could not pick one of the responsible hidden " - "service directories, because we requested them all " - "recently without success."); + "service directories, because %s.", warn_str); if (options->StrictNodes && excluded_some) { log_warn(LD_REND, "Could not pick a hidden service directory for the " "requested hidden service: they are all either down or " @@ -1654,6 +1662,10 @@ hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str) hs_lookup_last_hid_serv_request(hs_dir, req_key_str, now, 1); } + if (is_rate_limited != NULL) { + *is_rate_limited = rate_limited; + } + return hs_dir; } diff --git a/src/feature/hs/hs_common.h b/src/feature/hs/hs_common.h index abf39fa431..f96fc8beb7 100644 --- a/src/feature/hs/hs_common.h +++ b/src/feature/hs/hs_common.h @@ -241,7 +241,7 @@ void hs_get_responsible_hsdirs(const struct ed25519_public_key_t *blinded_pk, int use_second_hsdir_index, int for_fetching, smartlist_t *responsible_dirs); routerstatus_t *hs_pick_hsdir(smartlist_t *responsible_dirs, - const char *req_key_str); + const char *req_key_str, int *is_rate_limited); time_t hs_hsdir_requery_period(const or_options_t *options); time_t hs_lookup_last_hid_serv_request(routerstatus_t *hs_dir, diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c index 5a8b234544..9863fc1c11 100644 --- a/src/feature/rend/rendclient.c +++ b/src/feature/rend/rendclient.c @@ -469,16 +469,19 @@ directory_get_from_hs_dir(const char *desc_id, /* Automatically pick an hs dir if none given. */ if (!rs_hsdir) { + int rate_limited; + /* Determine responsible dirs. Even if we can't get all we want, work with * the ones we have. If it's empty, we'll notice in hs_pick_hsdir(). */ smartlist_t *responsible_dirs = smartlist_new(); hid_serv_get_responsible_directories(responsible_dirs, desc_id); - hs_dir = hs_pick_hsdir(responsible_dirs, desc_id_base32); + hs_dir = hs_pick_hsdir(responsible_dirs, desc_id_base32, &rate_limited); if (!hs_dir) { /* No suitable hs dir can be found, stop right now. */ - control_event_hsv2_descriptor_failed(rend_query, NULL, - "QUERY_NO_HSDIR"); + const char *query_response = (rate_limited) ? "QUERY_RATE_LIMITED" : + "QUERY_NO_HSDIR"; + control_event_hsv2_descriptor_failed(rend_query, NULL, query_response); control_event_hs_descriptor_content(rend_data_get_address(rend_query), desc_id_base32, NULL, NULL); return 0; diff --git a/src/test/test_hs.c b/src/test/test_hs.c index aeb3387471..5d3327c777 100644 --- a/src/test/test_hs.c +++ b/src/test/test_hs.c @@ -323,6 +323,16 @@ test_hs_desc_event(void *arg) tt_str_op(received_msg,OP_EQ, expected_msg); tor_free(received_msg); + /* test HSDir rate limited */ + rend_query.auth_type = REND_NO_AUTH; + control_event_hsv2_descriptor_failed(&rend_query.base_, NULL, + "QUERY_RATE_LIMITED"); + expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" NO_AUTH " \ + "UNKNOWN REASON=QUERY_RATE_LIMITED\r\n"; + tt_assert(received_msg); + tt_str_op(received_msg,OP_EQ, expected_msg); + tor_free(received_msg); + /* Test invalid content with no HSDir fingerprint. */ char *exp_msg; control_event_hs_descriptor_content(rend_query.onion_address, -- cgit v1.2.3-54-g00ecf From e39b53ef7de4ac6705869fd153da7b0f87c48ee6 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 11 Apr 2019 17:59:21 -0400 Subject: changes file and practracker updates for 30147. --- changes/coverity_falsepos | 4 ++++ scripts/maint/practracker/exceptions.txt | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 changes/coverity_falsepos (limited to 'changes') diff --git a/changes/coverity_falsepos b/changes/coverity_falsepos new file mode 100644 index 0000000000..9fbb01a0c1 --- /dev/null +++ b/changes/coverity_falsepos @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Refactor several places in our code that coverity incorrectly believed + that we might have memory leaks, so that we can analyze our software + more easily. Closes ticket 30147. diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index 7d03bf27d6..b84396272d 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -119,7 +119,7 @@ problem function-size /src/core/or/connection_or.c:connection_or_client_learned_ problem function-size /src/core/or/connection_or.c:connection_or_compute_authenticate_cell_body() 235 problem file-size /src/core/or/policies.c 3163 problem function-size /src/core/or/policies.c:policy_summarize() 107 -problem function-size /src/core/or/protover.c:protover_all_supported() 116 +problem function-size /src/core/or/protover.c:protover_all_supported() 117 problem file-size /src/core/or/relay.c 3173 problem function-size /src/core/or/relay.c:circuit_receive_relay_cell() 123 problem function-size /src/core/or/relay.c:relay_send_command_from_edge_() 101 @@ -245,7 +245,7 @@ problem function-size /src/feature/rend/rendmid.c:rend_mid_establish_intro_legac problem function-size /src/feature/rend/rendparse.c:rend_parse_v2_service_descriptor() 187 problem function-size /src/feature/rend/rendparse.c:rend_decrypt_introduction_points() 104 problem function-size /src/feature/rend/rendparse.c:rend_parse_introduction_points() 131 -problem file-size /src/feature/rend/rendservice.c 4509 +problem file-size /src/feature/rend/rendservice.c 4510 problem function-size /src/feature/rend/rendservice.c:rend_service_prune_list_impl_() 107 problem function-size /src/feature/rend/rendservice.c:rend_config_service() 164 problem function-size /src/feature/rend/rendservice.c:rend_service_load_auth_keys() 178 @@ -256,7 +256,7 @@ problem function-size /src/feature/rend/rendservice.c:rend_service_intro_has_ope problem function-size /src/feature/rend/rendservice.c:rend_service_rendezvous_has_opened() 117 problem function-size /src/feature/rend/rendservice.c:directory_post_to_hs_dir() 108 problem function-size /src/feature/rend/rendservice.c:upload_service_descriptor() 111 -problem function-size /src/feature/rend/rendservice.c:rend_consider_services_intro_points() 169 +problem function-size /src/feature/rend/rendservice.c:rend_consider_services_intro_points() 170 problem function-size /src/feature/stats/rephist.c:rep_hist_load_mtbf_data() 185 problem function-size /src/feature/stats/rephist.c:rep_hist_format_exit_stats() 148 problem function-size /src/lib/compress/compress.c:tor_compress_impl() 133 -- cgit v1.2.3-54-g00ecf From 73323460023807259d3cd1dd52d33749ffe53886 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 11 Apr 2019 18:58:44 -0400 Subject: Changes file and practracker updates for 30149. --- changes/ticket30149 | 3 +++ scripts/maint/practracker/exceptions.txt | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/ticket30149 (limited to 'changes') diff --git a/changes/ticket30149 b/changes/ticket30149 new file mode 100644 index 0000000000..a21687ac2f --- /dev/null +++ b/changes/ticket30149 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Add several assertions in an attempt to fix some Coverity warnings. + Closes ticket 30149. diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index 7d03bf27d6..ecc58012c6 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -218,7 +218,7 @@ problem include-count /src/feature/nodelist/networkstatus.c 61 problem function-size /src/feature/nodelist/networkstatus.c:networkstatus_check_consensus_signature() 176 problem function-size /src/feature/nodelist/networkstatus.c:networkstatus_set_current_consensus() 293 problem function-size /src/feature/nodelist/node_select.c:router_pick_directory_server_impl() 123 -problem function-size /src/feature/nodelist/node_select.c:compute_weighted_bandwidths() 205 +problem function-size /src/feature/nodelist/node_select.c:compute_weighted_bandwidths() 206 problem function-size /src/feature/nodelist/node_select.c:router_pick_trusteddirserver_impl() 114 problem function-size /src/feature/nodelist/nodelist.c:compute_frac_paths_available() 193 problem file-size /src/feature/nodelist/routerlist.c 3234 -- cgit v1.2.3-54-g00ecf From cdafcc49bc273e472d40ea8c01219bbc165c92cb Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 11 Apr 2019 19:09:23 -0400 Subject: Fix a memory leak in tor-resolve.c Closes bug 30151/coverity CID 1441830. Bugfix on 0.4.0.1-alpha when we started doing trunnel parsing in tor-resolve.c. --- changes/bug30151 | 5 +++++ src/tools/tor-resolve.c | 1 + 2 files changed, 6 insertions(+) create mode 100644 changes/bug30151 (limited to 'changes') diff --git a/changes/bug30151 b/changes/bug30151 new file mode 100644 index 0000000000..8ac9a320a0 --- /dev/null +++ b/changes/bug30151 @@ -0,0 +1,5 @@ + o Minor bugfixes (tor-resolve): + - Fix a memory leak in tor-resolve that could happen if Tor gave it a + malformed SOCKS response. (Memory leaks in tor-resolve don't actually + matter, but it's good to fix them anyway.) Fixes bug 30151; bugfix on + 0.4.0.1-alpha. diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c index 98b3a4a74c..5d97696c18 100644 --- a/src/tools/tor-resolve.c +++ b/src/tools/tor-resolve.c @@ -424,6 +424,7 @@ do_resolve(const char *hostname, if (parsed < 2) { log_err(LD_NET, "Failed to parse SOCKS5 method selection " "message"); + socks5_server_method_free(m); goto err; } -- cgit v1.2.3-54-g00ecf From e16f5184dad6d0052df37496327e2652d9c79d00 Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Thu, 11 Apr 2019 20:32:38 -0400 Subject: Fix grammar in bug24490 changes file --- changes/bug24490 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'changes') diff --git a/changes/bug24490 b/changes/bug24490 index 9ae09dbd17..1167e9f8d3 100644 --- a/changes/bug24490 +++ b/changes/bug24490 @@ -1,5 +1,5 @@ o Minor bugfixes (bridge authority): - We set bridges as running in a callback which runs every 5 minutes. - Previously, we set bridges as running in a GETINFO controller as + Previously, we set bridges as running in a GETINFO controller, but these shouldn't modify vital data structures. Fixes bug 24490; bugfix on 0.2.0.13-alpha. Patch by Neel Chauhan -- cgit v1.2.3-54-g00ecf From c07d854772bda558ef8cf4fd71f2673c7ed00083 Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Thu, 11 Apr 2019 21:28:35 -0400 Subject: Remove callback for setting bridges as running --- changes/bug24490 | 2 +- scripts/maint/practracker/exceptions.txt | 8 ++++---- src/core/mainloop/mainloop.c | 20 -------------------- src/feature/nodelist/networkstatus.c | 5 ++++- 4 files changed, 9 insertions(+), 26 deletions(-) (limited to 'changes') diff --git a/changes/bug24490 b/changes/bug24490 index 1167e9f8d3..cf9281c878 100644 --- a/changes/bug24490 +++ b/changes/bug24490 @@ -1,5 +1,5 @@ o Minor bugfixes (bridge authority): - - We set bridges as running in a callback which runs every 5 minutes. + - We set bridges as running when we dump the bridge status to a file. Previously, we set bridges as running in a GETINFO controller, but these shouldn't modify vital data structures. Fixes bug 24490; bugfix on 0.2.0.13-alpha. Patch by Neel Chauhan diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index 7b06683eb7..ad5d3e9725 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -67,11 +67,11 @@ problem function-size /src/core/mainloop/connection.c:connection_handle_read_imp problem function-size /src/core/mainloop/connection.c:connection_buf_read_from_socket() 177 problem function-size /src/core/mainloop/connection.c:connection_handle_write_impl() 241 problem function-size /src/core/mainloop/connection.c:assert_connection_ok() 143 -problem file-size /src/core/mainloop/mainloop.c 3071 -problem include-count /src/core/mainloop/mainloop.c 68 +problem file-size /src/core/mainloop/mainloop.c 3051 +problem include-count /src/core/mainloop/mainloop.c 66 problem function-size /src/core/mainloop/mainloop.c:conn_close_if_marked() 108 problem function-size /src/core/mainloop/mainloop.c:run_connection_housekeeping() 123 -problem function-size /src/core/mainloop/mainloop.c:CALLBACK() 118 +problem function-size /src/core/mainloop/mainloop.c:CALLBACK() 116 problem file-size /src/core/or/channel.c 3476 problem function-size /src/core/or/channeltls.c:channel_tls_handle_var_cell() 160 problem function-size /src/core/or/channeltls.c:channel_tls_process_versions_cell() 170 @@ -276,7 +276,7 @@ problem function-size /src/lib/net/resolve.c:tor_addr_lookup() 110 problem function-size /src/lib/net/socketpair.c:tor_ersatz_socketpair() 102 problem function-size /src/lib/osinfo/uname.c:get_uname() 116 problem function-size /src/lib/process/process_unix.c:process_unix_exec() 220 -problem function-size /src/lib/process/process_win32.c:process_win32_exec() 133 +problem function-size /src/lib/process/process_win32.c:process_win32_exec() 138 problem function-size /src/lib/process/process_win32.c:process_win32_create_pipe() 112 problem function-size /src/lib/process/restrict.c:set_max_file_descriptors() 102 problem function-size /src/lib/process/setuid.c:switch_id() 156 diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c index e845ff416e..c9f2b0d896 100644 --- a/src/core/mainloop/mainloop.c +++ b/src/core/mainloop/mainloop.c @@ -76,7 +76,6 @@ #include "feature/control/control_events.h" #include "feature/dirauth/authmode.h" #include "feature/dirauth/reachability.h" -#include "feature/dirauth/voteflags.h" #include "feature/dircache/consdiffmgr.h" #include "feature/dircache/dirserv.h" #include "feature/dircommon/directory.h" @@ -88,7 +87,6 @@ #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerlist.h" -#include "feature/nodelist/routerlist_st.h" #include "feature/relay/dns.h" #include "feature/relay/routerkeys.h" #include "feature/relay/routermode.h" @@ -1377,7 +1375,6 @@ CALLBACK(rotate_onion_key); CALLBACK(rotate_x509_certificate); CALLBACK(save_stability); CALLBACK(save_state); -CALLBACK(set_bridge_running); CALLBACK(write_bridge_ns); CALLBACK(write_stats_file); CALLBACK(control_per_second_events); @@ -1456,7 +1453,6 @@ STATIC periodic_event_item_t periodic_events[] = { /* Bridge Authority only. */ CALLBACK(write_bridge_ns, BRIDGEAUTH, 0), - CALLBACK(set_bridge_running, BRIDGEAUTH, 0), /* Directory server only. */ CALLBACK(clean_consdiffmgr, DIRSERVER, 0), @@ -2587,22 +2583,6 @@ write_bridge_ns_callback(time_t now, const or_options_t *options) return PERIODIC_EVENT_NO_UPDATE; } -/** - * Periodic callback: if we're the bridge authority, set the running flag on - * bridges if they're reachable - */ -static int -set_bridge_running_callback(time_t now, const or_options_t *options) -{ - if (authdir_mode_bridge(options)) { - dirserv_set_bridges_running(now); - -#define SET_BRIDGES_RUNNING_INTERVAL (5*60) - return SET_BRIDGES_RUNNING_INTERVAL; - } - return PERIODIC_EVENT_NO_UPDATE; -} - static int heartbeat_callback_first_time = 1; /** diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index bc12fa4075..20881112aa 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -2409,7 +2409,7 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now) void networkstatus_dump_bridge_status_to_file(time_t now) { - char *status = networkstatus_getinfo_by_purpose("bridge", now); + char *status; char *fname = NULL; char *thresholds = NULL; char *published_thresholds_and_status = NULL; @@ -2418,6 +2418,9 @@ networkstatus_dump_bridge_status_to_file(time_t now) char fingerprint[FINGERPRINT_LEN+1]; char *fingerprint_line = NULL; + dirserv_set_bridges_running(now); + status = networkstatus_getinfo_by_purpose("bridge", now); + if (me && crypto_pk_get_fingerprint(me->identity_pkey, fingerprint, 0) >= 0) { tor_asprintf(&fingerprint_line, "fingerprint %s\n", fingerprint); -- cgit v1.2.3-54-g00ecf From db52180abe2bc9e82c7ce44d278af7e408974b12 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Fri, 12 Apr 2019 22:43:49 +0300 Subject: Add changes file --- changes/ticket30077 | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 changes/ticket30077 (limited to 'changes') diff --git a/changes/ticket30077 b/changes/ticket30077 new file mode 100644 index 0000000000..9be014730e --- /dev/null +++ b/changes/ticket30077 @@ -0,0 +1,2 @@ + o Code simplification and refactoring (shell scripts): + - Fix shellcheck warnings in fuzz_multi.sh. Resolves issue 30077. -- cgit v1.2.3-54-g00ecf From e7288111101b2a0fe74ec87a314d6d33c1a2920a Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Thu, 11 Apr 2019 20:22:46 -0400 Subject: Add changes file for Bug #29613 --- changes/bug29613 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/bug29613 (limited to 'changes') diff --git a/changes/bug29613 b/changes/bug29613 new file mode 100644 index 0000000000..e966973255 --- /dev/null +++ b/changes/bug29613 @@ -0,0 +1,5 @@ + o Minor bugfixes (relay): + - If we are are a relay and have IPv6Exit to 1 while ExitRelay is + auto, we act as if ExitRelay is 1. Previously, we ignored IPv6Exit + if ExitRelay was 0 or auto. Fixes bug 29613; bugfix on 0.3.5.1-alpha. + Patch by Neel Chauhan. -- cgit v1.2.3-54-g00ecf From 55b4f02ba6cbbd4cae942a9e84e48e237d8e38aa Mon Sep 17 00:00:00 2001 From: rl1987 Date: Mon, 15 Apr 2019 12:13:35 +0300 Subject: Fix shellcheck warnings in fixup_filenames.sh --- changes/ticket30078 | 3 +++ src/test/fuzz/fixup_filenames.sh | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 changes/ticket30078 (limited to 'changes') diff --git a/changes/ticket30078 b/changes/ticket30078 new file mode 100644 index 0000000000..5ab5abdbfd --- /dev/null +++ b/changes/ticket30078 @@ -0,0 +1,3 @@ + o Code simplification and refactoring (shell scripts): + - Fix shellcheck warnings in src/test/fuzz/fixup_filenames.sh. Resolves + issue 30078. diff --git a/src/test/fuzz/fixup_filenames.sh b/src/test/fuzz/fixup_filenames.sh index 68efc1abc5..f730d532a5 100755 --- a/src/test/fuzz/fixup_filenames.sh +++ b/src/test/fuzz/fixup_filenames.sh @@ -8,9 +8,9 @@ if [ ! -d "$1" ] ; then fi for fn in "$1"/* ; do - prev=`basename "$fn"` - post=`sha256sum "$fn" | sed -e 's/ .*//;'` - if [ "$prev" == "$post" ] ; then + prev=$(basename "$fn") + post=$(sha256sum "$fn" | sed -e 's/ .*//;') + if [ "$prev" = "$post" ] ; then echo "OK $prev" else echo "mv $prev $post" -- cgit v1.2.3-54-g00ecf From 670d0f9f5bb7d73ad236a035ed7bd69e96cadd41 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Sat, 13 Apr 2019 16:55:36 +0200 Subject: Clear memory in smartlist_remove_keeporder. The smartlist functions take great care to reset unused pointers inside the smartlist memory to NULL. The function smartlist_remove_keeporder does not clear memory in such way when elements have been removed. Therefore call memset after the for-loop that removes elements. If no element is removed, it is effectively a no-op. Signed-off-by: Tobias Stoeckmann --- changes/ticket30176 | 4 ++++ src/lib/smartlist_core/smartlist_core.c | 2 ++ 2 files changed, 6 insertions(+) create mode 100644 changes/ticket30176 (limited to 'changes') diff --git a/changes/ticket30176 b/changes/ticket30176 new file mode 100644 index 0000000000..da23760ce5 --- /dev/null +++ b/changes/ticket30176 @@ -0,0 +1,4 @@ + o Minor features (defense in depth): + - In smartlist_remove_keeporder(), set any pointers that become + unused to NULL, in case a bug causes them to be used later. Closes + ticket 30176. Patch from Tobias Stoeckmann. diff --git a/src/lib/smartlist_core/smartlist_core.c b/src/lib/smartlist_core/smartlist_core.c index 5947e76271..6b0a305a93 100644 --- a/src/lib/smartlist_core/smartlist_core.c +++ b/src/lib/smartlist_core/smartlist_core.c @@ -177,6 +177,8 @@ smartlist_remove_keeporder(smartlist_t *sl, const void *element) sl->list[i++] = sl->list[j]; } } + memset(sl->list + sl->num_used, 0, + sizeof(void *) * (num_used_orig - sl->num_used)); } /** If sl is nonempty, remove and return the final element. Otherwise, -- cgit v1.2.3-54-g00ecf From 37d7daa3cd22a7dce833e09392bcdbadf6e047f1 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 17 Apr 2019 12:34:33 +1000 Subject: changes: update the changes file for 30001 --- changes/bug30001 | 3 +++ 1 file changed, 3 insertions(+) (limited to 'changes') diff --git a/changes/bug30001 b/changes/bug30001 index e3304701e7..52e58872ef 100644 --- a/changes/bug30001 +++ b/changes/bug30001 @@ -2,3 +2,6 @@ - Use the approx_time() function when setting the "Expires" header in directory replies, to make them more testable. Needed for ticket 30001. + o Minor bug fixes (testing): + - Check the time in the "Expires" header with approx_time(). + Fixes bug 30001; bugfix on 0.4.0.4-rc. -- cgit v1.2.3-54-g00ecf From 728d20ed08122d2f34b001217faa009040fb2fee Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 17 Apr 2019 17:58:40 +1000 Subject: connection_edge: Return a web page when HTTPTunnelPort is misconfigured Return an informative web page when the HTTPTunnelPort is used as an HTTP proxy. Closes ticket 27821, patch by "eighthave". --- changes/ticket27821 | 3 +++ src/core/or/connection_edge.c | 27 ++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 changes/ticket27821 (limited to 'changes') diff --git a/changes/ticket27821 b/changes/ticket27821 new file mode 100644 index 0000000000..158f308fbf --- /dev/null +++ b/changes/ticket27821 @@ -0,0 +1,3 @@ + o Minor features (HTTP tunnel): + - Return an informative web page when the HTTPTunnelPort is used as an + HTTP proxy. Closes ticket 27821, patch by "eighthave". diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c index 071a8c91ed..4f7cbafe07 100644 --- a/src/core/or/connection_edge.c +++ b/src/core/or/connection_edge.c @@ -2810,6 +2810,31 @@ connection_ap_process_natd(entry_connection_t *conn) return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); } +static const char HTTP_CONNECT_IS_NOT_AN_HTTP_PROXY_MSG[] = + "HTTP/1.0 405 Method Not Allowed\r\n"; + "Content-Type: text/html; charset=iso-8859-1\r\n\r\n" + "\n" + "\n" + "This is an HTTP CONNECT tunnel, not an full HTTP Proxy\n" + "\n" + "\n" + "

This is an HTTP CONNECT tunnel, not an HTTP proxy.

\n" + "

\n" + "It appears you have configured your web browser to use this Tor port as\n" + "an HTTP proxy.\n" + "

\n" + "This is not correct: This port is configured as a CONNECT tunnel, not\n" + "an HTTP proxy. Please configure your client accordingly. You can also\n" + "use HTTPS, then the client should automatically use HTTP CONNECT." + "

\n" + "

\n" + "See " + "https://www.torproject.org/documentation.html for more " + "information.\n" + "

\n" + "\n" + "\n"; + /** Called on an HTTP CONNECT entry connection when some bytes have arrived, * but we have not yet received a full HTTP CONNECT request. Try to parse an * HTTP CONNECT request from the connection's inbuf. On success, set up the @@ -2850,7 +2875,7 @@ connection_ap_process_http_connect(entry_connection_t *conn) tor_assert(command); tor_assert(addrport); if (strcasecmp(command, "connect")) { - errmsg = "HTTP/1.0 405 Method Not Allowed\r\n\r\n"; + errmsg = HTTP_CONNECT_IS_NOT_AN_HTTP_PROXY_MSG; goto err; } -- cgit v1.2.3-54-g00ecf From 0d88b808e93fd20a3690061d781fe896ad9e2084 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Wed, 17 Apr 2019 13:15:02 +0300 Subject: Remove contrib/dist/tor.sh.in --- changes/ticket30075 | 3 ++ configure.ac | 1 - contrib/dist/tor.sh.in | 123 ------------------------------------------------- contrib/include.am | 1 - 4 files changed, 3 insertions(+), 125 deletions(-) create mode 100644 changes/ticket30075 delete mode 100644 contrib/dist/tor.sh.in (limited to 'changes') diff --git a/changes/ticket30075 b/changes/ticket30075 new file mode 100644 index 0000000000..288abd7674 --- /dev/null +++ b/changes/ticket30075 @@ -0,0 +1,3 @@ + o Removed features: + - Remove the obsolete script at contrib/dist/tor.sh.in. Resolves issue + 30075. diff --git a/configure.ac b/configure.ac index 0b80669f03..3ea578bbba 100644 --- a/configure.ac +++ b/configure.ac @@ -2459,7 +2459,6 @@ AC_CONFIG_FILES([ config.rust contrib/dist/suse/tor.sh contrib/operator-tools/tor.logrotate - contrib/dist/tor.sh contrib/dist/torctl contrib/dist/tor.service src/config/torrc.sample diff --git a/contrib/dist/tor.sh.in b/contrib/dist/tor.sh.in deleted file mode 100644 index 92f890681f..0000000000 --- a/contrib/dist/tor.sh.in +++ /dev/null @@ -1,123 +0,0 @@ -#!/bin/sh -# -# tor The Onion Router -# -# Startup/shutdown script for tor. This is a wrapper around torctl; -# torctl does the actual work in a relatively system-independent, or at least -# distribution-independent, way, and this script deals with fitting the -# whole thing into the conventions of the particular system at hand. -# This particular script is written for Red Hat/Fedora Linux, and may -# also work on Mandrake, but not SuSE. -# -# These next couple of lines "declare" tor for the "chkconfig" program, -# originally from SGI, used on Red Hat/Fedora and probably elsewhere. -# -# chkconfig: 2345 90 10 -# description: Onion Router - A low-latency anonymous proxy -# - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/sbin/tor -NAME=tor -DESC="tor daemon" -TORPIDDIR=/var/run/tor -TORPID=$TORPIDDIR/tor.pid -WAITFORDAEMON=60 -ARGS="" - -# Library functions -if [ -f /etc/rc.d/init.d/functions ]; then - . /etc/rc.d/init.d/functions -elif [ -f /etc/init.d/functions ]; then - . /etc/init.d/functions -fi - -TORCTL=@BINDIR@/torctl - -# torctl will use these environment variables -TORUSER=@TORUSER@ -export TORUSER - -if [ -x /bin/su ] ; then - SUPROG=/bin/su -elif [ -x /sbin/su ] ; then - SUPROG=/sbin/su -elif [ -x /usr/bin/su ] ; then - SUPROG=/usr/bin/su -elif [ -x /usr/sbin/su ] ; then - SUPROG=/usr/sbin/su -else - SUPROG=/bin/su -fi - -# Raise ulimit based on number of file descriptors available (thanks, Debian) - -if [ -r /proc/sys/fs/file-max ]; then - system_max=`cat /proc/sys/fs/file-max` - if [ "$system_max" -gt "80000" ] ; then - MAX_FILEDESCRIPTORS=32768 - elif [ "$system_max" -gt "40000" ] ; then - MAX_FILEDESCRIPTORS=16384 - elif [ "$system_max" -gt "10000" ] ; then - MAX_FILEDESCRIPTORS=8192 - else - MAX_FILEDESCRIPTORS=1024 - cat << EOF - -Warning: Your system has very few filedescriptors available in total. - -Maybe you should try raising that by adding 'fs.file-max=100000' to your -/etc/sysctl.conf file. Feel free to pick any number that you deem appropriate. -Then run 'sysctl -p'. See /proc/sys/fs/file-max for the current value, and -file-nr in the same directory for how many of those are used at the moment. - -EOF - fi -else - MAX_FILEDESCRIPTORS=8192 -fi - -NICE="" - -case "$1" in - - start) - if [ -n "$MAX_FILEDESCRIPTORS" ]; then - echo -n "Raising maximum number of filedescriptors (ulimit -n) to $MAX_FILEDESCRIPTORS" - if ulimit -n "$MAX_FILEDESCRIPTORS" ; then - echo "." - else - echo ": FAILED." - fi - fi - - action $"Starting tor:" $TORCTL start - RETVAL=$? - ;; - - stop) - action $"Stopping tor:" $TORCTL stop - RETVAL=$? - ;; - - restart) - action $"Restarting tor:" $TORCTL restart - RETVAL=$? - ;; - - reload) - action $"Reloading tor:" $TORCTL reload - RETVAL=$? - ;; - - status) - $TORCTL status - RETVAL=$? - ;; - - *) - echo "Usage: $0 (start|stop|restart|reload|status)" - RETVAL=1 -esac - -exit $RETVAL diff --git a/contrib/include.am b/contrib/include.am index 742bc58163..9f4775632c 100644 --- a/contrib/include.am +++ b/contrib/include.am @@ -4,7 +4,6 @@ EXTRA_DIST+= \ contrib/client-tools/torify \ contrib/dist/rc.subr \ contrib/dist/suse/tor.sh.in \ - contrib/dist/tor.sh \ contrib/dist/torctl \ contrib/dist/tor.service.in \ contrib/operator-tools/tor-exit-notice.html \ -- cgit v1.2.3-54-g00ecf From ac5753d3ca943982290d24899a2c4d406098424a Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 23 Apr 2019 10:03:18 +1000 Subject: Coding Standards: Document how to find git commits Document how to find git commits and tags for bug fixes in CodingStandards.md. And update some changes file documentation. Closes ticket 30261. --- changes/ticket30261 | 4 ++++ doc/HACKING/CodingStandards.md | 41 +++++++++++++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 changes/ticket30261 (limited to 'changes') diff --git a/changes/ticket30261 b/changes/ticket30261 new file mode 100644 index 0000000000..e4a2643c88 --- /dev/null +++ b/changes/ticket30261 @@ -0,0 +1,4 @@ + o Documentation: + - Document how to find git commits and tags for bug fixes in + CodingStandards.md. And update some changes file documentation. + Closes ticket 30261. diff --git a/doc/HACKING/CodingStandards.md b/doc/HACKING/CodingStandards.md index 4f229348e4..74db2a39a3 100644 --- a/doc/HACKING/CodingStandards.md +++ b/doc/HACKING/CodingStandards.md @@ -110,12 +110,41 @@ it's a bugfix, mention what bug it fixes and when the bug was introduced. To find out which Git tag the change was introduced in, you can use `git describe --contains `. -If at all possible, try to create this file in the same commit where you are -making the change. Please give it a distinctive name that no other branch will -use for the lifetime of your change. To verify the format of the changes file, -you can use `make check-changes`. This is run automatically as part of -`make check` -- if it fails, we must fix it before we release. These -checks are implemented in `scripts/maint/lintChanges.py`. +If you don't know the commit, you can search the git diffs (-S) for the first +instance of the feature (--reverse). + +For example, for #30224, we wanted to know when the bridge-distribution-request +feature was introduced into Tor: + $ git log -S bridge-distribution-request --reverse + commit ebab521525 + Author: Roger Dingledine + Date: Sun Nov 13 02:39:16 2016 -0500 + + Add new BridgeDistribution config option + + $ git describe --contains ebab521525 + tor-0.3.2.3-alpha~15^2~4 + +If you need to know all the Tor versions that contain a commit, use: + $ git tag --contains 9f2efd02a1 | sort -V + tor-0.2.5.16 + tor-0.2.8.17 + tor-0.2.9.14 + tor-0.2.9.15 + ... + tor-0.3.0.13 + tor-0.3.1.9 + tor-0.3.1.10 + ... + +If at all possible, try to create the changes file in the same commit where +you are making the change. Please give it a distinctive name that no other +branch will use for the lifetime of your change. We usually use "ticketNNNNN" +or "bugNNNNN", where NNNNN is the ticket number. To verify the format of the +changes file, you can use `make check-changes`. This is run automatically as +part of `make check` -- if it fails, we must fix it as soon as possible, so +that our CI passes. These checks are implemented in +`scripts/maint/lintChanges.py`. Changes file style guide: * Changes files begin with " o Header (subheading):". The header -- cgit v1.2.3-54-g00ecf From 1788343affdec7ac73dbdf1c50b486f593a2d428 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 23 Apr 2019 12:31:14 +1000 Subject: Stop looking for scripts in the build directory during "make shellcheck" Fixes bug 30263; bugfix on 0.4.0.1-alpha. --- Makefile.am | 2 +- changes/bug30263 | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/bug30263 (limited to 'changes') diff --git a/Makefile.am b/Makefile.am index d65c08f6bf..8bf2aaf910 100644 --- a/Makefile.am +++ b/Makefile.am @@ -220,7 +220,7 @@ shellcheck: if command -v shellcheck; then \ find $(top_srcdir)/scripts/ -name "*.sh" -exec shellcheck {} +; \ if [ -d "$(top_srcdir)/scripts/test" ]; then \ - shellcheck $(top_srcdir)/scripts/test/cov-diff $(top_builddir)/scripts/test/coverage; \ + shellcheck $(top_srcdir)/scripts/test/cov-diff $(top_srcdir)/scripts/test/coverage; \ fi; \ fi diff --git a/changes/bug30263 b/changes/bug30263 new file mode 100644 index 0000000000..ba81c1b8a1 --- /dev/null +++ b/changes/bug30263 @@ -0,0 +1,3 @@ + o Minor bugfixes (shellcheck): + - Stop looking for scripts in the build directory during + "make shellcheck". Fixes bug 30263; bugfix on 0.4.0.1-alpha. -- cgit v1.2.3-54-g00ecf From 0c78811ceabaece8bec92cc6a9a42a7b4631cfa7 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Fri, 19 Apr 2019 09:51:04 +0300 Subject: Add changes file --- changes/ticket30051 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/ticket30051 (limited to 'changes') diff --git a/changes/ticket30051 b/changes/ticket30051 new file mode 100644 index 0000000000..87b6d7611f --- /dev/null +++ b/changes/ticket30051 @@ -0,0 +1,5 @@ + o Minor features (developer tooling): + - Call practracker from pre-push and pre-commit git hooks to let a + developer know if they made any code style violations in their last + commit. This should help preventing code style violations appearing + upstream. Closes ticket 30051. -- cgit v1.2.3-54-g00ecf From 26183476575abf0f8daccc2f4ca8be4ba0e2a5de Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Tue, 31 Jul 2018 08:41:21 -0400 Subject: Use fascist_firewall_choose_address_ls() in hs_get_extend_info_from_lspecs() --- changes/bug23588 | 7 +++++ src/core/or/policies.c | 22 ++++++++------ src/core/or/policies.h | 3 +- src/feature/hs/hs_common.c | 76 ++++++++++++++++++---------------------------- 4 files changed, 51 insertions(+), 57 deletions(-) create mode 100644 changes/bug23588 (limited to 'changes') diff --git a/changes/bug23588 b/changes/bug23588 new file mode 100644 index 0000000000..754d083614 --- /dev/null +++ b/changes/bug23588 @@ -0,0 +1,7 @@ + o Minor bugfixes (address selection): + - Introduce fascist_firewall_choose_address_ls() which chooses an + IPv6 or IPv4 address based on a smartlist of link specifiers of + what is available and what we prefer. We use this function in + hs_get_extend_info_from_lspecs(). Fixes bug 23588; bugfix on + 0.3.5.1-alpha. Patch by Neel Chauhan. + diff --git a/src/core/or/policies.c b/src/core/or/policies.c index 26a053821a..b58a5c9cb6 100644 --- a/src/core/or/policies.c +++ b/src/core/or/policies.c @@ -1017,17 +1017,26 @@ fascist_firewall_choose_address_rs(const routerstatus_t *rs, } /** Like fascist_firewall_choose_address_base(), but takes in a smartlist - * lspecs consisting of one or more link specifiers. + * lspecs consisting of one or more link specifiers. We assume + * fw_connection is FIREWALL_OR_CONNECTION as link specifiers cannot + * contain DirPorts. */ void fascist_firewall_choose_address_ls(const smartlist_t *lspecs, - int pref_only, tor_addr_port_t* ap, - int direct_conn) + int pref_only, tor_addr_port_t* ap) { int have_v4 = 0, have_v6 = 0; uint16_t port_v4 = 0, port_v6 = 0; tor_addr_t addr_v4, addr_v6; + tor_assert(ap); + + tor_addr_make_null(&ap->addr, AF_UNSPEC); + ap->port = 0; + + tor_addr_make_null(&addr_v4, AF_INET); + tor_addr_make_null(&addr_v6, AF_INET6); + SMARTLIST_FOREACH_BEGIN(lspecs, const link_specifier_t *, ls) { switch (link_specifier_get_ls_type(ls)) { case LS_IPV4: @@ -1041,7 +1050,7 @@ fascist_firewall_choose_address_ls(const smartlist_t *lspecs, case LS_IPV6: /* Skip if we already seen a v6, or deliberately skip it if we're not a * direct connection. */ - if (have_v6 || !direct_conn) continue; + if (have_v6) continue; tor_addr_from_ipv6_bytes(&addr_v6, (const char *) link_specifier_getconstarray_un_ipv6_addr(ls)); port_v6 = link_specifier_get_un_ipv6_port(ls); @@ -1053,11 +1062,6 @@ fascist_firewall_choose_address_ls(const smartlist_t *lspecs, } } SMARTLIST_FOREACH_END(ls); - tor_assert(ap); - - tor_addr_make_null(&ap->addr, AF_UNSPEC); - ap->port = 0; - /* Here, don't check for DirPorts as link specifiers are only used for * ORPorts. */ const or_options_t *options = get_options(); diff --git a/src/core/or/policies.h b/src/core/or/policies.h index f4c68fd952..3c46363c04 100644 --- a/src/core/or/policies.h +++ b/src/core/or/policies.h @@ -93,8 +93,7 @@ void fascist_firewall_choose_address_rs(const routerstatus_t *rs, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t* ap); void fascist_firewall_choose_address_ls(const smartlist_t *lspecs, - int pref_only, tor_addr_port_t* ap, - int direct_conn); + int pref_only, tor_addr_port_t* ap); void fascist_firewall_choose_address_node(const node_t *node, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t* ap); diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c index d4736c2862..ca7e991b75 100644 --- a/src/feature/hs/hs_common.c +++ b/src/feature/hs/hs_common.c @@ -1672,14 +1672,16 @@ hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str, return hs_dir; } -/* From a list of link specifier, an onion key and if we are requesting a - * direct connection (ex: single onion service), return a newly allocated - * extend_info_t object. This function always returns an extend info with - * an IPv4 address, or NULL. +/* Given a list of link specifiers lspecs, a curve 25519 onion_key, and + * a direct connection boolean direct_conn (true for single onion services), + * return a newly allocated extend_info_t object. + * + * This function always returns an extend info with a valid IP address and + * ORPort, or NULL. If direct_conn is false, the IP address is always IPv4. * * It performs the following checks: - * if either IPv4 or legacy ID is missing, return NULL. - * if direct_conn, and we can't reach the IPv4 address, return NULL. + * if there is no usable IP address, or legacy ID is missing, return NULL. + * if direct_conn, and we can't reach any IP address, return NULL. */ extend_info_t * hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, @@ -1688,10 +1690,12 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, { int have_v4 = 0, have_legacy_id = 0, have_ed25519_id = 0; char legacy_id[DIGEST_LEN] = {0}; - uint16_t port_v4 = 0; - tor_addr_t addr_v4; ed25519_public_key_t ed25519_pk; extend_info_t *info = NULL; + tor_addr_port_t ap; + + tor_addr_make_null(&ap.addr, AF_UNSPEC); + ap.port = 0; tor_assert(lspecs); @@ -1704,11 +1708,14 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, SMARTLIST_FOREACH_BEGIN(lspecs, const link_specifier_t *, ls) { switch (link_specifier_get_ls_type(ls)) { case LS_IPV4: - /* Skip if we already seen a v4. */ - if (have_v4) continue; - tor_addr_from_ipv4h(&addr_v4, + /* Skip if we already seen a v4. If direct_conn is true, we skip this + * block because fascist_firewall_choose_address_ls() will set ap. If + * direct_conn is false, set ap to the first IPv4 address and port in + * the link specifiers.*/ + if (have_v4 || direct_conn) continue; + tor_addr_from_ipv4h(&ap.addr, link_specifier_get_un_ipv4_addr(ls)); - port_v4 = link_specifier_get_un_ipv4_port(ls); + ap.port = link_specifier_get_un_ipv4_port(ls); have_v4 = 1; break; case LS_LEGACY_ID: @@ -1732,55 +1739,32 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, } } SMARTLIST_FOREACH_END(ls); - /* Legacy ID is mandatory, and we require IPv4. */ - if (!have_v4 || !have_legacy_id) { - bool both = !have_v4 && !have_legacy_id; - log_fn(LOG_PROTOCOL_WARN, LD_REND, "Missing %s%s%s link specifier%s.", - !have_v4 ? "IPv4" : "", - both ? " and " : "", - !have_legacy_id ? "legacy ID" : "", - both ? "s" : ""); - goto done; - } + /* Choose a preferred address first, but fall back to an allowed address. */ + if (direct_conn) + fascist_firewall_choose_address_ls(lspecs, 0, &ap); - /* We know we have IPv4, because we just checked. */ - if (!direct_conn) { - /* All clients can extend to any IPv4 via a 3-hop path. */ - goto validate; - } else if (direct_conn && - fascist_firewall_allows_address_addr(&addr_v4, port_v4, - FIREWALL_OR_CONNECTION, - 0, 0)) { - /* Direct connection and we can reach it in IPv4 so go for it. */ - goto validate; - - /* We will add support for falling back to a 3-hop path in a later - * release. */ - } else { - /* If we can't reach IPv4, return NULL. */ - log_fn(LOG_PROTOCOL_WARN, LD_REND, - "Received an IPv4 link specifier, " - "but the address is not reachable: %s:%u", - fmt_addr(&addr_v4), port_v4); + /* Legacy ID is mandatory, and we require an IP address. */ + if (!tor_addr_port_is_valid_ap(&ap, 0) || !have_legacy_id) { + /* If we're missing the legacy ID or the IP address, return NULL. */ goto done; } - /* We will add support for IPv6 in a later release. */ + /* We will add support for falling back to a 3-hop path in a later + * release. */ - validate: /* We'll validate now that the address we've picked isn't a private one. If * it is, are we allowed to extend to private addresses? */ - if (!extend_info_addr_is_allowed(&addr_v4)) { + if (!extend_info_addr_is_allowed(&ap.addr)) { log_fn(LOG_PROTOCOL_WARN, LD_REND, "Requested address is private and we are not allowed to extend to " - "it: %s:%u", fmt_addr(&addr_v4), port_v4); + "it: %s:%u", fmt_addr(&ap.addr), ap.port); goto done; } /* We do have everything for which we think we can connect successfully. */ info = extend_info_new(NULL, legacy_id, (have_ed25519_id) ? &ed25519_pk : NULL, NULL, - onion_key, &addr_v4, port_v4); + onion_key, &ap.addr, ap.port); done: return info; } -- cgit v1.2.3-54-g00ecf From b19dd1bb11a59ab38dc1b45f2108a4a6f5ce2813 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 12 Dec 2018 12:43:48 +1000 Subject: Update 23588 changes file to say what the patch actually does Stop ignoring IPv6 link specifiers sent to v3 onion services. v3 onion service IPv6 support is still incomplete, see 23493 for details. Fixes bug 23588; bugfix on 0.3.2.1-alpha. Patch by Neel Chauhan. --- changes/bug23588 | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'changes') diff --git a/changes/bug23588 b/changes/bug23588 index 754d083614..86064ab313 100644 --- a/changes/bug23588 +++ b/changes/bug23588 @@ -1,7 +1,5 @@ - o Minor bugfixes (address selection): - - Introduce fascist_firewall_choose_address_ls() which chooses an - IPv6 or IPv4 address based on a smartlist of link specifiers of - what is available and what we prefer. We use this function in - hs_get_extend_info_from_lspecs(). Fixes bug 23588; bugfix on - 0.3.5.1-alpha. Patch by Neel Chauhan. - + o Minor bugfixes (v3 onion services): + - Stop ignoring IPv6 link specifiers sent to v3 onion services. + v3 onion service IPv6 support is still incomplete, see 23493 for + details. Fixes bug 23588; bugfix on 0.3.2.1-alpha. + Patch by Neel Chauhan. -- cgit v1.2.3-54-g00ecf From f35bd3681466e58e525d95714ba630caa98f67ae Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 24 Apr 2019 17:41:09 +1000 Subject: test-network-all: Test IPv6-only v3 single onion services In "make test-network-all", test IPv6-only v3 single onion services, using the chutney network single-onion-v23-ipv6-md. This test will not pass until 23588 has been merged. Closes ticket 27251. --- changes/ticket27251 | 4 ++++ src/test/include.am | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 changes/ticket27251 (limited to 'changes') diff --git a/changes/ticket27251 b/changes/ticket27251 new file mode 100644 index 0000000000..7ce296e8da --- /dev/null +++ b/changes/ticket27251 @@ -0,0 +1,4 @@ + o Testing (chutney): + - In "make test-network-all", test IPv6-only v3 single onion services, + using the chutney network single-onion-v23-ipv6-md. This test will + not pass until 23588 has been merged. Closes ticket 27251. diff --git a/src/test/include.am b/src/test/include.am index 497aa320a4..fb4e9f4bc0 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -46,10 +46,8 @@ TESTS += src/test/test src/test/test-slow src/test/test-memwipe \ TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v2-min hs-v3-min \ single-onion-v23 # only run if we can ping6 ::1 (localhost) -# IPv6-only v3 single onion services don't work yet, so we don't test the -# single-onion-v23-ipv6-md flavor TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-v23-ipv6-md \ - single-onion-ipv6-md + single-onion-v23-ipv6-md # only run if we can find a stable (or simply another) version of tor TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v2 -- cgit v1.2.3-54-g00ecf From 04290724957e14710646a5c28bd3230710466c92 Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Thu, 25 Apr 2019 01:50:13 +0200 Subject: Lower log level of unlink() errors in networkstatus_set_current_consensus(). In this patch we lower the log level of the failures for the three calls to unlink() in networkstatus_set_current_consensus(). These errors might trigger on Windows because the memory mapped consensus file keeps the file in open state even after we have close()'d it. Windows will then error on the unlink() call with a "Permission denied" error. The consequences of ignoring these errors is that we leave an unused file around on the file-system, which is an easier way to fix this problem right now than refactoring networkstatus_set_current_consensus(). See: https://bugs.torproject.org/29930 --- changes/bug29930 | 4 ++++ src/feature/nodelist/networkstatus.c | 18 +++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 changes/bug29930 (limited to 'changes') diff --git a/changes/bug29930 b/changes/bug29930 new file mode 100644 index 0000000000..a99b11430b --- /dev/null +++ b/changes/bug29930 @@ -0,0 +1,4 @@ + o Minor bugfixes (UI): + - Lower log level of unlink() errors during bootstrap. Fixes bug 29930; + bugfix on 0.4.0.1-alpha. + diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index a988f700f3..24e3b212f0 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -2033,9 +2033,9 @@ networkstatus_set_current_consensus(const char *consensus, * latest consensus. */ if (was_waiting_for_certs && from_cache) if (unlink(unverified_fname) != 0) { - log_warn(LD_FS, - "Failed to unlink %s: %s", - unverified_fname, strerror(errno)); + log_debug(LD_FS, + "Failed to unlink %s: %s", + unverified_fname, strerror(errno)); } } goto done; @@ -2048,9 +2048,9 @@ networkstatus_set_current_consensus(const char *consensus, } if (was_waiting_for_certs && (r < -1) && from_cache) { if (unlink(unverified_fname) != 0) { - log_warn(LD_FS, - "Failed to unlink %s: %s", - unverified_fname, strerror(errno)); + log_debug(LD_FS, + "Failed to unlink %s: %s", + unverified_fname, strerror(errno)); } } goto done; @@ -2115,9 +2115,9 @@ networkstatus_set_current_consensus(const char *consensus, waiting->set_at = 0; waiting->dl_failed = 0; if (unlink(unverified_fname) != 0) { - log_warn(LD_FS, - "Failed to unlink %s: %s", - unverified_fname, strerror(errno)); + log_debug(LD_FS, + "Failed to unlink %s: %s", + unverified_fname, strerror(errno)); } } -- cgit v1.2.3-54-g00ecf From dbfe1a14e44647a4d5f27f8d495f3468208d75dd Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 2 Apr 2019 10:41:12 -0400 Subject: When parsing a multiline controller command, be careful with linebreaks The first line break in particular was mishandled: it was discarded if no arguments came before it, which made it impossible to distinguish arguments from the first line of the body. To solve this, we need to allocate a copy of the command rather than using NUL to separate it, since we might have "COMMAND\n" as our input. Fixes ticket 29984. --- changes/ticket29984 | 5 ++++ scripts/maint/practracker/exceptions.txt | 2 +- src/core/mainloop/connection.c | 1 + src/feature/control/control.c | 45 ++++++++++++++++++++--------- src/feature/control/control.h | 3 +- src/feature/control/control_cmd.c | 12 ++++---- src/feature/control/control_connection_st.h | 3 +- 7 files changed, 48 insertions(+), 23 deletions(-) create mode 100644 changes/ticket29984 (limited to 'changes') diff --git a/changes/ticket29984 b/changes/ticket29984 new file mode 100644 index 0000000000..8631dff27b --- /dev/null +++ b/changes/ticket29984 @@ -0,0 +1,5 @@ + o Minor bugfixes (controller protocol): + - Teach the controller parser to correctly distinguish an object + preceded by an argument list from one without. Previously, it + couldn't distinguish an argument list from the first line of a + multiline object. Fixes bug 29984; bugfix on 0.2.3.8-alpha. diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index 7d03bf27d6..7582395fea 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -56,7 +56,7 @@ problem function-size /src/app/main/ntmain.c:nt_service_install() 125 problem include-count /src/app/main/shutdown.c 52 problem file-size /src/core/mainloop/connection.c 5558 problem include-count /src/core/mainloop/connection.c 61 -problem function-size /src/core/mainloop/connection.c:connection_free_minimal() 184 +problem function-size /src/core/mainloop/connection.c:connection_free_minimal() 185 problem function-size /src/core/mainloop/connection.c:connection_listener_new() 328 problem function-size /src/core/mainloop/connection.c:connection_handle_listener_read() 161 problem function-size /src/core/mainloop/connection.c:connection_connect_sockaddr() 103 diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c index 51c19b4c4c..30504e4edb 100644 --- a/src/core/mainloop/connection.c +++ b/src/core/mainloop/connection.c @@ -697,6 +697,7 @@ connection_free_minimal(connection_t *conn) control_connection_t *control_conn = TO_CONTROL_CONN(conn); tor_free(control_conn->safecookie_client_hash); tor_free(control_conn->incoming_cmd); + tor_free(control_conn->current_cmd); if (control_conn->ephemeral_onion_services) { SMARTLIST_FOREACH(control_conn->ephemeral_onion_services, char *, cp, { memwipe(cp, 0, strlen(cp)); diff --git a/src/feature/control/control.c b/src/feature/control/control.c index 308f1936b9..23ef83ef95 100644 --- a/src/feature/control/control.c +++ b/src/feature/control/control.c @@ -276,25 +276,38 @@ peek_connection_has_http_command(connection_t *conn) } /** - * Helper: take a nul-terminated command of given length, and find where - * the command starts and the argument begins. Separate them with a NUL, - * and return a pointer to the arguments. + * Helper: take a nul-terminated command of given length, and find where the + * command starts and the arguments begin. Separate them, allocate a new + * string in current_cmd_out for the command, and return a pointer + * to the arguments. **/ STATIC char * -control_split_incoming_command(char *incoming_cmd, size_t *data_len) +control_split_incoming_command(char *incoming_cmd, + size_t *data_len, + char **current_cmd_out) { + const bool is_multiline = *data_len && incoming_cmd[0] == '+'; size_t cmd_len = 0; while (cmd_len < *data_len && !TOR_ISSPACE(incoming_cmd[cmd_len])) ++cmd_len; - incoming_cmd[cmd_len]='\0'; - char *args = incoming_cmd+cmd_len+1; - tor_assert(*data_len>cmd_len); - *data_len -= (cmd_len+1); /* skip the command and NUL we added after it */ - while (TOR_ISSPACE(*args)) { - ++args; - --*data_len; + *current_cmd_out = tor_memdup_nulterm(incoming_cmd, cmd_len); + char *args = incoming_cmd+cmd_len; + tor_assert(*data_len>=cmd_len); + *data_len -= cmd_len; + if (is_multiline) { + // Only match horizontal space: any line after the first is data, + // not arguments. + while ((*args == '\t' || *args == ' ') && *data_len) { + ++args; + --*data_len; + } + } else { + while (TOR_ISSPACE(*args) && *data_len) { + ++args; + --*data_len; + } } return args; @@ -429,7 +442,11 @@ connection_control_process_inbuf(control_connection_t *conn) /* Okay, we now have a command sitting on conn->incoming_cmd. See if we * recognize it. */ - args = control_split_incoming_command(conn->incoming_cmd, &data_len); + tor_free(conn->current_cmd); + args = control_split_incoming_command(conn->incoming_cmd, &data_len, + &conn->current_cmd); + if (BUG(!conn->current_cmd)) + return -1; /* If the connection is already closing, ignore further commands */ if (TO_CONN(conn)->marked_for_close) { @@ -437,14 +454,14 @@ connection_control_process_inbuf(control_connection_t *conn) } /* Otherwise, Quit is always valid. */ - if (!strcasecmp(conn->incoming_cmd, "QUIT")) { + if (!strcasecmp(conn->current_cmd, "QUIT")) { connection_write_str_to_buf("250 closing connection\r\n", conn); connection_mark_and_flush(TO_CONN(conn)); return 0; } if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && - !is_valid_initial_command(conn, conn->incoming_cmd)) { + !is_valid_initial_command(conn, conn->current_cmd)) { connection_write_str_to_buf("514 Authentication required.\r\n", conn); connection_mark_for_close(TO_CONN(conn)); return 0; diff --git a/src/feature/control/control.h b/src/feature/control/control.h index 6fc1c40cac..8d3595d2ed 100644 --- a/src/feature/control/control.h +++ b/src/feature/control/control.h @@ -62,7 +62,8 @@ void set_cached_network_liveness(int liveness); #ifdef CONTROL_PRIVATE STATIC char *control_split_incoming_command(char *incoming_cmd, - size_t *data_len); + size_t *data_len, + char **current_cmd_out); #endif #endif /* !defined(TOR_CONTROL_H) */ diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c index aa0bef5135..53cbf2bd0f 100644 --- a/src/feature/control/control_cmd.c +++ b/src/feature/control/control_cmd.c @@ -2299,7 +2299,7 @@ handle_control_obsolete(control_connection_t *conn, { (void)arg_len; (void)args; - char *command = tor_strdup(conn->incoming_cmd); + char *command = tor_strdup(conn->current_cmd); tor_strupper(command); connection_printf_to_buf(conn, "511 %s is obsolete.\r\n", command); tor_free(command); @@ -2490,14 +2490,14 @@ handle_single_control_command(const control_cmd_def_t *def, control_cmd_args_t *parsed_args; char *err=NULL; tor_assert(def->syntax); - parsed_args = control_cmd_parse_args(conn->incoming_cmd, + parsed_args = control_cmd_parse_args(conn->current_cmd, def->syntax, cmd_data_len, args, &err); if (!parsed_args) { connection_printf_to_buf(conn, "512 Bad arguments to %s: %s\r\n", - conn->incoming_cmd, err?err:""); + conn->current_cmd, err?err:""); tor_free(err); } else { if (BUG(err)) @@ -2519,7 +2519,7 @@ handle_single_control_command(const control_cmd_def_t *def, } /** - * Run a given controller command, as selected by the incoming_cmd field of + * Run a given controller command, as selected by the current_cmd field of * conn. */ int @@ -2533,13 +2533,13 @@ handle_control_command(control_connection_t *conn, for (unsigned i = 0; i < N_CONTROL_COMMANDS; ++i) { const control_cmd_def_t *def = &CONTROL_COMMANDS[i]; - if (!strcasecmp(conn->incoming_cmd, def->name)) { + if (!strcasecmp(conn->current_cmd, def->name)) { return handle_single_control_command(def, conn, cmd_data_len, args); } } connection_printf_to_buf(conn, "510 Unrecognized command \"%s\"\r\n", - conn->incoming_cmd); + conn->current_cmd); return 0; } diff --git a/src/feature/control/control_connection_st.h b/src/feature/control/control_connection_st.h index 177a916257..cace6bb36f 100644 --- a/src/feature/control/control_connection_st.h +++ b/src/feature/control/control_connection_st.h @@ -40,7 +40,8 @@ struct control_connection_t { /** A control command that we're reading from the inbuf, but which has not * yet arrived completely. */ char *incoming_cmd; + /** The control command that we are currently processing. */ + char *current_cmd; }; #endif - -- cgit v1.2.3-54-g00ecf From 3ed7ceeb856b3c1fbe5edf3b8c6ffe3f5e875622 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 9 Apr 2019 11:18:18 -0400 Subject: changes file for ticket 30091 (controller parsing refactor) --- changes/ticket30091 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket30091 (limited to 'changes') diff --git a/changes/ticket30091 b/changes/ticket30091 new file mode 100644 index 0000000000..968ea01f4a --- /dev/null +++ b/changes/ticket30091 @@ -0,0 +1,4 @@ + o Major features (controller protocol): + - Controller commands are now parsed using a generalized parsing + subsystem. Previously, each controller command was responsible for + parsing its own input. Closes ticket 30091. -- cgit v1.2.3-54-g00ecf From 650b94ebc157da01fcb34e08341ad1717c61f4fe Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 26 Apr 2019 11:03:22 -0400 Subject: Use a linear algorithm to subtract two nodelists. The nodelist_idx for each node_t serves as a unique identifier for the node, so we can use a bitarray to hold all the excluded nodes, and then remove them from the smartlist. Previously use used smartlist_subtract(sl, excluded), which is O(len(sl)*len(excluded)). We can use this function in other places too, but this is the one that showed up on the profiles of 30291. Closes ticket 30307. --- changes/ticket30307 | 4 +++ src/feature/nodelist/node_select.c | 74 ++++++++++++++++++++++++++++++-------- src/test/test_entrynodes.c | 1 + 3 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 changes/ticket30307 (limited to 'changes') diff --git a/changes/ticket30307 b/changes/ticket30307 new file mode 100644 index 0000000000..abcacb6085 --- /dev/null +++ b/changes/ticket30307 @@ -0,0 +1,4 @@ + o Major features (performance): + - Update our node selection algorithm to exclude nodes in linear time. + Previously, the algorithm was quadratic, which could slow down heavily + used onion services. Closes ticket 30307. diff --git a/src/feature/nodelist/node_select.c b/src/feature/nodelist/node_select.c index 93ddb066d4..719b4b1b27 100644 --- a/src/feature/nodelist/node_select.c +++ b/src/feature/nodelist/node_select.c @@ -30,6 +30,7 @@ #include "feature/nodelist/routerset.h" #include "feature/relay/router.h" #include "feature/relay/routermode.h" +#include "lib/container/bitarray.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/math/fp.h" @@ -826,6 +827,58 @@ routerlist_add_node_and_family(smartlist_t *sl, const routerinfo_t *router) nodelist_add_node_and_family(sl, node); } +/** + * Remove every node_t that appears in excluded from sl. + * + * Behaves like smartlist_subtract, but uses nodelist_idx values to deliver + * linear performance when smartlist_subtract would be quadratic. + **/ +static void +nodelist_subtract(smartlist_t *sl, const smartlist_t *excluded) +{ + const smartlist_t *nodelist = nodelist_get_list(); + const int nodelist_len = smartlist_len(nodelist); + bitarray_t *excluded_idx = bitarray_init_zero(nodelist_len); + + /* We haven't used nodelist_idx in this way previously, so I'm going to be + * paranoid in this code, and check that nodelist_idx is correct for every + * node before we use it. If we fail, we fall back to smartlist_subtract(). + */ + + /* Set the excluded_idx bit corresponding to every excluded node... + */ + SMARTLIST_FOREACH_BEGIN(excluded, const node_t *, node) { + const int idx = node->nodelist_idx; + if (BUG(idx < 0) || BUG(idx >= nodelist_len) || + BUG(node != smartlist_get(nodelist, idx))) { + goto internal_error; + } + bitarray_set(excluded_idx, idx); + } SMARTLIST_FOREACH_END(node); + + /* Then remove them from sl. + */ + SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) { + const int idx = node->nodelist_idx; + if (BUG(idx < 0) || BUG(idx >= nodelist_len) || + BUG(node != smartlist_get(nodelist, idx))) { + goto internal_error; + } + if (bitarray_is_set(excluded_idx, idx)) { + SMARTLIST_DEL_CURRENT(sl, node); + } + } SMARTLIST_FOREACH_END(node); + + bitarray_free(excluded_idx); + return; + + internal_error: + log_warn(LD_BUG, "Internal error prevented us from using the fast method " + "for subtracting nodelists. Falling back to the quadratic way."); + smartlist_subtract(sl, excluded); + bitarray_free(excluded_idx); +} + /** Return a random running node from the nodelist. Never * pick a node that is in * excludedsmartlist, or which matches excludedset, @@ -860,6 +913,7 @@ router_choose_random_node(smartlist_t *excludedsmartlist, const int direct_conn = (flags & CRN_DIRECT_CONN) != 0; const int rendezvous_v3 = (flags & CRN_RENDEZVOUS_V3) != 0; + const smartlist_t *node_list = nodelist_get_list(); smartlist_t *sl=smartlist_new(), *excludednodes=smartlist_new(); const node_t *choice = NULL; @@ -870,17 +924,17 @@ router_choose_random_node(smartlist_t *excludedsmartlist, rule = weight_for_exit ? WEIGHT_FOR_EXIT : (need_guard ? WEIGHT_FOR_GUARD : WEIGHT_FOR_MID); - SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) { + SMARTLIST_FOREACH_BEGIN(node_list, const node_t *, node) { if (node_allows_single_hop_exits(node)) { /* Exclude relays that allow single hop exit circuits. This is an * obsolete option since 0.2.9.2-alpha and done by default in * 0.3.1.0-alpha. */ - smartlist_add(excludednodes, node); + smartlist_add(excludednodes, (node_t*)node); } else if (rendezvous_v3 && !node_supports_v3_rendezvous_point(node)) { /* Exclude relays that do not support to rendezvous for a hidden service * version 3. */ - smartlist_add(excludednodes, node); + smartlist_add(excludednodes, (node_t*)node); } } SMARTLIST_FOREACH_END(node); @@ -897,19 +951,11 @@ router_choose_random_node(smartlist_t *excludedsmartlist, "We found %d running nodes.", smartlist_len(sl)); - smartlist_subtract(sl,excludednodes); - log_debug(LD_CIRC, - "We removed %d excludednodes, leaving %d nodes.", - smartlist_len(excludednodes), - smartlist_len(sl)); - if (excludedsmartlist) { - smartlist_subtract(sl,excludedsmartlist); - log_debug(LD_CIRC, - "We removed %d excludedsmartlist, leaving %d nodes.", - smartlist_len(excludedsmartlist), - smartlist_len(sl)); + smartlist_add_all(excludednodes, excludedsmartlist); } + nodelist_subtract(sl, excludednodes); + if (excludedset) { routerset_subtract_nodes(sl,excludedset); log_debug(LD_CIRC, diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index bdf057bb50..c43b21c673 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -197,6 +197,7 @@ big_fake_network_setup(const struct testcase_t *testcase) n->md->exit_policy = parse_short_policy("accept 443"); } + n->nodelist_idx = smartlist_len(big_fake_net_nodes); smartlist_add(big_fake_net_nodes, n); } -- cgit v1.2.3-54-g00ecf From 806539b40a18dec15e1d3d108eb5aec9d9f3ca40 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 26 Apr 2019 11:19:46 -0400 Subject: Use fast check for missing id in node_is_a_configured_bridge() Fixes bug 30308; bugfix on 0.3.5.1-alpha. --- changes/ticket30308 | 5 +++++ src/feature/client/bridges.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changes/ticket30308 (limited to 'changes') diff --git a/changes/ticket30308 b/changes/ticket30308 new file mode 100644 index 0000000000..b78e6b3e9f --- /dev/null +++ b/changes/ticket30308 @@ -0,0 +1,5 @@ + o Minor bugfixes (performance): + - When checking a node for bridge status, use a fast check to make sure + that its identity is set. Previously, we used a constant-time check, + which is not necessary when verifying a BUG() condition that causes + a stack trace. Fixes bug 30308; bugfix on 0.3.5.1-alpha. diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c index 05f89ad36c..ea1aff9519 100644 --- a/src/feature/client/bridges.c +++ b/src/feature/client/bridges.c @@ -348,7 +348,7 @@ int node_is_a_configured_bridge(const node_t *node) { /* First, let's try searching for a bridge with matching identity. */ - if (BUG(tor_digest_is_zero(node->identity))) + if (BUG(tor_mem_is_zero(node->identity, DIGEST_LEN))) return 0; if (find_bridge_by_digest(node->identity) != NULL) -- cgit v1.2.3-54-g00ecf From 6d347fe329cdb2fdda4059ce36a6916225ab4c87 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Tue, 9 Apr 2019 11:23:03 +0300 Subject: Remove obsolete OpenSUSE initscript --- changes/ticket30076 | 2 + configure.ac | 1 - contrib/README | 2 - contrib/dist/suse/tor.sh.in | 118 -------------------------------------------- contrib/include.am | 1 - 5 files changed, 2 insertions(+), 122 deletions(-) create mode 100644 changes/ticket30076 delete mode 100644 contrib/dist/suse/tor.sh.in (limited to 'changes') diff --git a/changes/ticket30076 b/changes/ticket30076 new file mode 100644 index 0000000000..1334bc4603 --- /dev/null +++ b/changes/ticket30076 @@ -0,0 +1,2 @@ + o Removed features: + - Remove obsolete OpenSUSE initscript. Resolves issue 30076. diff --git a/configure.ac b/configure.ac index 3ea578bbba..e65e960d7f 100644 --- a/configure.ac +++ b/configure.ac @@ -2457,7 +2457,6 @@ AC_CONFIG_FILES([ Doxyfile Makefile config.rust - contrib/dist/suse/tor.sh contrib/operator-tools/tor.logrotate contrib/dist/torctl contrib/dist/tor.service diff --git a/contrib/README b/contrib/README index 3a94bb5016..735fcf4c9f 100644 --- a/contrib/README +++ b/contrib/README @@ -34,8 +34,6 @@ tools. Everybody likes to write init scripts differently, it seems. tor.service is a sample service file for use with systemd. -The suse/ subdirectory contains files used by the suse distribution. - operator-tools/ -- Tools for Tor relay operators ------------------------------------------------ diff --git a/contrib/dist/suse/tor.sh.in b/contrib/dist/suse/tor.sh.in deleted file mode 100644 index b7e9005eb5..0000000000 --- a/contrib/dist/suse/tor.sh.in +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006-2007 Andrew Lewman -# -# tor The Onion Router -# -# Startup/shutdown script for tor. This is a wrapper around torctl; -# torctl does the actual work in a relatively system-independent, or at least -# distribution-independent, way, and this script deals with fitting the -# whole thing into the conventions of the particular system at hand. -# -# These next couple of lines "declare" tor for the "chkconfig" program, -# originally from SGI, used on Red Hat/Fedora and probably elsewhere. -# -# chkconfig: 2345 90 10 -# description: Onion Router - A low-latency anonymous proxy -# - -### BEGIN INIT INFO -# Provides: tor -# Required-Start: $remote_fs $network -# Required-Stop: $remote_fs $network -# Default-Start: 3 5 -# Default-Stop: 0 1 2 6 -# Short-Description: Start the tor daemon -# Description: Start the tor daemon: the anon-proxy server -### END INIT INFO - -. /etc/rc.status - -# Shell functions sourced from /etc/rc.status: -# rc_check check and set local and overall rc status -# rc_status check and set local and overall rc status -# rc_status -v ditto but be verbose in local rc status -# rc_status -v -r ditto and clear the local rc status -# rc_failed set local and overall rc status to failed -# rc_reset clear local rc status (overall remains) -# rc_exit exit appropriate to overall rc status - -# First reset status of this service -rc_reset - -# Increase open file descriptors a reasonable amount -ulimit -n 8192 - -TORCTL=@BINDIR@/torctl - -# torctl will use these environment variables -TORUSER=@TORUSER@ -export TORUSER -TORGROUP=@TORGROUP@ -export TORGROUP - -TOR_DAEMON_PID_DIR="@LOCALSTATEDIR@/run/tor" - -if [ -x /bin/su ] ; then - SUPROG=/bin/su -elif [ -x /sbin/su ] ; then - SUPROG=/sbin/su -elif [ -x /usr/bin/su ] ; then - SUPROG=/usr/bin/su -elif [ -x /usr/sbin/su ] ; then - SUPROG=/usr/sbin/su -else - SUPROG=/bin/su -fi - -case "$1" in - - start) - echo "Starting tor daemon" - - if [ ! -d $TOR_DAEMON_PID_DIR ] ; then - mkdir -p $TOR_DAEMON_PID_DIR - chown $TORUSER:$TORGROUP $TOR_DAEMON_PID_DIR - fi - - ## Start daemon with startproc(8). If this fails - ## the echo return value is set appropriate. - - startproc -f $TORCTL start - # Remember status and be verbose - rc_status -v - ;; - - stop) - echo "Stopping tor daemon" - startproc -f $TORCTL stop - # Remember status and be verbose - rc_status -v - ;; - - restart) - echo "Restarting tor daemon" - startproc -f $TORCTL restart - # Remember status and be verbose - rc_status -v - ;; - - reload) - echo "Reloading tor daemon" - startproc -f $TORCTL reload - # Remember status and be verbose - rc_status -v - ;; - - status) - startproc -f $TORCTL status - # Remember status and be verbose - rc_status -v - ;; - - *) - echo "Usage: $0 (start|stop|restart|reload|status)" - RETVAL=1 -esac - -rc_exit diff --git a/contrib/include.am b/contrib/include.am index 9f4775632c..8dd8593304 100644 --- a/contrib/include.am +++ b/contrib/include.am @@ -3,7 +3,6 @@ EXTRA_DIST+= \ contrib/README \ contrib/client-tools/torify \ contrib/dist/rc.subr \ - contrib/dist/suse/tor.sh.in \ contrib/dist/torctl \ contrib/dist/tor.service.in \ contrib/operator-tools/tor-exit-notice.html \ -- cgit v1.2.3-54-g00ecf From b05b165a75a9d9e912da64788fc873fb215f5d75 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sun, 21 Apr 2019 21:06:57 +0300 Subject: Add changes file --- changes/ticket30213 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket30213 (limited to 'changes') diff --git a/changes/ticket30213 b/changes/ticket30213 new file mode 100644 index 0000000000..acb7614807 --- /dev/null +++ b/changes/ticket30213 @@ -0,0 +1,3 @@ + o Minor features (continuous integration): + - Remove sudo configuration lines from .travis.yml as they are no longer + needed with current Travis build environment. Resolves issue 30213. -- cgit v1.2.3-54-g00ecf From 48e1ab17204944e6197002dfa3d3d0c8a08184dc Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 18 Mar 2019 12:50:35 -0400 Subject: Changes file for 29732. --- changes/ticket29732 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/ticket29732 (limited to 'changes') diff --git a/changes/ticket29732 b/changes/ticket29732 new file mode 100644 index 0000000000..bb72361c48 --- /dev/null +++ b/changes/ticket29732 @@ -0,0 +1,5 @@ + o Minor features (testing): + - Tor's unit test code now contains a standard set of functions to + replace the PRNG with a deterministic or reproducible version for + testing. Previously, various tests implemented this in various ways. + Implements ticket 29732. -- cgit v1.2.3-54-g00ecf From 7e03500eefacdb8a987b16d4a9b256443216a27e Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 25 Apr 2019 15:12:10 -0400 Subject: Changes file for periodic event movement --- changes/ticket30293 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/ticket30293 (limited to 'changes') diff --git a/changes/ticket30293 b/changes/ticket30293 new file mode 100644 index 0000000000..c74b6cd346 --- /dev/null +++ b/changes/ticket30293 @@ -0,0 +1,5 @@ + o Code simplification and refactoring: + - Start move responsibility for knowing about periodic events to the + appropriate subsystems, so that the mainloop doesn't need to know all + the periodic events in the rest of the codebase. Implements tickets + 30293 and 30294. -- cgit v1.2.3-54-g00ecf From 09003679962e5d0e0c15cb278b83e3ef79affdda Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Fri, 26 Apr 2019 13:25:12 -0500 Subject: Changes file for ticket30007 --- changes/ticket30007 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket30007 (limited to 'changes') diff --git a/changes/ticket30007 b/changes/ticket30007 new file mode 100644 index 0000000000..e87f6b956f --- /dev/null +++ b/changes/ticket30007 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Abstract out the low-level formatting of replies on the control + port. Implements ticket 30007. -- cgit v1.2.3-54-g00ecf From 309467c64e007ea6841c07fdee35eaff0146d541 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 30 Apr 2019 14:43:35 -0400 Subject: Rename tor_mem_is_zero to fast_mem_is_zero() For memeq and friends, "tor_" indicates constant-time and "fast_" indicates optimized. I'm fine with leaving the constant-time "safe_mem_is_zero" with its current name, but the "tor_" prefix on the current optimized version is misleading. Also, make the tor_digest*_is_zero() uniformly constant-time, and add a fast_digest*_is_zero() version to use as needed. A later commit in this branch will fix all the users of tor_mem_is_zero(). Closes ticket 30309. --- changes/bug30309 | 3 +++ src/lib/string/util_string.c | 9 +++------ src/lib/string/util_string.h | 8 +++++++- 3 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 changes/bug30309 (limited to 'changes') diff --git a/changes/bug30309 b/changes/bug30309 new file mode 100644 index 0000000000..6cbbe8d156 --- /dev/null +++ b/changes/bug30309 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Rename tor_mem_is_zero() to fast_mem_is_zero(), to emphasize that + it is not a constant-time function. Closes ticket 30309. diff --git a/src/lib/string/util_string.c b/src/lib/string/util_string.c index 0c4e399008..f5061a11d2 100644 --- a/src/lib/string/util_string.c +++ b/src/lib/string/util_string.c @@ -71,7 +71,7 @@ tor_memstr(const void *haystack, size_t hlen, const char *needle) /** Return true iff the 'len' bytes at 'mem' are all zero. */ int -tor_mem_is_zero(const char *mem, size_t len) +fast_mem_is_zero(const char *mem, size_t len) { static const char ZERO[] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, @@ -95,17 +95,14 @@ tor_mem_is_zero(const char *mem, size_t len) int tor_digest_is_zero(const char *digest) { - static const uint8_t ZERO_DIGEST[] = { - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 - }; - return tor_memeq(digest, ZERO_DIGEST, DIGEST_LEN); + return safe_mem_is_zero(digest, DIGEST_LEN); } /** Return true iff the DIGEST256_LEN bytes in digest are all zero. */ int tor_digest256_is_zero(const char *digest) { - return tor_mem_is_zero(digest, DIGEST256_LEN); + return safe_mem_is_zero(digest, DIGEST256_LEN); } /** Remove from the string s every character which appears in diff --git a/src/lib/string/util_string.h b/src/lib/string/util_string.h index da4fab159c..7e8af0578c 100644 --- a/src/lib/string/util_string.h +++ b/src/lib/string/util_string.h @@ -20,7 +20,13 @@ const void *tor_memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen); const void *tor_memstr(const void *haystack, size_t hlen, const char *needle); -int tor_mem_is_zero(const char *mem, size_t len); +int fast_mem_is_zero(const char *mem, size_t len); +#define fast_digest_is_zero(d) fast_mem_is_zero((d), DIGEST_LEN) +#define fast_digetst256_is_zero(d) fast_mem_is_zero((d), DIGEST256_LEN) + +// XXXX remove this after we replace all users. +#define tor_mem_is_zero fast_mem_is_zero + int tor_digest_is_zero(const char *digest); int tor_digest256_is_zero(const char *digest); -- cgit v1.2.3-54-g00ecf From 332617a81a874412bbadf331be74b7414545c197 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Wed, 1 May 2019 21:03:23 +0000 Subject: Changes file for bug29231. --- changes/bug29231 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/bug29231 (limited to 'changes') diff --git a/changes/bug29231 b/changes/bug29231 new file mode 100644 index 0000000000..bcc19e1b48 --- /dev/null +++ b/changes/bug29231 @@ -0,0 +1,4 @@ + o Minor bugfixes (Channel padding statistics): + - Channel padding write totals and padding-enabled totals are now + counted properly in relay extrainfo descriptors. Fixes bug 29231; + bugfix on 0.3.1.1-alpha -- cgit v1.2.3-54-g00ecf From 3d13841fa542889df741c8c5630ec2dd576f645d Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 2 May 2019 08:42:01 -0400 Subject: Remove changes files that are already in 0.4.0.5 or earlier --- changes/29241_diagnostic | 4 ---- changes/bug13221 | 5 ----- changes/bug27199 | 3 --- changes/bug28525 | 7 ------- changes/bug28614_better_logging | 6 ------ changes/bug28656 | 3 --- changes/bug28925 | 4 ---- changes/bug29017 | 4 ---- changes/bug29036 | 5 ----- changes/bug29144 | 5 ----- changes/bug29241 | 6 ------ changes/bug29500 | 3 --- changes/bug29527 | 5 ----- changes/bug29530_035 | 5 ----- changes/bug29562 | 4 ---- changes/bug29599 | 3 --- changes/bug29601 | 6 ------ changes/bug29665 | 7 ------- changes/bug29693 | 3 --- changes/bug29703 | 4 ---- changes/bug29706_minimal | 4 ---- changes/bug29706_refactor | 4 ---- changes/bug29874 | 4 ---- changes/bug29922 | 4 ---- changes/bug29930 | 4 ---- changes/bug29959-040 | 3 --- changes/bug30001 | 7 ------- changes/bug30011 | 4 ---- changes/bug30021 | 8 -------- changes/bug30040 | 9 --------- changes/bug30041 | 5 ----- changes/bug30263 | 3 --- changes/cid1444119 | 3 --- changes/diagnostic_28223_redux | 4 ---- changes/doc29121 | 3 --- changes/geoip-2019-03-04 | 4 ---- changes/geoip-2019-04-02 | 4 ---- changes/ticket21377 | 4 ---- changes/ticket29357 | 7 ------- changes/ticket29435 | 3 --- changes/ticket29631 | 4 ---- changes/ticket29806 | 7 ------- changes/ticket29897 | 3 --- changes/ticket29962 | 3 --- changes/ticket30117 | 4 ---- 45 files changed, 204 deletions(-) delete mode 100644 changes/29241_diagnostic delete mode 100644 changes/bug13221 delete mode 100644 changes/bug27199 delete mode 100644 changes/bug28525 delete mode 100644 changes/bug28614_better_logging delete mode 100644 changes/bug28656 delete mode 100644 changes/bug28925 delete mode 100644 changes/bug29017 delete mode 100644 changes/bug29036 delete mode 100644 changes/bug29144 delete mode 100644 changes/bug29241 delete mode 100644 changes/bug29500 delete mode 100644 changes/bug29527 delete mode 100644 changes/bug29530_035 delete mode 100644 changes/bug29562 delete mode 100644 changes/bug29599 delete mode 100644 changes/bug29601 delete mode 100644 changes/bug29665 delete mode 100644 changes/bug29693 delete mode 100644 changes/bug29703 delete mode 100644 changes/bug29706_minimal delete mode 100644 changes/bug29706_refactor delete mode 100644 changes/bug29874 delete mode 100644 changes/bug29922 delete mode 100644 changes/bug29930 delete mode 100644 changes/bug29959-040 delete mode 100644 changes/bug30001 delete mode 100644 changes/bug30011 delete mode 100644 changes/bug30021 delete mode 100644 changes/bug30040 delete mode 100644 changes/bug30041 delete mode 100644 changes/bug30263 delete mode 100644 changes/cid1444119 delete mode 100644 changes/diagnostic_28223_redux delete mode 100644 changes/doc29121 delete mode 100644 changes/geoip-2019-03-04 delete mode 100644 changes/geoip-2019-04-02 delete mode 100644 changes/ticket21377 delete mode 100644 changes/ticket29357 delete mode 100644 changes/ticket29435 delete mode 100644 changes/ticket29631 delete mode 100644 changes/ticket29806 delete mode 100644 changes/ticket29897 delete mode 100644 changes/ticket29962 delete mode 100644 changes/ticket30117 (limited to 'changes') diff --git a/changes/29241_diagnostic b/changes/29241_diagnostic deleted file mode 100644 index 1e38654957..0000000000 --- a/changes/29241_diagnostic +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (NSS, diagnostic): - - Try to log an error from NSS (if there is any) and a more useful - description of our situation if we are using NSS and a call to - SSL_ExportKeyingMaterial() fails. Diagnostic for ticket 29241. diff --git a/changes/bug13221 b/changes/bug13221 deleted file mode 100644 index 13935a1921..0000000000 --- a/changes/bug13221 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (logging): - - Correct a misleading error message when IPv4Only or IPv6Only - is used but the resolved address can not be interpreted as an - address of the specified IP version. Fixes bug 13221; bugfix - on 0.2.3.9-alpha. Patch from Kris Katterjohn. diff --git a/changes/bug27199 b/changes/bug27199 deleted file mode 100644 index f9d2a422f9..0000000000 --- a/changes/bug27199 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (rust): - - Abort on panic in all build profiles, instead of potentially unwinding - into C code. Fixes bug 27199; bugfix on 0.3.3.1-alpha. diff --git a/changes/bug28525 b/changes/bug28525 deleted file mode 100644 index 988ffb2192..0000000000 --- a/changes/bug28525 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (address selection): - - Make Tor aware of the RFC 6598 (Carrier Grade NAT) IP range, which is the - subnet 100.64.0.0/10. This is deployed by many ISPs as an alternative to - RFC 1918 that does not break existing internal networks. This patch fixes - security issues caused by RFC 6518 by blocking control ports on these - addresses and warns users if client ports or ExtORPorts are listening on - a RFC 6598 address. Closes ticket 28525. Patch by Neel Chauhan. diff --git a/changes/bug28614_better_logging b/changes/bug28614_better_logging deleted file mode 100644 index 26d19c3c11..0000000000 --- a/changes/bug28614_better_logging +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (logging): - - On Windows, when errors cause us to reload a consensus from disk, tell - the user that we are retrying at log level "notice". Previously we only - logged this information at "info", which was confusing because the - errors themselves were logged at "warning". Improves previous fix for - 28614. Fixes bug 30004; bugfix on 0.4.0.2-alpha. diff --git a/changes/bug28656 b/changes/bug28656 deleted file mode 100644 index d3a13d196c..0000000000 --- a/changes/bug28656 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (logging): - - Stop logging a BUG() warning when tor is waiting for exit descriptors. - Fixes bug 28656; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug28925 b/changes/bug28925 deleted file mode 100644 index a867443885..0000000000 --- a/changes/bug28925 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (bootstrap reporting): - - During bootstrap reporting, correctly distinguish pluggable - transports from plain proxies. Fixes bug 28925; bugfix on - 0.4.0.1-alpha. diff --git a/changes/bug29017 b/changes/bug29017 deleted file mode 100644 index 5c4a53c43f..0000000000 --- a/changes/bug29017 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (stats): - - When ExtraInfoStatistics is 0, stop including PaddingStatistics in - relay and bridge extra-info documents. Fixes bug 29017; - bugfix on 0.3.1.1-alpha. diff --git a/changes/bug29036 b/changes/bug29036 deleted file mode 100644 index 8b96c5c8fa..0000000000 --- a/changes/bug29036 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfix (continuous integration): - - Reset coverage state on disk after Travis CI has finished. This is being - done to prevent future gcda file merge errors which causes the test suite - for the process subsystem to fail. The process subsystem was introduced - in 0.4.0.1-alpha. Fixes bug 29036; bugfix on 0.2.9.15. diff --git a/changes/bug29144 b/changes/bug29144 deleted file mode 100644 index 5801224f14..0000000000 --- a/changes/bug29144 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (logging): - - Log the correct port number for listening sockets when "auto" is - used to let Tor pick the port number. Previously, port 0 was - logged instead of the actual port number. Fixes bug 29144; - bugfix on 0.3.5.1-alpha. Patch from Kris Katterjohn. diff --git a/changes/bug29241 b/changes/bug29241 deleted file mode 100644 index 7f25e154d1..0000000000 --- a/changes/bug29241 +++ /dev/null @@ -1,6 +0,0 @@ - o Major bugfixes (NSS, relay): - - When running with NSS, disable TLS 1.2 ciphersuites that use SHA384 - for their PRF. Due to an NSS bug, the TLS key exporters for these - ciphersuites don't work -- which caused relays to fail to handshake - with one another when these ciphersuites were enabled. - Fixes bug 29241; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug29500 b/changes/bug29500 deleted file mode 100644 index 16550935b2..0000000000 --- a/changes/bug29500 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (circuitpadding testing): - - Minor tweaks to avoid very rare test failures related to timers and - monotime. Fixes bug 29500; bugfix on 0.4.0.1-alpha diff --git a/changes/bug29527 b/changes/bug29527 deleted file mode 100644 index 6f36a9e1a0..0000000000 --- a/changes/bug29527 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (circuit padding): - - Stop warning about undefined behavior in the probability distribution - tests. Float division by zero may technically be undefined behaviour in - C, but it's well-defined in IEEE 754. Partial backport of 29298. - Closes ticket 29527; bugfix on 0.4.0.1-alpha. diff --git a/changes/bug29530_035 b/changes/bug29530_035 deleted file mode 100644 index 6dfcd51e7b..0000000000 --- a/changes/bug29530_035 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (testing): - - Downgrade some LOG_ERR messages in the address/* tests to warnings. - The LOG_ERR messages were occurring when we had no configured network. - We were failing the unit tests, because we backported 28668 to 0.3.5.8, - but did not backport 29530. Fixes bug 29530; bugfix on 0.3.5.8. diff --git a/changes/bug29562 b/changes/bug29562 deleted file mode 100644 index 0621cd09a0..0000000000 --- a/changes/bug29562 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (pluggable transports): - - Fix an assertion failure crash bug when a pluggable transport process is - terminated during the bootstrap phase. Fixes bug 29562; bugfix on - 0.4.0.1-alpha. diff --git a/changes/bug29599 b/changes/bug29599 deleted file mode 100644 index 14e2f5d077..0000000000 --- a/changes/bug29599 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (memory management, testing): - - Stop leaking parts of the shared random state in the shared-random unit - tests. Fixes bug 29599; bugfix on 0.2.9.1-alpha. diff --git a/changes/bug29601 b/changes/bug29601 deleted file mode 100644 index c4ba5fbc8b..0000000000 --- a/changes/bug29601 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (Windows, CI): - - Skip the Appveyor 32-bit Windows Server 2016 job, and 64-bit Windows - Server 2012 R2 job. The remaining 2 jobs still provide coverage of - 64/32-bit, and Windows Server 2016/2012 R2. Also set fast_finish, so - failed jobs terminate the build immediately. - Fixes bug 29601; bugfix on 0.3.5.4-alpha. diff --git a/changes/bug29665 b/changes/bug29665 deleted file mode 100644 index d89046faf5..0000000000 --- a/changes/bug29665 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor bugfixes (single onion services): - - Allow connections to single onion services to remain idle without - being disconnected. Relays acting as rendezvous points for - single onion services were mistakenly closing idle established - rendezvous circuits after 60 seconds, thinking that they are unused - directory-fetching circuits that had served their purpose. Fixes - bug 29665; bugfix on 0.2.1.26. diff --git a/changes/bug29693 b/changes/bug29693 deleted file mode 100644 index 33ce051c40..0000000000 --- a/changes/bug29693 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (unit tests): - - Decrease the false positive rate of stochastic probability distribution - tests. Fixes bug 29693; bugfix on 0.4.0.1-alpha. \ No newline at end of file diff --git a/changes/bug29703 b/changes/bug29703 deleted file mode 100644 index 0e17ee45e6..0000000000 --- a/changes/bug29703 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (testing): - - Backport the 0.3.4 src/test/test-network.sh to 0.2.9. - We need a recent test-network.sh to use new chutney features in CI. - Fixes bug 29703; bugfix on 0.2.9.1-alpha. diff --git a/changes/bug29706_minimal b/changes/bug29706_minimal deleted file mode 100644 index 9d4a43326c..0000000000 --- a/changes/bug29706_minimal +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (memory management, testing): - - Stop leaking parts of the shared random state in the shared-random unit - tests. The previous fix in 29599 was incomplete. - Fixes bug 29706; bugfix on 0.2.9.1-alpha. diff --git a/changes/bug29706_refactor b/changes/bug29706_refactor deleted file mode 100644 index ba1d0c7edd..0000000000 --- a/changes/bug29706_refactor +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (memory management): - - Refactor the shared random state's memory management so that it actually - takes ownership of the shared random value pointers. - Fixes bug 29706; bugfix on 0.2.9.1-alpha. diff --git a/changes/bug29874 b/changes/bug29874 deleted file mode 100644 index 8534753b51..0000000000 --- a/changes/bug29874 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (pluggable transports): - - Restore old behaviour when it comes to discovering the path of a given - Pluggable Transport exe-file. Fixes bug 29874; bugfix on 0.4.0.1-alpha. - diff --git a/changes/bug29922 b/changes/bug29922 deleted file mode 100644 index dacb951097..0000000000 --- a/changes/bug29922 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (testing, windows): - - Fix a test failure caused by an unexpected bug warning in - our test for tor_gmtime_r(-1). Fixes bug 29922; - bugfix on 0.2.9.3-alpha. diff --git a/changes/bug29930 b/changes/bug29930 deleted file mode 100644 index a99b11430b..0000000000 --- a/changes/bug29930 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (UI): - - Lower log level of unlink() errors during bootstrap. Fixes bug 29930; - bugfix on 0.4.0.1-alpha. - diff --git a/changes/bug29959-040 b/changes/bug29959-040 deleted file mode 100644 index 3740e0169a..0000000000 --- a/changes/bug29959-040 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (directory authorities): - - Actually include the bandwidth-file-digest line in directory authority - votes. Fixes bug 29959; bugfix on 0.4.0.2-alpha. diff --git a/changes/bug30001 b/changes/bug30001 deleted file mode 100644 index 52e58872ef..0000000000 --- a/changes/bug30001 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (testing): - - Use the approx_time() function when setting the "Expires" header - in directory replies, to make them more testable. Needed for - ticket 30001. - o Minor bug fixes (testing): - - Check the time in the "Expires" header with approx_time(). - Fixes bug 30001; bugfix on 0.4.0.4-rc. diff --git a/changes/bug30011 b/changes/bug30011 deleted file mode 100644 index 4c9069e291..0000000000 --- a/changes/bug30011 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (CI): - - Terminate test-stem if it takes more than 9.5 minutes to run. - (Travis terminates the job after 10 minutes of no output.) - Diagnostic for 29437. Fixes bug 30011; bugfix on 0.3.5.4-alpha. diff --git a/changes/bug30021 b/changes/bug30021 deleted file mode 100644 index 2a887f3cf2..0000000000 --- a/changes/bug30021 +++ /dev/null @@ -1,8 +0,0 @@ - o Minor bugfixes (TLS protocol, integration tests): - - When classifying a client's selection of TLS ciphers, if the client - ciphers are not yet available, do not cache the result. Previously, - we had cached the unavailability of the cipher list and never looked - again, which in turn led us to assume that the client only supported - the ancient V1 link protocol. This, in turn, was causing Stem - integration tests to stall in some cases. - Fixes bug 30021; bugfix on 0.2.4.8-alpha. diff --git a/changes/bug30040 b/changes/bug30040 deleted file mode 100644 index 7d80528a10..0000000000 --- a/changes/bug30040 +++ /dev/null @@ -1,9 +0,0 @@ - o Minor bugfixes (security): - - Fix a potential double free bug when reading huge bandwidth files. The - issue is not exploitable in the current Tor network because the - vulnerable code is only reached when directory authorities read bandwidth - files, but bandwidth files come from a trusted source (usually the - authorities themselves). Furthermore, the issue is only exploitable in - rare (non-POSIX) 32-bit architectures which are not used by any of the - current authorities. Fixes bug 30040; bugfix on 0.3.5.1-alpha. Bug found - and fixed by Tobias Stoeckmann. diff --git a/changes/bug30041 b/changes/bug30041 deleted file mode 100644 index 801c8f67ac..0000000000 --- a/changes/bug30041 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (hardening): - - Verify in more places that we are not about to create a buffer - with more than INT_MAX bytes, to avoid possible OOB access in the event - of bugs. Fixes bug 30041; bugfix on 0.2.0.16. Found and fixed by - Tobias Stoeckmann. diff --git a/changes/bug30263 b/changes/bug30263 deleted file mode 100644 index ba81c1b8a1..0000000000 --- a/changes/bug30263 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (shellcheck): - - Stop looking for scripts in the build directory during - "make shellcheck". Fixes bug 30263; bugfix on 0.4.0.1-alpha. diff --git a/changes/cid1444119 b/changes/cid1444119 deleted file mode 100644 index bb6854e66f..0000000000 --- a/changes/cid1444119 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (C correctness): - - Fix an unlikely memory leak in consensus_diff_apply(). Fixes bug 29824; - bugfix on 0.3.1.1-alpha. This is Coverity warning CID 1444119. diff --git a/changes/diagnostic_28223_redux b/changes/diagnostic_28223_redux deleted file mode 100644 index 0d7499832e..0000000000 --- a/changes/diagnostic_28223_redux +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (diagnostic): - - Add more diagnostic log messages in an attempt to solve - the issue of NUL bytes appearing in a microdescriptor cache. - Related to ticket 28223. diff --git a/changes/doc29121 b/changes/doc29121 deleted file mode 100644 index dd31cc9c70..0000000000 --- a/changes/doc29121 +++ /dev/null @@ -1,3 +0,0 @@ - o Documentation: - - Clarify that Tor performs stream isolation between *Port listeners by - default. Resolves issue 29121. diff --git a/changes/geoip-2019-03-04 b/changes/geoip-2019-03-04 deleted file mode 100644 index c8ce5dad5d..0000000000 --- a/changes/geoip-2019-03-04 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (geoip): - - Update geoip and geoip6 to the March 4 2019 Maxmind GeoLite2 - Country database. Closes ticket 29666. - diff --git a/changes/geoip-2019-04-02 b/changes/geoip-2019-04-02 deleted file mode 100644 index 7302d939f6..0000000000 --- a/changes/geoip-2019-04-02 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (geoip): - - Update geoip and geoip6 to the April 2 2019 Maxmind GeoLite2 - Country database. Closes ticket 29992. - diff --git a/changes/ticket21377 b/changes/ticket21377 deleted file mode 100644 index 2bf5149a0a..0000000000 --- a/changes/ticket21377 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (dircache): - - When a directory authority is using a bandwidth file to obtain the - bandwidth values that will be included in the next vote, serve this - bandwidth file at /tor/status-vote/next/bandwidth. Closes ticket 21377. \ No newline at end of file diff --git a/changes/ticket29357 b/changes/ticket29357 deleted file mode 100644 index 3aab930cd4..0000000000 --- a/changes/ticket29357 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (dormant mode): - - Add a DormantCanceledByStartup option to tell Tor that it should - treat a startup event as cancelling any previous dormant state. - Integrators should use this option with caution: it should - only be used if Tor is being started because of something that the - user did, and not if Tor is being automatically started in the - background. Closes ticket 29357. diff --git a/changes/ticket29435 b/changes/ticket29435 deleted file mode 100644 index d48ae98e4b..0000000000 --- a/changes/ticket29435 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (testing): - - Fix our gcov wrapper script to look for object files at the - correct locations. Fixes bug 29435; bugfix on 0.3.5.1-alpha. diff --git a/changes/ticket29631 b/changes/ticket29631 deleted file mode 100644 index 9fc194ba96..0000000000 --- a/changes/ticket29631 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (Rust, protover): - - The Rust implementation of protover was missing the "Padding" value in - the translate function from C to Rust. Fixes bug 29631; bugfix on - 0.4.0.1-alpha. diff --git a/changes/ticket29806 b/changes/ticket29806 deleted file mode 100644 index 6afefd4c04..0000000000 --- a/changes/ticket29806 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (bandwidth authority): - - Make bandwidth authorities to ignore relays that are reported in the - bandwidth file with the key-value "vote=0". - This change allows to report the relays that were not measured due - some failure and diagnose the reasons without the bandwidth being included in the - bandwidth authorities vote. - Closes ticket 29806. diff --git a/changes/ticket29897 b/changes/ticket29897 deleted file mode 100644 index 232a79fbce..0000000000 --- a/changes/ticket29897 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Refactor handle_get_next_bandwidth() to use connection_dir_buf_add(). - Implements ticket 29897. diff --git a/changes/ticket29962 b/changes/ticket29962 deleted file mode 100644 index e36cc0cf9a..0000000000 --- a/changes/ticket29962 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (continuous integration): - - On Travis Rust builds, cleanup Rust registry and refrain from caching - target/ directory to speed up builds. Resolves issue 29962. diff --git a/changes/ticket30117 b/changes/ticket30117 deleted file mode 100644 index 5b6e6dabf7..0000000000 --- a/changes/ticket30117 +++ /dev/null @@ -1,4 +0,0 @@ - o Testing (continuous integration): - - In Travis, tell timelimit to use stem's backtrace signals. And launch - python directly from timelimit, so python receives the signals from - timelimit, rather than make. Closes ticket 30117. -- cgit v1.2.3-54-g00ecf From ee36bfa6de95bf3d2214961d07edb001eb1ca150 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 30 Apr 2019 14:59:28 -0400 Subject: Changes file for improved dirauth modularity (ticket 30345) --- changes/ticket30345 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket30345 (limited to 'changes') diff --git a/changes/ticket30345 b/changes/ticket30345 new file mode 100644 index 0000000000..639db8d7ee --- /dev/null +++ b/changes/ticket30345 @@ -0,0 +1,3 @@ + o Minor features (modularity): + - The --disable-module-dirauth compile-time option now disables + even more dirauth-only code. Closes ticket 30345. -- cgit v1.2.3-54-g00ecf From 562bcbcfc216df9f25cd72f1e227b9313c872172 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 2 May 2019 11:10:41 -0400 Subject: sendme: Add changes file for prop289 Signed-off-by: David Goulet --- changes/ticket26288 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/ticket26288 (limited to 'changes') diff --git a/changes/ticket26288 b/changes/ticket26288 new file mode 100644 index 0000000000..59bb856dd2 --- /dev/null +++ b/changes/ticket26288 @@ -0,0 +1,6 @@ + o Major features (flow control): + - Implement authenticated SENDMEs detailed in proposal 289. A SENDME cell + now includes the digest of the last cell received so once the end point + receives the SENDME, it can confirm the other side's knowledge of the + previous cells that were sent. This behavior is controlled by two new + consensus parameters, see proposal for more details. Fixes ticket 26288. -- cgit v1.2.3-54-g00ecf From e9769d621769c2ee31657b6da25032d86f79b15d Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 6 May 2019 17:54:51 +0300 Subject: Hiding crypt_path_t: Add changes file. --- changes/bug30236 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/bug30236 (limited to 'changes') diff --git a/changes/bug30236 b/changes/bug30236 new file mode 100644 index 0000000000..ceaa98c8f1 --- /dev/null +++ b/changes/bug30236 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Refactor and encapsulate parts of the codebase that manipulate + crypt_path_t objects. Resolves issue 30236. \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 3c2648bbda53f74a4e960ad149600c3a2b12305c Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 2 May 2019 09:52:03 -0400 Subject: Move "relay" and "router" periodic callbacks out of mainloop.c (Some of these callbacks are specific to the OR module, so now it's time to have an or_sys and or_periodic.) --- changes/ticket30414 | 3 + src/app/main/shutdown.c | 6 - src/app/main/subsystem_list.c | 7 +- src/core/include.am | 6 + src/core/mainloop/mainloop.c | 288 ---------------------------------- src/core/mainloop/mainloop.h | 1 - src/core/or/circuitstats.c | 2 + src/core/or/or_periodic.c | 65 ++++++++ src/core/or/or_periodic.h | 17 ++ src/core/or/or_sys.c | 43 ++++++ src/core/or/or_sys.h | 17 ++ src/feature/relay/relay_periodic.c | 308 +++++++++++++++++++++++++++++++++++++ src/feature/relay/relay_periodic.h | 18 +++ src/feature/relay/relay_sys.c | 2 + src/feature/relay/selftest.c | 1 + 15 files changed, 488 insertions(+), 296 deletions(-) create mode 100644 changes/ticket30414 create mode 100644 src/core/or/or_periodic.c create mode 100644 src/core/or/or_periodic.h create mode 100644 src/core/or/or_sys.c create mode 100644 src/core/or/or_sys.h create mode 100644 src/feature/relay/relay_periodic.c create mode 100644 src/feature/relay/relay_periodic.h (limited to 'changes') diff --git a/changes/ticket30414 b/changes/ticket30414 new file mode 100644 index 0000000000..029ed1311f --- /dev/null +++ b/changes/ticket30414 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Move most relay-only periodic events out of mainloop.c into the + relay subsystem. Closes ticket 30414. diff --git a/src/app/main/shutdown.c b/src/app/main/shutdown.c index b8de0f37dc..1871717ad5 100644 --- a/src/app/main/shutdown.c +++ b/src/app/main/shutdown.c @@ -25,10 +25,7 @@ #include "core/or/circuitpadding.h" #include "core/or/connection_edge.h" #include "core/or/dos.h" -#include "core/or/policies.h" -#include "core/or/protover.h" #include "core/or/scheduler.h" -#include "core/or/versions.h" #include "feature/client/addressmap.h" #include "feature/client/bridges.h" #include "feature/client/entrynodes.h" @@ -136,19 +133,16 @@ tor_free_all(int postfork) microdesc_free_all(); routerparse_free_all(); control_free_all(); - protover_free_all(); bridges_free_all(); consdiffmgr_free_all(); hs_free_all(); dos_free_all(); circuitmux_ewma_free_all(); accounting_free_all(); - protover_summary_cache_free_all(); if (!postfork) { config_free_all(); or_state_free_all(); - policies_free_all(); } if (!postfork) { #ifndef _WIN32 diff --git a/src/app/main/subsystem_list.c b/src/app/main/subsystem_list.c index 00effe01aa..f595796232 100644 --- a/src/app/main/subsystem_list.c +++ b/src/app/main/subsystem_list.c @@ -10,19 +10,21 @@ #include "core/mainloop/mainloop_sys.h" #include "core/or/ocirc_event_sys.h" +#include "core/or/or_sys.h" #include "core/or/orconn_event_sys.h" #include "feature/control/btrack_sys.h" +#include "feature/relay/relay_sys.h" #include "lib/compress/compress_sys.h" #include "lib/crypt_ops/crypto_sys.h" #include "lib/err/torerr_sys.h" #include "lib/log/log_sys.h" #include "lib/net/network_sys.h" +#include "lib/process/process_sys.h" #include "lib/process/winprocess_sys.h" #include "lib/thread/thread_sys.h" #include "lib/time/time_sys.h" #include "lib/tls/tortls_sys.h" #include "lib/wallclock/wallclock_sys.h" -#include "lib/process/process_sys.h" #include "feature/dirauth/dirauth_sys.h" @@ -49,6 +51,9 @@ const subsys_fns_t *tor_subsystems[] = { &sys_btrack, /* -30 */ &sys_mainloop, /* 5 */ + &sys_or, /* 20 */ + + &sys_relay, /* 50 */ #ifdef HAVE_MODULE_DIRAUTH &sys_dirauth, /* 70 */ diff --git a/src/core/include.am b/src/core/include.am index d477cceb35..dfbdd82685 100644 --- a/src/core/include.am +++ b/src/core/include.am @@ -45,6 +45,8 @@ LIBTOR_APP_A_SOURCES = \ src/core/or/dos.c \ src/core/or/onion.c \ src/core/or/ocirc_event.c \ + src/core/or/or_periodic.c \ + src/core/or/or_sys.c \ src/core/or/orconn_event.c \ src/core/or/policies.c \ src/core/or/protover.c \ @@ -137,6 +139,7 @@ LIBTOR_APP_A_SOURCES = \ src/feature/relay/dns.c \ src/feature/relay/ext_orport.c \ src/feature/relay/onion_queue.c \ + src/feature/relay/relay_periodic.c \ src/feature/relay/relay_sys.c \ src/feature/relay/router.c \ src/feature/relay/routerkeys.c \ @@ -261,6 +264,8 @@ noinst_HEADERS += \ src/core/or/listener_connection_st.h \ src/core/or/onion.h \ src/core/or/or.h \ + src/core/or/or_periodic.h \ + src/core/or/or_sys.h \ src/core/or/orconn_event.h \ src/core/or/orconn_event_sys.h \ src/core/or/or_circuit_st.h \ @@ -406,6 +411,7 @@ noinst_HEADERS += \ src/feature/relay/dns_structs.h \ src/feature/relay/ext_orport.h \ src/feature/relay/onion_queue.h \ + src/feature/relay/relay_periodic.h \ src/feature/relay/relay_sys.h \ src/feature/relay/router.h \ src/feature/relay/routerkeys.h \ diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c index 4401f805d9..82042e8498 100644 --- a/src/core/mainloop/mainloop.c +++ b/src/core/mainloop/mainloop.c @@ -1342,28 +1342,18 @@ static int periodic_events_initialized = 0; #define CALLBACK(name) \ static int name ## _callback(time_t, const or_options_t *) CALLBACK(add_entropy); -CALLBACK(check_canonical_channels); -CALLBACK(check_descriptor); -CALLBACK(check_dns_honesty); -CALLBACK(check_ed_keys); CALLBACK(check_expired_networkstatus); -CALLBACK(check_for_reachability_bw); -CALLBACK(check_onion_keys_expiry_time); CALLBACK(clean_caches); CALLBACK(clean_consdiffmgr); -CALLBACK(expire_old_ciruits_serverside); CALLBACK(fetch_networkstatus); CALLBACK(heartbeat); CALLBACK(hs_service); CALLBACK(launch_descriptor_fetches); CALLBACK(prune_old_routers); -CALLBACK(reachability_warnings); CALLBACK(record_bridge_stats); CALLBACK(rend_cache_failure_clean); CALLBACK(reset_padding_counts); -CALLBACK(retry_dns); CALLBACK(retry_listeners); -CALLBACK(rotate_onion_key); CALLBACK(rotate_x509_certificate); CALLBACK(save_state); CALLBACK(write_stats_file); @@ -1408,20 +1398,6 @@ STATIC periodic_event_item_t mainloop_periodic_events[] = { CALLBACK(write_stats_file, NET_PARTICIPANT, FL(RUN_ON_DISABLE)), CALLBACK(prune_old_routers, NET_PARTICIPANT, FL(RUN_ON_DISABLE)), - /* Routers (bridge and relay) only. */ - CALLBACK(check_descriptor, ROUTER, FL(NEED_NET)), - CALLBACK(check_ed_keys, ROUTER, 0), - CALLBACK(check_for_reachability_bw, ROUTER, FL(NEED_NET)), - CALLBACK(check_onion_keys_expiry_time, ROUTER, 0), - CALLBACK(expire_old_ciruits_serverside, ROUTER, FL(NEED_NET)), - CALLBACK(reachability_warnings, ROUTER, FL(NEED_NET)), - CALLBACK(retry_dns, ROUTER, 0), - CALLBACK(rotate_onion_key, ROUTER, 0), - - /* Relay only. */ - CALLBACK(check_canonical_channels, RELAY, FL(NEED_NET)), - CALLBACK(check_dns_honesty, RELAY, FL(NEED_NET)), - /* Hidden Service service only. */ CALLBACK(hs_service, HS_SERVICE, FL(NEED_NET)), // XXXX break this down more @@ -1447,7 +1423,6 @@ STATIC periodic_event_item_t mainloop_periodic_events[] = { * implement particular callbacks. We keep them separate here so that we * can access them by name. We also keep them inside periodic_events[] * so that we can implement "reset all timers" in a reasonable way. */ -static periodic_event_item_t *check_descriptor_event=NULL; static periodic_event_item_t *fetch_networkstatus_event=NULL; static periodic_event_item_t *launch_descriptor_fetches_event=NULL; static periodic_event_item_t *check_dns_honesty_event=NULL; @@ -1544,7 +1519,6 @@ initialize_periodic_events(void) #define NAMED_CALLBACK(name) \ STMT_BEGIN name ## _event = periodic_events_find( #name ); STMT_END - NAMED_CALLBACK(check_descriptor); NAMED_CALLBACK(prune_old_routers); NAMED_CALLBACK(fetch_networkstatus); NAMED_CALLBACK(launch_descriptor_fetches); @@ -1556,7 +1530,6 @@ STATIC void teardown_periodic_events(void) { periodic_events_disconnect_all(); - check_descriptor_event = NULL; fetch_networkstatus_event = NULL; launch_descriptor_fetches_event = NULL; check_dns_honesty_event = NULL; @@ -1607,19 +1580,6 @@ periodic_events_on_new_options(const or_options_t *options) rescan_periodic_events(options); } -/** - * Update our schedule so that we'll check whether we need to update our - * descriptor immediately, rather than after up to CHECK_DESCRIPTOR_INTERVAL - * seconds. - */ -void -reschedule_descriptor_update_check(void) -{ - if (check_descriptor_event) { - periodic_event_reschedule(check_descriptor_event); - } -} - /** * Update our schedule so that we'll check whether we need to fetch directory * info immediately. @@ -1762,77 +1722,6 @@ second_elapsed_callback(time_t now, const or_options_t *options) return 1; } -/* Periodic callback: rotate the onion keys after the period defined by the - * "onion-key-rotation-days" consensus parameter, shut down and restart all - * cpuworkers, and update our descriptor if necessary. - */ -static int -rotate_onion_key_callback(time_t now, const or_options_t *options) -{ - if (server_mode(options)) { - int onion_key_lifetime = get_onion_key_lifetime(); - time_t rotation_time = get_onion_key_set_at()+onion_key_lifetime; - if (rotation_time > now) { - return ONION_KEY_CONSENSUS_CHECK_INTERVAL; - } - - log_info(LD_GENERAL,"Rotating onion key."); - rotate_onion_key(); - cpuworkers_rotate_keyinfo(); - if (router_rebuild_descriptor(1)<0) { - log_info(LD_CONFIG, "Couldn't rebuild router descriptor"); - } - if (advertised_server_mode() && !net_is_disabled()) - router_upload_dir_desc_to_dirservers(0); - return ONION_KEY_CONSENSUS_CHECK_INTERVAL; - } - return PERIODIC_EVENT_NO_UPDATE; -} - -/* Period callback: Check if our old onion keys are still valid after the - * period of time defined by the consensus parameter - * "onion-key-grace-period-days", otherwise expire them by setting them to - * NULL. - */ -static int -check_onion_keys_expiry_time_callback(time_t now, const or_options_t *options) -{ - if (server_mode(options)) { - int onion_key_grace_period = get_onion_key_grace_period(); - time_t expiry_time = get_onion_key_set_at()+onion_key_grace_period; - if (expiry_time > now) { - return ONION_KEY_CONSENSUS_CHECK_INTERVAL; - } - - log_info(LD_GENERAL, "Expiring old onion keys."); - expire_old_onion_keys(); - cpuworkers_rotate_keyinfo(); - return ONION_KEY_CONSENSUS_CHECK_INTERVAL; - } - - return PERIODIC_EVENT_NO_UPDATE; -} - -/* Periodic callback: Every 30 seconds, check whether it's time to make new - * Ed25519 subkeys. - */ -static int -check_ed_keys_callback(time_t now, const or_options_t *options) -{ - if (server_mode(options)) { - if (should_make_new_ed_keys(options, now)) { - int new_signing_key = load_ed_keys(options, now); - if (new_signing_key < 0 || - generate_ed_link_cert(options, now, new_signing_key > 0)) { - log_err(LD_OR, "Unable to update Ed25519 keys! Exiting."); - tor_shutdown_event_loop_and_exit(1); - } - } - return 30; - } - return PERIODIC_EVENT_NO_UPDATE; -} - /** * Periodic callback: Every {LAZY,GREEDY}_DESCRIPTOR_RETRY_INTERVAL, * see about fetching descriptors, microdescriptors, and extrainfo @@ -2053,17 +1942,6 @@ write_stats_file_callback(time_t now, const or_options_t *options) return safe_timer_diff(now, next_time_to_write_stats_files); } -#define CHANNEL_CHECK_INTERVAL (60*60) -static int -check_canonical_channels_callback(time_t now, const or_options_t *options) -{ - (void)now; - if (public_server_mode(options)) - channel_check_for_duplicates(); - - return CHANNEL_CHECK_INTERVAL; -} - static int reset_padding_counts_callback(time_t now, const or_options_t *options) { @@ -2137,19 +2015,6 @@ rend_cache_failure_clean_callback(time_t now, const or_options_t *options) return 30; } -/** - * Periodic callback: If we're a server and initializing dns failed, retry. - */ -static int -retry_dns_callback(time_t now, const or_options_t *options) -{ - (void)now; -#define RETRY_DNS_INTERVAL (10*60) - if (server_mode(options) && has_dns_init_failed()) - dns_init(); - return RETRY_DNS_INTERVAL; -} - /** * Periodic callback: prune routerlist of old information about Tor network. */ @@ -2171,71 +2036,6 @@ prune_old_routers_callback(time_t now, const or_options_t *options) return ROUTERLIST_PRUNING_INTERVAL; } -/** Periodic callback: consider rebuilding or and re-uploading our descriptor - * (if we've passed our internal checks). */ -static int -check_descriptor_callback(time_t now, const or_options_t *options) -{ -/** How often do we check whether part of our router info has changed in a - * way that would require an upload? That includes checking whether our IP - * address has changed. */ -#define CHECK_DESCRIPTOR_INTERVAL (60) - - (void)options; - - /* 2b. Once per minute, regenerate and upload the descriptor if the old - * one is inaccurate. */ - if (!net_is_disabled()) { - check_descriptor_bandwidth_changed(now); - check_descriptor_ipaddress_changed(now); - mark_my_descriptor_dirty_if_too_old(now); - consider_publishable_server(0); - } - - return CHECK_DESCRIPTOR_INTERVAL; -} - -/** - * Periodic callback: check whether we're reachable (as a relay), and - * whether our bandwidth has changed enough that we need to - * publish a new descriptor. - */ -static int -check_for_reachability_bw_callback(time_t now, const or_options_t *options) -{ - /* XXXX This whole thing was stuck in the middle of what is now - * XXXX check_descriptor_callback. I'm not sure it's right. */ - - static int dirport_reachability_count = 0; - /* also, check religiously for reachability, if it's within the first - * 20 minutes of our uptime. */ - if (server_mode(options) && - (have_completed_a_circuit() || !any_predicted_circuits(now)) && - !net_is_disabled()) { - if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { - router_do_reachability_checks(1, dirport_reachability_count==0); - if (++dirport_reachability_count > 5) - dirport_reachability_count = 0; - return 1; - } else { - /* If we haven't checked for 12 hours and our bandwidth estimate is - * low, do another bandwidth test. This is especially important for - * bridges, since they might go long periods without much use. */ - const routerinfo_t *me = router_get_my_routerinfo(); - static int first_time = 1; - if (!first_time && me && - me->bandwidthcapacity < me->bandwidthrate && - me->bandwidthcapacity < 51200) { - reset_bandwidth_test(); - } - first_time = 0; -#define BANDWIDTH_RECHECK_INTERVAL (12*60*60) - return BANDWIDTH_RECHECK_INTERVAL; - } - } - return CHECK_DESCRIPTOR_INTERVAL; -} - /** * Periodic event: once a minute, (or every second if TestingTorNetwork, or * during client bootstrap), check whether we want to download any @@ -2278,93 +2078,6 @@ retry_listeners_callback(time_t now, const or_options_t *options) return PERIODIC_EVENT_NO_UPDATE; } -/** - * Periodic callback: as a server, see if we have any old unused circuits - * that should be expired */ -static int -expire_old_ciruits_serverside_callback(time_t now, const or_options_t *options) -{ - (void)options; - /* every 11 seconds, so not usually the same second as other such events */ - circuit_expire_old_circuits_serverside(now); - return 11; -} - -/** - * Callback: Send warnings if Tor doesn't find its ports reachable. - */ -static int -reachability_warnings_callback(time_t now, const or_options_t *options) -{ - (void) now; - - if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { - return (int)(TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT - get_uptime()); - } - - if (server_mode(options) && - !net_is_disabled() && - have_completed_a_circuit()) { - /* every 20 minutes, check and complain if necessary */ - const routerinfo_t *me = router_get_my_routerinfo(); - if (me && !check_whether_orport_reachable(options)) { - char *address = tor_dup_ip(me->addr); - log_warn(LD_CONFIG,"Your server (%s:%d) has not managed to confirm that " - "its ORPort is reachable. Relays do not publish descriptors " - "until their ORPort and DirPort are reachable. Please check " - "your firewalls, ports, address, /etc/hosts file, etc.", - address, me->or_port); - control_event_server_status(LOG_WARN, - "REACHABILITY_FAILED ORADDRESS=%s:%d", - address, me->or_port); - tor_free(address); - } - - if (me && !check_whether_dirport_reachable(options)) { - char *address = tor_dup_ip(me->addr); - log_warn(LD_CONFIG, - "Your server (%s:%d) has not managed to confirm that its " - "DirPort is reachable. Relays do not publish descriptors " - "until their ORPort and DirPort are reachable. Please check " - "your firewalls, ports, address, /etc/hosts file, etc.", - address, me->dir_port); - control_event_server_status(LOG_WARN, - "REACHABILITY_FAILED DIRADDRESS=%s:%d", - address, me->dir_port); - tor_free(address); - } - } - - return TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT; -} - -static int dns_honesty_first_time = 1; - -/** - * Periodic event: if we're an exit, see if our DNS server is telling us - * obvious lies. - */ -static int -check_dns_honesty_callback(time_t now, const or_options_t *options) -{ - (void)now; - /* 9. and if we're an exit node, check whether our DNS is telling stories - * to us. */ - if (net_is_disabled() || - ! public_server_mode(options) || - router_my_exit_policy_is_reject_star()) - return PERIODIC_EVENT_NO_UPDATE; - - if (dns_honesty_first_time) { - /* Don't launch right when we start */ - dns_honesty_first_time = 0; - return crypto_rand_int_range(60, 180); - } - - dns_launch_correctness_checks(); - return 12*3600 + crypto_rand_int(12*3600); -} - static int heartbeat_callback_first_time = 1; /** @@ -2830,7 +2543,6 @@ tor_mainloop_free_all(void) can_complete_circuits = 0; quiet_level = 0; should_init_bridge_stats = 1; - dns_honesty_first_time = 1; heartbeat_callback_first_time = 1; current_second = 0; memset(¤t_second_last_changed, 0, diff --git a/src/core/mainloop/mainloop.h b/src/core/mainloop/mainloop.h index 3a611f81aa..cdc2bf8608 100644 --- a/src/core/mainloop/mainloop.h +++ b/src/core/mainloop/mainloop.h @@ -59,7 +59,6 @@ void directory_info_has_arrived(time_t now, int from_cache, int suppress_logs); void ip_address_changed(int at_interface); void dns_servers_relaunch_checks(void); void reset_all_main_loop_timers(void); -void reschedule_descriptor_update_check(void); void reschedule_directory_downloads(void); void reschedule_or_state_save(void); void mainloop_schedule_postloop_cleanup(void); diff --git a/src/core/or/circuitstats.c b/src/core/or/circuitstats.c index e5a3bac30b..03eea1d779 100644 --- a/src/core/or/circuitstats.c +++ b/src/core/or/circuitstats.c @@ -44,6 +44,7 @@ #include "lib/time/tvdiff.h" #include "lib/encoding/confline.h" #include "feature/dirauth/authmode.h" +#include "feature/relay/relay_periodic.h" #include "core/or/crypt_path_st.h" #include "core/or/origin_circuit_st.h" @@ -1420,6 +1421,7 @@ void circuit_build_times_network_is_live(circuit_build_times_t *cbt) { time_t now = approx_time(); + // XXXX this should use pubsub if (cbt->liveness.nonlive_timeouts > 0) { time_t time_since_live = now - cbt->liveness.network_last_live; log_notice(LD_CIRC, diff --git a/src/core/or/or_periodic.c b/src/core/or/or_periodic.c new file mode 100644 index 0000000000..93dfa8cf8b --- /dev/null +++ b/src/core/or/or_periodic.c @@ -0,0 +1,65 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file or_periodic.c + * @brief Periodic callbacks for the onion routing subsystem + **/ + +#include "orconfig.h" +#include "core/or/or.h" + +#include "core/mainloop/periodic.h" + +#include "core/or/channel.h" +#include "core/or/circuituse.h" +#include "core/or/or_periodic.h" + +#include "src/feature/relay/routermode.h" + +#define DECLARE_EVENT(name, roles, flags) \ + static periodic_event_item_t name ## _event = \ + PERIODIC_EVENT(name, \ + PERIODIC_EVENT_ROLE_##roles, \ + flags) + +#define FL(name) (PERIODIC_EVENT_FLAG_ ## name) + +#define CHANNEL_CHECK_INTERVAL (60*60) +static int +check_canonical_channels_callback(time_t now, const or_options_t *options) +{ + (void)now; + if (public_server_mode(options)) + channel_check_for_duplicates(); + + return CHANNEL_CHECK_INTERVAL; +} + +DECLARE_EVENT(check_canonical_channels, RELAY, FL(NEED_NET)); + +/** + * Periodic callback: as a server, see if we have any old unused circuits + * that should be expired */ +static int +expire_old_circuits_serverside_callback(time_t now, + const or_options_t *options) +{ + (void)options; + /* every 11 seconds, so not usually the same second as other such events */ + circuit_expire_old_circuits_serverside(now); + return 11; +} + +DECLARE_EVENT(expire_old_circuits_serverside, ROUTER, FL(NEED_NET)); + +void +or_register_periodic_events(void) +{ + // These are router-only events, but they're owned by the OR subsystem. */ + periodic_events_register(&check_canonical_channels_event); + periodic_events_register(&expire_old_circuits_serverside_event); +} diff --git a/src/core/or/or_periodic.h b/src/core/or/or_periodic.h new file mode 100644 index 0000000000..c2f47cf5ef --- /dev/null +++ b/src/core/or/or_periodic.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file or_periodic.h + * @brief Header for core/or/or_periodic.c + **/ + +#ifndef TOR_CORE_OR_OR_PERIODIC_H +#define TOR_CORE_OR_OR_PERIODIC_H + +void or_register_periodic_events(void); + +#endif /* !defined(TOR_CORE_OR_OR_PERIODIC_H) */ diff --git a/src/core/or/or_sys.c b/src/core/or/or_sys.c new file mode 100644 index 0000000000..6f8c81a4df --- /dev/null +++ b/src/core/or/or_sys.c @@ -0,0 +1,43 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file or_sys.c + * @brief Subsystem definitions for OR module. + **/ + +#include "orconfig.h" +#include "core/or/or.h" +#include "core/or/or_periodic.h" +#include "core/or/or_sys.h" +#include "core/or/policies.h" +#include "core/or/protover.h" +#include "core/or/versions.h" + +#include "lib/subsys/subsys.h" + +static int +subsys_or_initialize(void) +{ + or_register_periodic_events(); + return 0; +} + +static void +subsys_or_shutdown(void) +{ + protover_free_all(); + protover_summary_cache_free_all(); + policies_free_all(); +} + +const struct subsys_fns_t sys_or = { + .name = "or", + .supported = true, + .level = 20, + .initialize = subsys_or_initialize, + .shutdown = subsys_or_shutdown, +}; diff --git a/src/core/or/or_sys.h b/src/core/or/or_sys.h new file mode 100644 index 0000000000..c37ef01858 --- /dev/null +++ b/src/core/or/or_sys.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file or_sys.h + * @brief Header for core/or/or_sys.c + **/ + +#ifndef TOR_CORE_OR_OR_SYS_H +#define TOR_CORE_OR_OR_SYS_H + +extern const struct subsys_fns_t sys_or; + +#endif /* !defined(TOR_CORE_OR_OR_SYS_H) */ diff --git a/src/feature/relay/relay_periodic.c b/src/feature/relay/relay_periodic.c new file mode 100644 index 0000000000..8908b57415 --- /dev/null +++ b/src/feature/relay/relay_periodic.c @@ -0,0 +1,308 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_periodic.c + * @brief Periodic functions for the relay subsytem + **/ + +#include "orconfig.h" +#include "core/or/or.h" + +#include "core/mainloop/periodic.h" +#include "core/mainloop/cpuworker.h" // XXXX use a pubsub event. +#include "core/mainloop/mainloop.h" +#include "core/mainloop/netstatus.h" +#include "core/or/circuituse.h" // XXXX move have_performed_bandwidth_test + +#include "feature/relay/dns.h" +#include "feature/relay/relay_periodic.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "feature/relay/routermode.h" +#include "feature/relay/selftest.h" +#include "src/feature/stats/predict_ports.h" + +#include "lib/crypt_ops/crypto_rand.h" + +#include "feature/nodelist/routerinfo_st.h" +#include "feature/control/control_events.h" + +#define DECLARE_EVENT(name, roles, flags) \ + static periodic_event_item_t name ## _event = \ + PERIODIC_EVENT(name, \ + PERIODIC_EVENT_ROLE_##roles, \ + flags) + +#define FL(name) (PERIODIC_EVENT_FLAG_##name) + +/** + * Periodic callback: If we're a server and initializing dns failed, retry. + */ +static int +retry_dns_callback(time_t now, const or_options_t *options) +{ + (void)now; +#define RETRY_DNS_INTERVAL (10*60) + if (server_mode(options) && has_dns_init_failed()) + dns_init(); + return RETRY_DNS_INTERVAL; +} + +DECLARE_EVENT(retry_dns, ROUTER, 0); + +static int dns_honesty_first_time = 1; + +/** + * Periodic event: if we're an exit, see if our DNS server is telling us + * obvious lies. + */ +static int +check_dns_honesty_callback(time_t now, const or_options_t *options) +{ + (void)now; + /* 9. and if we're an exit node, check whether our DNS is telling stories + * to us. */ + if (net_is_disabled() || + ! public_server_mode(options) || + router_my_exit_policy_is_reject_star()) + return PERIODIC_EVENT_NO_UPDATE; + + if (dns_honesty_first_time) { + /* Don't launch right when we start */ + dns_honesty_first_time = 0; + return crypto_rand_int_range(60, 180); + } + + dns_launch_correctness_checks(); + return 12*3600 + crypto_rand_int(12*3600); +} + +DECLARE_EVENT(check_dns_honesty, RELAY, FL(NEED_NET)); + +/* Periodic callback: rotate the onion keys after the period defined by the + * "onion-key-rotation-days" consensus parameter, shut down and restart all + * cpuworkers, and update our descriptor if necessary. + */ +static int +rotate_onion_key_callback(time_t now, const or_options_t *options) +{ + if (server_mode(options)) { + int onion_key_lifetime = get_onion_key_lifetime(); + time_t rotation_time = get_onion_key_set_at()+onion_key_lifetime; + if (rotation_time > now) { + return ONION_KEY_CONSENSUS_CHECK_INTERVAL; + } + + log_info(LD_GENERAL,"Rotating onion key."); + rotate_onion_key(); + cpuworkers_rotate_keyinfo(); + if (router_rebuild_descriptor(1)<0) { + log_info(LD_CONFIG, "Couldn't rebuild router descriptor"); + } + if (advertised_server_mode() && !net_is_disabled()) + router_upload_dir_desc_to_dirservers(0); + return ONION_KEY_CONSENSUS_CHECK_INTERVAL; + } + return PERIODIC_EVENT_NO_UPDATE; +} + +DECLARE_EVENT(rotate_onion_key, ROUTER, 0); + +/** Periodic callback: consider rebuilding or and re-uploading our descriptor + * (if we've passed our internal checks). */ +static int +check_descriptor_callback(time_t now, const or_options_t *options) +{ +/** How often do we check whether part of our router info has changed in a + * way that would require an upload? That includes checking whether our IP + * address has changed. */ +#define CHECK_DESCRIPTOR_INTERVAL (60) + + (void)options; + + /* 2b. Once per minute, regenerate and upload the descriptor if the old + * one is inaccurate. */ + if (!net_is_disabled()) { + check_descriptor_bandwidth_changed(now); + check_descriptor_ipaddress_changed(now); + mark_my_descriptor_dirty_if_too_old(now); + consider_publishable_server(0); + } + + return CHECK_DESCRIPTOR_INTERVAL; +} + +DECLARE_EVENT(check_descriptor, ROUTER, FL(NEED_NET)); + +static int dirport_reachability_count = 0; + +/** + * Periodic callback: check whether we're reachable (as a relay), and + * whether our bandwidth has changed enough that we need to + * publish a new descriptor. + */ +static int +check_for_reachability_bw_callback(time_t now, const or_options_t *options) +{ + /* XXXX This whole thing was stuck in the middle of what is now + * XXXX check_descriptor_callback. I'm not sure it's right. */ + + /* also, check religiously for reachability, if it's within the first + * 20 minutes of our uptime. */ + if (server_mode(options) && + (have_completed_a_circuit() || !any_predicted_circuits(now)) && + !net_is_disabled()) { + if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { + router_do_reachability_checks(1, dirport_reachability_count==0); + if (++dirport_reachability_count > 5) + dirport_reachability_count = 0; + return 1; + } else { + /* If we haven't checked for 12 hours and our bandwidth estimate is + * low, do another bandwidth test. This is especially important for + * bridges, since they might go long periods without much use. */ + const routerinfo_t *me = router_get_my_routerinfo(); + static int first_time = 1; + if (!first_time && me && + me->bandwidthcapacity < me->bandwidthrate && + me->bandwidthcapacity < 51200) { + reset_bandwidth_test(); + } + first_time = 0; +#define BANDWIDTH_RECHECK_INTERVAL (12*60*60) + return BANDWIDTH_RECHECK_INTERVAL; + } + } + return CHECK_DESCRIPTOR_INTERVAL; +} + +DECLARE_EVENT(check_for_reachability_bw, ROUTER, FL(NEED_NET)); + +/** + * Callback: Send warnings if Tor doesn't find its ports reachable. + */ +static int +reachability_warnings_callback(time_t now, const or_options_t *options) +{ + (void) now; + + if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { + return (int)(TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT - get_uptime()); + } + + if (server_mode(options) && + !net_is_disabled() && + have_completed_a_circuit()) { + /* every 20 minutes, check and complain if necessary */ + const routerinfo_t *me = router_get_my_routerinfo(); + if (me && !check_whether_orport_reachable(options)) { + char *address = tor_dup_ip(me->addr); + log_warn(LD_CONFIG,"Your server (%s:%d) has not managed to confirm that " + "its ORPort is reachable. Relays do not publish descriptors " + "until their ORPort and DirPort are reachable. Please check " + "your firewalls, ports, address, /etc/hosts file, etc.", + address, me->or_port); + control_event_server_status(LOG_WARN, + "REACHABILITY_FAILED ORADDRESS=%s:%d", + address, me->or_port); + tor_free(address); + } + + if (me && !check_whether_dirport_reachable(options)) { + char *address = tor_dup_ip(me->addr); + log_warn(LD_CONFIG, + "Your server (%s:%d) has not managed to confirm that its " + "DirPort is reachable. Relays do not publish descriptors " + "until their ORPort and DirPort are reachable. Please check " + "your firewalls, ports, address, /etc/hosts file, etc.", + address, me->dir_port); + control_event_server_status(LOG_WARN, + "REACHABILITY_FAILED DIRADDRESS=%s:%d", + address, me->dir_port); + tor_free(address); + } + } + + return TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT; +} + +DECLARE_EVENT(reachability_warnings, ROUTER, FL(NEED_NET)); + +/* Periodic callback: Every 30 seconds, check whether it's time to make new + * Ed25519 subkeys. + */ +static int +check_ed_keys_callback(time_t now, const or_options_t *options) +{ + if (server_mode(options)) { + if (should_make_new_ed_keys(options, now)) { + int new_signing_key = load_ed_keys(options, now); + if (new_signing_key < 0 || + generate_ed_link_cert(options, now, new_signing_key > 0)) { + log_err(LD_OR, "Unable to update Ed25519 keys! Exiting."); + tor_shutdown_event_loop_and_exit(1); + } + } + return 30; + } + return PERIODIC_EVENT_NO_UPDATE; +} + +DECLARE_EVENT(check_ed_keys, ROUTER, 0); + +/* Period callback: Check if our old onion keys are still valid after the + * period of time defined by the consensus parameter + * "onion-key-grace-period-days", otherwise expire them by setting them to + * NULL. + */ +static int +check_onion_keys_expiry_time_callback(time_t now, const or_options_t *options) +{ + if (server_mode(options)) { + int onion_key_grace_period = get_onion_key_grace_period(); + time_t expiry_time = get_onion_key_set_at()+onion_key_grace_period; + if (expiry_time > now) { + return ONION_KEY_CONSENSUS_CHECK_INTERVAL; + } + + log_info(LD_GENERAL, "Expiring old onion keys."); + expire_old_onion_keys(); + cpuworkers_rotate_keyinfo(); + return ONION_KEY_CONSENSUS_CHECK_INTERVAL; + } + + return PERIODIC_EVENT_NO_UPDATE; +} + +DECLARE_EVENT(check_onion_keys_expiry_time, ROUTER, 0); + +void +relay_register_periodic_events(void) +{ + periodic_events_register(&retry_dns_event); + periodic_events_register(&check_dns_honesty_event); + periodic_events_register(&rotate_onion_key_event); + periodic_events_register(&check_descriptor_event); + periodic_events_register(&check_for_reachability_bw_event); + periodic_events_register(&reachability_warnings_event); + periodic_events_register(&check_ed_keys_event); + periodic_events_register(&check_onion_keys_expiry_time_event); + + dns_honesty_first_time = 1; + dirport_reachability_count = 0; +} + +/** + * Update our schedule so that we'll check whether we need to update our + * descriptor immediately, rather than after up to CHECK_DESCRIPTOR_INTERVAL + * seconds. + */ +void +reschedule_descriptor_update_check(void) +{ + periodic_event_reschedule(&check_descriptor_event); +} diff --git a/src/feature/relay/relay_periodic.h b/src/feature/relay/relay_periodic.h new file mode 100644 index 0000000000..b6ea83c749 --- /dev/null +++ b/src/feature/relay/relay_periodic.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_periodic.h + * @brief Header for feature/relay/relay_periodic.c + **/ + +#ifndef TOR_FEATURE_RELAY_RELAY_PERIODIC_H +#define TOR_FEATURE_RELAY_RELAY_PERIODIC_H + +void relay_register_periodic_events(void); +void reschedule_descriptor_update_check(void); + +#endif /* !defined(TOR_FEATURE_RELAY_RELAY_PERIODIC_H) */ diff --git a/src/feature/relay/relay_sys.c b/src/feature/relay/relay_sys.c index 4fdd3d3584..106e88b2a5 100644 --- a/src/feature/relay/relay_sys.c +++ b/src/feature/relay/relay_sys.c @@ -15,6 +15,7 @@ #include "feature/relay/dns.h" #include "feature/relay/ext_orport.h" #include "feature/relay/onion_queue.h" +#include "feature/relay/relay_periodic.h" #include "feature/relay/relay_sys.h" #include "feature/relay/routerkeys.h" #include "feature/relay/router.h" @@ -24,6 +25,7 @@ static int subsys_relay_initialize(void) { + relay_register_periodic_events(); return 0; } diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c index eeddd09b63..f8b54ff45d 100644 --- a/src/feature/relay/selftest.c +++ b/src/feature/relay/selftest.c @@ -35,6 +35,7 @@ #include "feature/nodelist/routerlist.h" // but... #include "feature/nodelist/routerset.h" #include "feature/nodelist/torcert.h" +#include "feature/relay/relay_periodic.h" #include "feature/relay/router.h" #include "feature/relay/selftest.h" -- cgit v1.2.3-54-g00ecf From 3cafdeb8c0f1dfa60a964e4fba04b54d1ad97d15 Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Tue, 7 May 2019 11:24:53 -0400 Subject: Only call tor_addr_parse() in circuit_is_acceptable() when needed --- changes/bug22210 | 7 +++++++ scripts/maint/practracker/exceptions.txt | 4 ++-- src/core/or/circuituse.c | 17 ++++++++++------- 3 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 changes/bug22210 (limited to 'changes') diff --git a/changes/bug22210 b/changes/bug22210 new file mode 100644 index 0000000000..d7a00fd72c --- /dev/null +++ b/changes/bug22210 @@ -0,0 +1,7 @@ + o Minor bugfixes (onion services, performance): + - If we are building circuits to onion services, in circuit_is_acceptable() + we only call tor_addr_parse() in places where we use the returned + family and address values from this function. Previously, we called + tor_addr_parse() in circuit_is_acceptable() even if it wasn't used. + This change will improve performance when building circuits. Fixes + bug 22210; bugfix on 0.2.8.12. Patch by Neel Chauhan diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index 21fe9ec351..8623b00a26 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -92,8 +92,8 @@ problem function-size /src/core/or/circuitlist.c:circuits_handle_oom() 117 problem function-size /src/core/or/circuitmux.c:circuitmux_set_policy() 110 problem function-size /src/core/or/circuitmux.c:circuitmux_attach_circuit() 114 problem function-size /src/core/or/circuitstats.c:circuit_build_times_parse_state() 124 -problem file-size /src/core/or/circuituse.c 3152 -problem function-size /src/core/or/circuituse.c:circuit_is_acceptable() 129 +problem file-size /src/core/or/circuituse.c 3155 +problem function-size /src/core/or/circuituse.c:circuit_is_acceptable() 133 problem function-size /src/core/or/circuituse.c:circuit_expire_building() 394 problem function-size /src/core/or/circuituse.c:circuit_log_ancient_one_hop_circuits() 126 problem function-size /src/core/or/circuituse.c:circuit_build_failed() 149 diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c index 2f27cf996f..226295425e 100644 --- a/src/core/or/circuituse.c +++ b/src/core/or/circuituse.c @@ -178,7 +178,6 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, purpose == CIRCUIT_PURPOSE_S_HSDIR_POST || purpose == CIRCUIT_PURPOSE_C_HSDIR_GET) { tor_addr_t addr; - const int family = tor_addr_parse(&addr, conn->socks_request->address); if (!exitnode && !build_state->onehop_tunnel) { log_debug(LD_CIRC,"Not considering circuit with unknown router."); return 0; /* this circuit is screwed and doesn't know it yet, @@ -199,6 +198,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, return 0; /* this is a circuit to somewhere else */ if (tor_digest_is_zero(digest)) { /* we don't know the digest; have to compare addr:port */ + const int family = tor_addr_parse(&addr, + conn->socks_request->address); if (family < 0 || !tor_addr_eq(&build_state->chosen_exit->addr, &addr) || build_state->chosen_exit->port != conn->socks_request->port) @@ -211,12 +212,14 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, return 0; } } - if (origin_circ->prepend_policy && family != -1) { - int r = compare_tor_addr_to_addr_policy(&addr, - conn->socks_request->port, - origin_circ->prepend_policy); - if (r == ADDR_POLICY_REJECTED) - return 0; + if (origin_circ->prepend_policy) { + if (tor_addr_parse(&addr, conn->socks_request->address) != -1) { + int r = compare_tor_addr_to_addr_policy(&addr, + conn->socks_request->port, + origin_circ->prepend_policy); + if (r == ADDR_POLICY_REJECTED) + return 0; + } } if (exitnode && !connection_ap_can_use_exit(conn, exitnode)) { /* can't exit from this router */ -- cgit v1.2.3-54-g00ecf From 0a4e68e4e24849a8d95dfa9ca0eb773b2cda6ebf Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sat, 11 May 2019 19:03:46 +0300 Subject: Add changes file --- changes/bug30286 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/bug30286 (limited to 'changes') diff --git a/changes/bug30286 b/changes/bug30286 new file mode 100644 index 0000000000..f2fc67a484 --- /dev/null +++ b/changes/bug30286 @@ -0,0 +1,4 @@ + o Minor bugfixes (developer tooling): + - Fix pre-push hook to refrain from rejecting fixup and squash commits + when pushing to non-upstream git remote. Fixes bug 30286; bugfix on + 0.4.0.1-alpha. -- cgit v1.2.3-54-g00ecf From 0d275ec592761390c5ee05b2acdf5ae193c2a0ca Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Wed, 17 Apr 2019 23:37:22 +0000 Subject: Changes file for bugs28693+30173+29203. --- changes/bugs28693+30173+29203 | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 changes/bugs28693+30173+29203 (limited to 'changes') diff --git a/changes/bugs28693+30173+29203 b/changes/bugs28693+30173+29203 new file mode 100644 index 0000000000..9faa6279bf --- /dev/null +++ b/changes/bugs28693+30173+29203 @@ -0,0 +1,12 @@ + o Minor bugfixes (circuit padding): + - Add a torrc option to disable circuit padding. Fixes bug 28693; bugfix + on 0.4.0.1-alpha. + o Minor bugfixes (circuit padding): + - Provide consensus parameter to fully disable circuit padding, to be used + in emergency network overload situations. Fixes bug 30173; bugfix on + 0.4.0.1-alpha. + o Minor bugfixes (circuit padding): + - Allow circuit padding machines to specify that they do not contribute + much overhead, and provide consensus flags and torrc options to force + clients to only use low overhead machines. Fixes bug 29203; bugfix on + 0.4.0.1-alpha. -- cgit v1.2.3-54-g00ecf From 9e5c27bd2c278238d003b2fc1891d5de48b766d7 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 14 May 2019 20:22:30 -0400 Subject: changes file for ticket 28878 --- changes/ticket28878 | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 changes/ticket28878 (limited to 'changes') diff --git a/changes/ticket28878 b/changes/ticket28878 new file mode 100644 index 0000000000..73ca47c72f --- /dev/null +++ b/changes/ticket28878 @@ -0,0 +1,11 @@ + o Minor features (testing): + - The circuitpadding tests now use a reproducible RNG implementation, + so that if a test fails, we can learn why. Part of ticket 28878. + - Tor's tests now support an environment variable, TOR_TEST_RNG_SEED, + to set the RNG seed for tests that use a reproducible RNG. + Part of ticket 28878. + + o Minor features (continuous integration): + - When running coverage builds on Travis, we now set TOR_TEST_RNG_SEED, + to avoid RNG-based coverage differences. + Part of ticket 28878. -- cgit v1.2.3-54-g00ecf From 5ef0d89d912c2b4cbf42510df5f609b3704ede73 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Wed, 8 May 2019 00:50:52 +0000 Subject: Bug 29085: Changes file. --- changes/bug29085 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/bug29085 (limited to 'changes') diff --git a/changes/bug29085 b/changes/bug29085 new file mode 100644 index 0000000000..b17c06378f --- /dev/null +++ b/changes/bug29085 @@ -0,0 +1,4 @@ + o Code simplification and refactoring (circuit padding): + - Avoid calling monotime_absolute_usec() in circuit padding machines + that do not use token removal or circuit RTT estimation. Fixes bug + 29085; bugfix on 0.4.0.1-alpha. -- cgit v1.2.3-54-g00ecf From 5cc988a947e8ba10e2682274465a82ff22e7c93d Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Thu, 18 Apr 2019 20:35:22 +0000 Subject: Bug 28780: Changes file --- changes/ticket28780 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket28780 (limited to 'changes') diff --git a/changes/ticket28780 b/changes/ticket28780 new file mode 100644 index 0000000000..d7c6693f8c --- /dev/null +++ b/changes/ticket28780 @@ -0,0 +1,3 @@ + o Minor features (circuit padding): + - Provide the ability for circuit padding machines to hold a circuit open + until they are done padding it. Closes ticket 28780. -- cgit v1.2.3-54-g00ecf From 58cb98af32e8436eccf9536255b8158271f1c03d Mon Sep 17 00:00:00 2001 From: "Iain R. Learmonth" Date: Thu, 16 May 2019 12:54:31 +0100 Subject: Prop 301: No longer vote on RecommendedPackages This is the first half of implementing proposal 301. The RecommendedPackages torrc option is marked as obsolete and the test cases for the option removed. Additionally, the code relating to generating and formatting package lines in votes is removed. These lines may still appear in votes from other directory authorities running earlier versions of the code and so consensuses may still contain package lines. A new consensus method will be needed to stop including package lines in consensuses. Fixes: #28465 --- changes/ticket29738 | 6 ++++++ doc/tor.1.txt | 6 ------ src/app/config/config.c | 9 +-------- src/app/config/or_options_st.h | 1 - src/feature/dirauth/dirvote.c | 26 -------------------------- src/test/test_options.c | 24 ------------------------ 6 files changed, 7 insertions(+), 65 deletions(-) create mode 100644 changes/ticket29738 (limited to 'changes') diff --git a/changes/ticket29738 b/changes/ticket29738 new file mode 100644 index 0000000000..9217cc9a5f --- /dev/null +++ b/changes/ticket29738 @@ -0,0 +1,6 @@ + o Minor features (recommended packages): + - No longer include recommended packages in votes as detailed in proposal + 301. The RecommendedPackages torrc option is deprecated and will no + longer have any effect. "package" lines will still be considered when + computing consensuses for consensus methods that include them. Fixes + ticket 29738. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 4bd365c774..064259b15f 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -2720,12 +2720,6 @@ on the public Tor network. multiple times: the values from multiple lines are spliced together. When this is set then **VersioningAuthoritativeDirectory** should be set too. -[[RecommendedPackages]] **RecommendedPackages** __PACKAGENAME__ __VERSION__ __URL__ __DIGESTTYPE__**=**__DIGEST__ :: - Adds "package" line to the directory authority's vote. This information - is used to vote on the correct URL and digest for the released versions - of different Tor-related packages, so that the consensus can certify - them. This line may appear any number of times. - [[RecommendedClientVersions]] **RecommendedClientVersions** __STRING__:: STRING is a comma-separated list of Tor versions currently believed to be safe for clients to use. This information is included in version 2 diff --git a/src/app/config/config.c b/src/app/config/config.c index d03305627b..4382a44723 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -593,7 +593,7 @@ static config_var_t option_vars_[] = { V(RecommendedVersions, LINELIST, NULL), V(RecommendedClientVersions, LINELIST, NULL), V(RecommendedServerVersions, LINELIST, NULL), - V(RecommendedPackages, LINELIST, NULL), + OBSOLETE("RecommendedPackages"), V(ReducedConnectionPadding, BOOL, "0"), V(ConnectionPadding, AUTOBOOL, "auto"), V(RefuseUnknownExits, AUTOBOOL, "auto"), @@ -3521,13 +3521,6 @@ options_validate(or_options_t *old_options, or_options_t *options, "features to be broken in unpredictable ways."); } - for (cl = options->RecommendedPackages; cl; cl = cl->next) { - if (! validate_recommended_package_line(cl->value)) { - log_warn(LD_CONFIG, "Invalid RecommendedPackage line %s will be ignored", - escaped(cl->value)); - } - } - if (options->AuthoritativeDir) { if (!options->ContactInfo && !options->TestingTorNetwork) REJECT("Authoritative directory servers must set ContactInfo"); diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h index 4e03bec7fa..7e79834f8c 100644 --- a/src/app/config/or_options_st.h +++ b/src/app/config/or_options_st.h @@ -121,7 +121,6 @@ struct or_options_t { struct config_line_t *RecommendedVersions; struct config_line_t *RecommendedClientVersions; struct config_line_t *RecommendedServerVersions; - struct config_line_t *RecommendedPackages; /** Whether dirservers allow router descriptors with private IPs. */ int DirAllowPrivateAddresses; /** Whether routers accept EXTEND cells to routers with private IPs. */ diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index b841ab240f..0084fea1e3 100644 --- a/src/feature/dirauth/dirvote.c +++ b/src/feature/dirauth/dirvote.c @@ -220,7 +220,6 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, networkstatus_t *v3_ns) { smartlist_t *chunks = smartlist_new(); - char *packages = NULL; char fingerprint[FINGERPRINT_LEN+1]; char digest[DIGEST_LEN]; uint32_t addr; @@ -246,19 +245,6 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, v3_ns->server_versions); protocols_lines = format_protocols_lines_for_vote(v3_ns); - if (v3_ns->package_lines) { - smartlist_t *tmp = smartlist_new(); - SMARTLIST_FOREACH(v3_ns->package_lines, const char *, p, - if (validate_recommended_package_line(p)) - smartlist_add_asprintf(tmp, "package %s\n", p)); - smartlist_sort_strings(tmp); - packages = smartlist_join_strings(tmp, "", 0, NULL); - SMARTLIST_FOREACH(tmp, char *, cp, tor_free(cp)); - smartlist_free(tmp); - } else { - packages = tor_strdup(""); - } - /* Get shared random commitments/reveals line(s). */ shared_random_vote_str = sr_get_string_for_vote(); @@ -344,7 +330,6 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, "voting-delay %d %d\n" "%s%s" /* versions */ "%s" /* protocols */ - "%s" /* packages */ "known-flags %s\n" "flag-thresholds %s\n" "params %s\n" @@ -361,7 +346,6 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, client_versions_line, server_versions_line, protocols_lines, - packages, flags, flag_thresholds, params, @@ -461,7 +445,6 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, tor_free(client_versions_line); tor_free(server_versions_line); tor_free(protocols_lines); - tor_free(packages); SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); smartlist_free(chunks); @@ -4669,15 +4652,6 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, tor_assert_nonfatal(protover_all_supported( v3_out->recommended_client_protocols, NULL)); - v3_out->package_lines = smartlist_new(); - { - config_line_t *cl; - for (cl = get_options()->RecommendedPackages; cl; cl = cl->next) { - if (validate_recommended_package_line(cl->value)) - smartlist_add_strdup(v3_out->package_lines, cl->value); - } - } - v3_out->known_flags = smartlist_new(); smartlist_split_string(v3_out->known_flags, DIRVOTE_UNIVERSAL_FLAGS, diff --git a/src/test/test_options.c b/src/test/test_options.c index 396be6b18d..d693fe0568 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -1342,29 +1342,6 @@ test_options_validate__token_bucket(void *ignored) tor_free(msg); } -static void -test_options_validate__recommended_packages(void *ignored) -{ - (void)ignored; - int ret; - char *msg; - setup_capture_of_logs(LOG_WARN); - options_test_data_t *tdata = get_options_test_data( - "RecommendedPackages foo 1.2 http://foo.com sha1=123123123123\n" - "RecommendedPackages invalid-package-line\n"); - - ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg); - tt_int_op(ret, OP_EQ, -1); - expect_no_log_msg("Invalid RecommendedPackage line " - "invalid-package-line will be ignored\n"); - - done: - escaped(NULL); // This will free the leaking memory from the previous escaped - teardown_capture_of_logs(); - free_options_test_data(tdata); - tor_free(msg); -} - static void test_options_validate__fetch_dir(void *ignored) { @@ -4200,7 +4177,6 @@ struct testcase_t options_tests[] = { LOCAL_VALIDATE_TEST(exclude_nodes), LOCAL_VALIDATE_TEST(node_families), LOCAL_VALIDATE_TEST(token_bucket), - LOCAL_VALIDATE_TEST(recommended_packages), LOCAL_VALIDATE_TEST(fetch_dir), LOCAL_VALIDATE_TEST(conn_limit), LOCAL_VALIDATE_TEST(paths_needed), -- cgit v1.2.3-54-g00ecf From 6246f4539ed317e05b773b0e373f1aa369d3759d Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 16 May 2019 15:38:08 -0400 Subject: changes file for coverity fixes in tests (30150) --- changes/ticket30150 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket30150 (limited to 'changes') diff --git a/changes/ticket30150 b/changes/ticket30150 new file mode 100644 index 0000000000..70808fa5db --- /dev/null +++ b/changes/ticket30150 @@ -0,0 +1,4 @@ + o Minor bugfixes (static analysis): + - Fix several spurious Coverity warnings about the unit tests, to lower our + chances of missing any real warnings in the future. Fixes bug 30150; + bugfix on 0.3.5.1-alpha and various other Tor versions. -- cgit v1.2.3-54-g00ecf From 1a79bedd97bb67931b87c0ec7e53ceceb77ea754 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Thu, 16 May 2019 20:25:25 +0000 Subject: Changes file. --- changes/ticket28634 | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 changes/ticket28634 (limited to 'changes') diff --git a/changes/ticket28634 b/changes/ticket28634 new file mode 100644 index 0000000000..7ba05e5c55 --- /dev/null +++ b/changes/ticket28634 @@ -0,0 +1,10 @@ + o Major features (Circuit padding): + - Onion service clients will now add padding cells to the initial portions + of their INTRODUCE and RENDEZVOUS circuits, to make those circuits' + traffic patterns look more like general purpose Exit traffic. The + overhead for this is 2 extra cells in each direction for RENDEZVOUS + circuits, and 1 extra upstream cell and 10 downstream cells for INTRODUCE + circuits. This will only be enabled if the circuit's middle node supports + this feature, too. (Clients may specify fixed middle nodes with the MiddleNodes + torrc directive, and may force-disable this feature with the CircuitPadding + torrc directive). Closes ticket 28634. -- cgit v1.2.3-54-g00ecf From aa4f2f739737edd8d1570474ee459d5b98713aba Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 17 May 2019 10:12:07 -0400 Subject: Initial changelog draft for 0.4.1.1-alpha (mostly automated) --- ChangeLog | 432 ++++++++++++++++++++++++++++++++++++++++++ changes/bug17357 | 7 - changes/bug22210 | 7 - changes/bug22781 | 4 - changes/bug23576 | 7 - changes/bug23588 | 5 - changes/bug24338 | 4 - changes/bug24490 | 5 - changes/bug28269 | 7 - changes/bug28636 | 8 - changes/bug29018 | 5 - changes/bug29061 | 4 - changes/bug29063 | 2 - changes/bug29085 | 4 - changes/bug29204 | 4 - changes/bug29221 | 5 - changes/bug29231 | 4 - changes/bug29243 | 3 - changes/bug29298 | 6 - changes/bug29613 | 5 - changes/bug29640 | 4 - changes/bug29805 | 3 - changes/bug29823 | 5 - changes/bug29926 | 2 - changes/bug29939 | 4 - changes/bug30002 | 2 - changes/bug30109 | 3 - changes/bug30148 | 4 - changes/bug30151 | 5 - changes/bug30189 | 4 - changes/bug30190 | 3 - changes/bug30236 | 3 - changes/bug30309 | 3 - changes/bug30452 | 3 - changes/bug30475 | 4 - changes/bugs28693+30173+29203 | 12 -- changes/coverity_falsepos | 4 - changes/feature29532 | 4 - changes/geoip-2019-05-13 | 4 - changes/pubsub | 5 - changes/ticket25110 | 4 - changes/ticket25417 | 4 - changes/ticket25614 | 3 - changes/ticket26069 | 2 - changes/ticket26288 | 6 - changes/ticket27251 | 4 - changes/ticket27821 | 3 - changes/ticket28634 | 10 - changes/ticket28780 | 3 - changes/ticket28816 | 4 - changes/ticket28837 | 4 - changes/ticket28913 | 4 - changes/ticket29059 | 3 - changes/ticket29060 | 2 - changes/ticket29062 | 3 - changes/ticket29064 | 2 - changes/ticket29065 | 3 - changes/ticket29067 | 3 - changes/ticket29068 | 2 - changes/ticket29070 | 2 - changes/ticket29071 | 3 - changes/ticket29108 | 5 - changes/ticket29391 | 3 - changes/ticket29434 | 3 - changes/ticket29436 | 4 - changes/ticket29536 | 9 - changes/ticket29537 | 3 - changes/ticket29542 | 7 - changes/ticket29553 | 5 - changes/ticket29588 | 4 - changes/ticket29635 | 3 - changes/ticket29660 | 5 - changes/ticket29662 | 5 - changes/ticket29732 | 5 - changes/ticket29756 | 3 - changes/ticket29894 | 4 - changes/ticket29913 | 4 - changes/ticket29984 | 5 - changes/ticket30007 | 3 - changes/ticket30033 | 4 - changes/ticket30051 | 5 - changes/ticket30075 | 3 - changes/ticket30076 | 2 - changes/ticket30077 | 2 - changes/ticket30078 | 3 - changes/ticket30079 | 3 - changes/ticket30091 | 4 - changes/ticket30114 | 3 - changes/ticket30149 | 3 - changes/ticket30176 | 4 - changes/ticket30213 | 3 - changes/ticket30234 | 2 - changes/ticket30261 | 4 - changes/ticket30293 | 5 - changes/ticket30307 | 4 - changes/ticket30308 | 5 - changes/ticket30345 | 3 - changes/ticket30414 | 3 - 98 files changed, 432 insertions(+), 396 deletions(-) delete mode 100644 changes/bug17357 delete mode 100644 changes/bug22210 delete mode 100644 changes/bug22781 delete mode 100644 changes/bug23576 delete mode 100644 changes/bug23588 delete mode 100644 changes/bug24338 delete mode 100644 changes/bug24490 delete mode 100644 changes/bug28269 delete mode 100644 changes/bug28636 delete mode 100644 changes/bug29018 delete mode 100644 changes/bug29061 delete mode 100644 changes/bug29063 delete mode 100644 changes/bug29085 delete mode 100644 changes/bug29204 delete mode 100644 changes/bug29221 delete mode 100644 changes/bug29231 delete mode 100644 changes/bug29243 delete mode 100644 changes/bug29298 delete mode 100644 changes/bug29613 delete mode 100644 changes/bug29640 delete mode 100644 changes/bug29805 delete mode 100644 changes/bug29823 delete mode 100644 changes/bug29926 delete mode 100644 changes/bug29939 delete mode 100644 changes/bug30002 delete mode 100644 changes/bug30109 delete mode 100644 changes/bug30148 delete mode 100644 changes/bug30151 delete mode 100644 changes/bug30189 delete mode 100644 changes/bug30190 delete mode 100644 changes/bug30236 delete mode 100644 changes/bug30309 delete mode 100644 changes/bug30452 delete mode 100644 changes/bug30475 delete mode 100644 changes/bugs28693+30173+29203 delete mode 100644 changes/coverity_falsepos delete mode 100644 changes/feature29532 delete mode 100644 changes/geoip-2019-05-13 delete mode 100644 changes/pubsub delete mode 100644 changes/ticket25110 delete mode 100644 changes/ticket25417 delete mode 100644 changes/ticket25614 delete mode 100644 changes/ticket26069 delete mode 100644 changes/ticket26288 delete mode 100644 changes/ticket27251 delete mode 100644 changes/ticket27821 delete mode 100644 changes/ticket28634 delete mode 100644 changes/ticket28780 delete mode 100644 changes/ticket28816 delete mode 100644 changes/ticket28837 delete mode 100644 changes/ticket28913 delete mode 100644 changes/ticket29059 delete mode 100644 changes/ticket29060 delete mode 100644 changes/ticket29062 delete mode 100644 changes/ticket29064 delete mode 100644 changes/ticket29065 delete mode 100644 changes/ticket29067 delete mode 100644 changes/ticket29068 delete mode 100644 changes/ticket29070 delete mode 100644 changes/ticket29071 delete mode 100644 changes/ticket29108 delete mode 100644 changes/ticket29391 delete mode 100644 changes/ticket29434 delete mode 100644 changes/ticket29436 delete mode 100644 changes/ticket29536 delete mode 100644 changes/ticket29537 delete mode 100644 changes/ticket29542 delete mode 100644 changes/ticket29553 delete mode 100644 changes/ticket29588 delete mode 100644 changes/ticket29635 delete mode 100644 changes/ticket29660 delete mode 100644 changes/ticket29662 delete mode 100644 changes/ticket29732 delete mode 100644 changes/ticket29756 delete mode 100644 changes/ticket29894 delete mode 100644 changes/ticket29913 delete mode 100644 changes/ticket29984 delete mode 100644 changes/ticket30007 delete mode 100644 changes/ticket30033 delete mode 100644 changes/ticket30051 delete mode 100644 changes/ticket30075 delete mode 100644 changes/ticket30076 delete mode 100644 changes/ticket30077 delete mode 100644 changes/ticket30078 delete mode 100644 changes/ticket30079 delete mode 100644 changes/ticket30091 delete mode 100644 changes/ticket30114 delete mode 100644 changes/ticket30149 delete mode 100644 changes/ticket30176 delete mode 100644 changes/ticket30213 delete mode 100644 changes/ticket30234 delete mode 100644 changes/ticket30261 delete mode 100644 changes/ticket30293 delete mode 100644 changes/ticket30307 delete mode 100644 changes/ticket30308 delete mode 100644 changes/ticket30345 delete mode 100644 changes/ticket30414 (limited to 'changes') diff --git a/ChangeLog b/ChangeLog index a69a7253b0..827c4c3131 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,435 @@ +Changes in version 0.4.1.1-alpha - 2019-05-?? + This is the first alpha in the 0.4.1.x series. It introduces + lightweight circuit padding to make some onion-service circuits harder + to distinguish, includes a new "authenticated SENDME" feature to make + certain denial-of-service attacks more difficult, and improves + performance in several areas. + + o Major features (Circuit padding): + - Onion service clients will now add padding cells to the initial + portions of their INTRODUCE and RENDEZVOUS circuits, to make those + circuits' traffic patterns look more like general purpose Exit + traffic. The overhead for this is 2 extra cells in each direction + for RENDEZVOUS circuits, and 1 extra upstream cell and 10 + downstream cells for INTRODUCE circuits. This will only be enabled + if the circuit's middle node supports this feature, too. (Clients + may specify fixed middle nodes with the MiddleNodes torrc + directive, and may force-disable this feature with the + CircuitPadding torrc directive). Closes ticket 28634. + + o Major features (code organization): + - Tor now includes a generic publish-subscribe message-passing + subsystem that we can use to organize intermodule dependencies. We + hope to use this to reduce dependencies between modules that don't + need to be related, and to generally simplify our codebase. Closes + ticket 28226. + + o Major features (controller protocol): + - Controller commands are now parsed using a generalized parsing + subsystem. Previously, each controller command was responsible for + parsing its own input. Closes ticket 30091. + + o Major features (flow control): + - Implement authenticated SENDMEs detailed in proposal 289. A SENDME + cell now includes the digest of the last cell received so once the + end point receives the SENDME, it can confirm the other side's + knowledge of the previous cells that were sent. This behavior is + controlled by two new consensus parameters, see proposal for more + details. Fixes ticket 26288. + + o Major features (performance): + - Update our node selection algorithm to exclude nodes in linear + time. Previously, the algorithm was quadratic, which could slow + down heavily used onion services. Closes ticket 30307. + + o Minor feature (circuit padding): + - We now use a fast RNG when scheduling circuit padding. Part of + ticket 28636. + + o Minor feature (maintenance scripts): + - Add to scripts/maint/ helper maintainer scripts used for git + maintenance. Closes ticket 29391. + + o Minor features (circuit padding): + - Allow the padding machine designer to pick the edges of their + histogram instead of trying to compute them automatically using an + exponential formula. Resolves some undefined behavior in the case + of small histograms and allows greater flexibility on machine + design. Closes ticket 29298; bugfix on 0.4.0.1-alpha. + - Provide the ability for circuit padding machines to hold a circuit + open until they are done padding it. Closes ticket 28780. + + o Minor features (compile-time modules): + - Add a --list-modules command to print a list of which compile-time + modules are enabled. Closes ticket 30452. + + o Minor features (continuous integration): + - Remove sudo configuration lines from .travis.yml as they are no + longer needed with current Travis build environment. Resolves + issue 30213. + + o Minor features (controller): + - Add onion service version 3 support to HSFETCH. Previously, only + version 2 onion services were supported. Closes ticket 25417. + Patch by Neel Chauhan + + o Minor features (debugging): + - Introduce tor_assertf() and tor_assertf_nonfatal() to enable + logging of additional information during assert failure. Now we + can use format strings to include pieces of information that are + relevant for trouble shooting. Resolves ticket 29662. + + o Minor features (defense in depth): + - In smartlist_remove_keeporder(), set any pointers that become + unused to NULL, in case a bug causes them to be used later. Closes + ticket 30176. Patch from Tobias Stoeckmann. + - Tor now uses a fast cryptographically strong PRNG even for + decisions that we do not believe are security-sensitive. + Previously, for performance reasons, we had used a trivially + predictable linear congruential generator algorithm for certain + load-balancing and statistical sampling decisions. Now we use our + fast RNG in those cases. Closes ticket 29542. + + o Minor features (developer tooling): + - Call practracker from pre-push and pre-commit git hooks to let a + developer know if they made any code style violations in their + last commit. This should help preventing code style violations + appearing upstream. Closes ticket 30051. + - Call pre-commit git hook from pre-push hook to make sure we're + running documentation and code style checks before pushing to + remote git repository. Implements feature 30033. + - Modify git pre-push hook script to disallow pushing branches other + than master, release-* and maint-* to origin remote. Implements + feature 29532. + + o Minor features (developer tools): + - Add a script to check that each header has a well-formed and + unique guard marco. Closes ticket 29756. + - Introduce a post-merge git hook script to check if we're pulling + in any changes to our git workspace management scripts from + upstream. Resolves issue 29588. + + o Minor features (development tools): + - Tor's test scripts now check for files and functions that seem too + long and complicated. Existing overlong functions and files are + accepted for now, but should eventually be refactored. Closes + ticket 29221. + + o Minor features (geoip): + - Update geoip and geoip6 to the May 13 2019 Maxmind GeoLite2 + Country database. Closes ticket 30522. + + o Minor features (git scripts): + - In git-pull-all.sh, also fetch the latest tor-github pull + requests. Implements ticket 30114. + + o Minor features (HTTP tunnel): + - Return an informative web page when the HTTPTunnelPort is used as + an HTTP proxy. Closes ticket 27821, patch by "eighthave". + + o Minor features (IPv6, v3 onion services): + - Make v3 onion services put IPv6 addresses in service descriptors. + Before this change, service descriptors only contained IPv4 + addressesd. Implements 26992. + + o Minor features (modularity): + - The --disable-module-dirauth compile-time option now disables even + more dirauth-only code. Closes ticket 30345. + + o Minor features (performance): + - Use OpenSSL's implementations of SHA3 when available (in OpenSSL + 1.1.1 and later), since they tend to be faster than tiny-keccak. + Closes ticket 28837. + + o Minor features (performance, RNG): + - Tor now constructs a fast secure pseudorandom number generator for + each thread, to use for cases where performance is critical. This + PRNG is based on AES-CTR, using a buffering construction similar + to libottery and the (newer) OpenBSD arc4random() code. It + outperforms OpenSSL 1.1.1a's CSPRNG by roughly a factor of 100 for + small outputs. Although we believe it to be cryptographically + strong, we are only using it when necessary for reasonable + performance. Implements tickets 29023 and 29536. + + o Minor features (testing): + - Tor's unit test code now contains a standard set of functions to + replace the PRNG with a deterministic or reproducible version for + testing. Previously, various tests implemented this in various + ways. Implements ticket 29732. + - We now have a script, cov-test-determinism.sh, to identify places + where our unit test coverage has become nondeterministic. Closes + ticket 29436. + + o Minor bugfixes (bridge authority): + - We set bridges as running when we dump the bridge status to a + file. Previously, we set bridges as running in a GETINFO + controller, but these shouldn't modify vital data structures. + Fixes bug 24490; bugfix on 0.2.0.13-alpha. Patch by Neel Chauhan + + o Minor bugfixes (Channel padding statistics): + - Channel padding write totals and padding-enabled totals are now + counted properly in relay extrainfo descriptors. Fixes bug 29231; + bugfix on 0.3.1.1-alpha + + o Minor bugfixes (circuit padding): + - Add a torrc option to disable circuit padding. Fixes bug 28693; + bugfix on 0.4.0.1-alpha. + - Allow circuit padding machines to specify that they do not + contribute much overhead, and provide consensus flags and torrc + options to force clients to only use low overhead machines. Fixes + bug 29203; bugfix on 0.4.0.1-alpha. + - Provide consensus parameter to fully disable circuit padding, to + be used in emergency network overload situations. Fixes bug 30173; + bugfix on 0.4.0.1-alpha. + - The circuit padding subsystem does not schedule padding if dormant + mode is enabled. Fixes bug 28636; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (circuitpadding): + - Inspect circuit-level cell queue before sending padding, to avoid + sending padding while too much data is queued. Fixes bug 29204; + bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (compilation, unusual configuration): + - Avoid failures when building with ALL_BUGS_ARE_FAILED due to + missing declarations of abort(), and prevent other such failures + in the future. Fixes bug 30189; bugfix on 0.3.4.1-alpha. + + o Minor bugfixes (controller protocol): + - Teach the controller parser to correctly distinguish an object + preceded by an argument list from one without. Previously, it + couldn't distinguish an argument list from the first line of a + multiline object. Fixes bug 29984; bugfix on 0.2.3.8-alpha. + + o Minor bugfixes (developer tools): + - Update our pre-commit.git-hook script to work correctly on older + Tor branches and release branches without any changes files, and + to actually exit when something fails. Fixes bug 29553; bugfix + on 0.4.0.2-alpha. + + o Minor bugfixes (dirauth, ipv6): + - If we are a durauth with IPv6 and are marking relays as running, + mark ourselves as reachable on IPv6. Fixes bug 24338; bugfix on + 0.4.0.2-alpha. Patch by Neel Chauhan + + o Minor bugfixes (documentation): + - Improve the documentation for MapAddress .exit. Fixes bug 30109; + bugfix on 0.1.0.1-rc. + - Improve the monotonic time module and function documentation. + Explain what "monotonic" actually means, and document some results + that have surprised people. Fixes bug 29640; bugfix + on 0.2.9.1-alpha. + + o Minor bugfixes (documentation, manpage): + - Use proper formatting when providing an example on quoting options + that contain whitespace. Fixes bug 29635; bugfix on 0.2.3.18-rc. + + o Minor bugfixes (lib): + + o Minor bugfixes (logging): + - Do not log a warning for OpenSSL versions that should be + compatible. Fixes bug 30190; bugfix on 0.2.4.2-alpha + + o Minor bugfixes (logging, configuration): + - Warn operators when MyFamily option is set but ContactInfo is + missing, as the latter should be set too. Fixes bug 25110; bugfix + on 0.3.3.1-alpha. + + o Minor bugfixes (memory leak): + - Avoid a minor memory leak that could occur on relays when creating + a keys directory failed. Fixes bug 30148; bugfix on 0.3.3.1-alpha. + + o Minor bugfixes (onion services): + - Avoid a GCC 9.1.1 warning (and possible crash depending on libc + implemenation) when failing to load an onion service client + authorization file. Fixes bug 30475; bugfix on 0.3.5.1-alpha. + - If we are launching repeated HSFETCH queries and are rate-limited, + we introduce a new controller response QUERY_RATE_LIMITED instead + of QUERY_NO_HSDIR, while keeping the latter for when onion service + directories are missing a descriptor. Previously, we returned + QUERY_NO_HSDIR for both cases. Fixes bug 28269; bugfix on + 0.3.1.1-alpha. Patch by Neel Chauhan + - If we are relaunching a circuit to a rendevous service in + rend_service_relaunch_rendezvous() and + hs_service_requires_uptime_circ() is true, the + CIRCLAUNCH_NEED_UPTIME flag is added to the circuit. Previously, + we only set this flag when we received a INTRODUCE2 cell in + rend_service_receive_introduction(). Fixes bug 17357; bugfix on + 0.4.0.2-alpha. Patch by Neel Chauhan + + o Minor bugfixes (onion services, performance): + - If we are building circuits to onion services, in + circuit_is_acceptable() we only call tor_addr_parse() in places + where we use the returned family and address values from this + function. Previously, we called tor_addr_parse() in + circuit_is_acceptable() even if it wasn't used. This change will + improve performance when building circuits. Fixes bug 22210; + bugfix on 0.2.8.12. Patch by Neel Chauhan + + o Minor bugfixes (performance): + - When checking a node for bridge status, use a fast check to make + sure that its identity is set. Previously, we used a constant-time + check, which is not necessary when verifying a BUG() condition that + causes a stack trace. Fixes bug 30308; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (pluggable transports): + - Tor now sets TOR_PT_EXIT_ON_STDIN_CLOSE=1 for client transports as + well as servers. Fixes bug 25614; bugfix on 0.2.7.1-alpha. + + o Minor bugfixes (probability distributions): + - Refactor and improve parts of the probability distribution code + that made Coverity complain. Fixes bug 29805; bugfix + on 0.4.0.1-alpha. + + o Minor bugfixes (python): + - Stop assuming that /usr/bin/python3 exists. For scripts that work + with python2, use /usr/bin/python. Otherwise, use /usr/bin/env + python3. Fixes bug 29913; bugfix on 0.2.5.3-alpha. + + o Minor bugfixes (relay): + - If we are are a relay and have IPv6Exit to 1 while ExitRelay is + auto, we act as if ExitRelay is 1. Previously, we ignored IPv6Exit + if ExitRelay was 0 or auto. Fixes bug 29613; bugfix on + 0.3.5.1-alpha. Patch by Neel Chauhan. + + o Minor bugfixes (stats): + - When ExtraInfoStatistics is 0, stop including bandwidth usage + statistics, GeoIPFile hashes, ServerTransportPlugin lines, and + bridge statistics by country in extra-info documents. Fixes bug + 29018; bugfix on 0.2.4.1-alpha. + + o Minor bugfixes (testing): + - Call setrlimit() to disable core dumps in test_bt_cl.c instead of + using `ulimit -c` in test_bt.sh, which violates POSIX shell + compatibility. Fixes bug 29061; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (testing, v3 onion services): + - Fix some incorrect code in the v3 onion service unit tests. Fixes + bug 29243; bugfix on 0.3.2.1-alpha. + + o Minor bugfixes (tor-resolve): + - Fix a memory leak in tor-resolve that could happen if Tor gave it + a malformed SOCKS response. (Memory leaks in tor-resolve don't + actually matter, but it's good to fix them anyway.) Fixes bug + 30151; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (unit tests): + - In the "routerkeys/*" tests, check the return values of mkdir() + for possible failures. Fixes bug 29939; bugfix on 0.2.7.2-alpha. + Found by Coverity as CID 1444254. + - Split test_utils_general() to several smaller test functions in + test_utils_general(). This makes it easier to perform resource + deallocation on assert failure and fixes Coverity warnings CID + 1444117 and CID 1444118. Fixes bug 29823; bugfix on 0.2.9.1-alpha. + + o Minor bugfixes (v3 onion services): + - Stop ignoring IPv6 link specifiers sent to v3 onion services. v3 + onion service IPv6 support is still incomplete, see 23493 for + details. Fixes bug 23588; bugfix on 0.3.2.1-alpha. Patch by + Neel Chauhan. + + o Code simplification and refactoring: + - Abstract out the low-level formatting of replies on the control + port. Implements ticket 30007. + - Add several assertions in an attempt to fix some Coverity + warnings. Closes ticket 30149. + - Introduce a connection_dir_buf_add() helper function that checks + for compress_state of dir_connection_t and automatically writes a + string to directory connection with or without compression. + Resolves issue 28816. + - Make the base32_decode() API return the number of bytes written, + for consistency with base64_decode(). Closes ticket 28913. + - Move most relay-only periodic events out of mainloop.c into the + relay subsystem. Closes ticket 30414. + - Refactor and encapsulate parts of the codebase that manipulate + crypt_path_t objects. Resolves issue 30236. + - Refactor several places in our code that coverity incorrectly + believed that we might have memory leaks, so that we can analyze + our software more easily. Closes ticket 30147. + - Remove redundant return values in crypto_format, and the + associated return value checks elsewhere in the code. Make the + implementations in crypto_format consistent, and remove redundant + code. Resolves ticket 29660. + - Rename tor_mem_is_zero() to fast_mem_is_zero(), to emphasize that + it is not a constant-time function. Closes ticket 30309. + - Replace hs_desc_link_specifier_t with link_specifier_t, and remove + all hs_desc_link_specifier_t-specific code. Fixes bug 22781; + bugfix on 0.3.2.1-alpha. + - Simplify v3 onion service link specifier handling code. Fixes bug + 23576; bugfix on 0.3.2.1-alpha. + - Split crypto_digest.c into three parts: 1) general code that does + not depend on either NSS or OpenSSL (stays in crypto_digest.c); 2) + code that depends on NSS API (moved to crypto_digest_nss.c); 3) + code that depends on OpenSSL API (moved to + crypto_digest_openssl.c). Resolves ticket 29108. + - Split up the control.c file into several submodules, in + preparation for distributing its current responsibilities + throughout the codebase. Closes ticket 29894. + - Start move responsibility for knowing about periodic events to the + appropriate subsystems, so that the mainloop doesn't need to know + all the periodic events in the rest of the codebase. Implements + tickets 30293 and 30294. + + o Documentation: + - Document how to find git commits and tags for bug fixes in + CodingStandards.md. And update some changes file documentation. + Closes ticket 30261. + + o Removed features: + - Remove linux-tor-prio.sh script from contrib/operator-tools + directory. Resolves issue 29434. + - Remove obsolete OpenSUSE initscript. Resolves issue 30076. + - Remove the obsolete script at contrib/dist/tor.sh.in. Resolves + issue 30075. + + o Testing: + - Check that representative subsets of values of `int` and `unsigned + int` can be represented by `void *`. Resolves issue 29537. + + o Code simplification and refactoring (circuit padding): + - Avoid calling monotime_absolute_usec() in circuit padding machines + that do not use token removal or circuit RTT estimation. Fixes bug + 29085; bugfix on 0.4.0.1-alpha. + + o Code simplification and refactoring (shell scripts): + - Cleanup autogen.sh to silence shellcheck warnings. Closes + ticket 26069. + - Cleanup test_keygen.sh to silence all shellcheck warnings. Closes + ticket 29062. + - Cleanup test_switch_id.sh to silence shellcheck warnings. Closes + ticket 29065. + - Fix issues shellcheck found in test_rebind.sh. Resolves + issue 29063. + - Fix shellcheck warning SC2006 in src/test/fuzz/minimize.sh. + Resolves issue 30079. + - Fix shellcheck warning in test_rust.sh. Fixes issue 29064. + - Fix shellcheck warning in torify script. Resolves issue 29070. + - Fix shellcheck warnings in asciidoc-helper.sh. Resolves + issue 29926. + - Fix shellcheck warnings in fuzz_multi.sh. Resolves issue 30077. + - Fix shellcheck warnings in fuzz_static_testcases.sh. Resolves + ticket 29059. + - Fix shellcheck warnings in nagios-check-tor-authority-cert script. + Resolves issue 29071. + - Fix shellcheck warnings in src/test/fuzz/fixup_filenames.sh. + Resolves issue 30078. + - Fix shellcheck warnings in test-network.sh. Resolves issue 29060. + - Fix shellcheck warnings in test_key_expiration.sh. Resolves + issue 30002. + - Fix shellcheck warnings in zero_length_keys.sh. Resolves + issue 29068. + - Fix test_workqueue_*.sh scripts to silence shellcheck SC2086 + warnings. Fixes issue 29067. + + o Testing (chutney): + - In "make test-network-all", test IPv6-only v3 single onion + services, using the chutney network single-onion-v23-ipv6-md. This + test will not pass until 23588 has been merged. Closes + ticket 27251. + + o Testing (continuous integration): + - In Travis, show stem's tor log after failure. Closes ticket 30234. + + Changes in version 0.4.0.5 - 2019-05-02 This is the first stable release in the 0.4.0.x series. It contains improvements for power management and bootstrap reporting, as well as diff --git a/changes/bug17357 b/changes/bug17357 deleted file mode 100644 index 1188b65fd7..0000000000 --- a/changes/bug17357 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor bugfixes (onion services): - - If we are relaunching a circuit to a rendevous service in - rend_service_relaunch_rendezvous() and hs_service_requires_uptime_circ() - is true, the CIRCLAUNCH_NEED_UPTIME flag is added to the circuit. - Previously, we only set this flag when we received a INTRODUCE2 - cell in rend_service_receive_introduction(). Fixes bug 17357; - bugfix on 0.4.0.2-alpha. Patch by Neel Chauhan diff --git a/changes/bug22210 b/changes/bug22210 deleted file mode 100644 index d7a00fd72c..0000000000 --- a/changes/bug22210 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor bugfixes (onion services, performance): - - If we are building circuits to onion services, in circuit_is_acceptable() - we only call tor_addr_parse() in places where we use the returned - family and address values from this function. Previously, we called - tor_addr_parse() in circuit_is_acceptable() even if it wasn't used. - This change will improve performance when building circuits. Fixes - bug 22210; bugfix on 0.2.8.12. Patch by Neel Chauhan diff --git a/changes/bug22781 b/changes/bug22781 deleted file mode 100644 index 5606dfa5e2..0000000000 --- a/changes/bug22781 +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring: - - Replace hs_desc_link_specifier_t with link_specifier_t, - and remove all hs_desc_link_specifier_t-specific code. - Fixes bug 22781; bugfix on 0.3.2.1-alpha. diff --git a/changes/bug23576 b/changes/bug23576 deleted file mode 100644 index edcae02e5e..0000000000 --- a/changes/bug23576 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (IPv6, v3 onion services): - - Make v3 onion services put IPv6 addresses in service - descriptors. Before this change, service descriptors only - contained IPv4 addressesd. Implements 26992. - o Code simplification and refactoring: - - Simplify v3 onion service link specifier handling code. - Fixes bug 23576; bugfix on 0.3.2.1-alpha. diff --git a/changes/bug23588 b/changes/bug23588 deleted file mode 100644 index 86064ab313..0000000000 --- a/changes/bug23588 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (v3 onion services): - - Stop ignoring IPv6 link specifiers sent to v3 onion services. - v3 onion service IPv6 support is still incomplete, see 23493 for - details. Fixes bug 23588; bugfix on 0.3.2.1-alpha. - Patch by Neel Chauhan. diff --git a/changes/bug24338 b/changes/bug24338 deleted file mode 100644 index 75984b6329..0000000000 --- a/changes/bug24338 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (dirauth, ipv6): - - If we are a durauth with IPv6 and are marking relays as running, mark - ourselves as reachable on IPv6. Fixes bug 24338; bugfix on 0.4.0.2-alpha. - Patch by Neel Chauhan diff --git a/changes/bug24490 b/changes/bug24490 deleted file mode 100644 index cf9281c878..0000000000 --- a/changes/bug24490 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (bridge authority): - - We set bridges as running when we dump the bridge status to a file. - Previously, we set bridges as running in a GETINFO controller, but - these shouldn't modify vital data structures. Fixes bug 24490; - bugfix on 0.2.0.13-alpha. Patch by Neel Chauhan diff --git a/changes/bug28269 b/changes/bug28269 deleted file mode 100644 index bdfe9e1aae..0000000000 --- a/changes/bug28269 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor bugfixes (onion services): - - If we are launching repeated HSFETCH queries and are rate-limited, - we introduce a new controller response QUERY_RATE_LIMITED instead - of QUERY_NO_HSDIR, while keeping the latter for when onion service - directories are missing a descriptor. Previously, we returned - QUERY_NO_HSDIR for both cases. Fixes bug 28269; bugfix on - 0.3.1.1-alpha. Patch by Neel Chauhan diff --git a/changes/bug28636 b/changes/bug28636 deleted file mode 100644 index 240655cbea..0000000000 --- a/changes/bug28636 +++ /dev/null @@ -1,8 +0,0 @@ - o Minor bugfixes (circuit padding): - - The circuit padding subsystem does not schedule padding if dormant mode - is enabled. Fixes bug 28636; bugfix on 0.4.0.1-alpha. - - o Minor feature (circuit padding): - - We now use a fast RNG when scheduling circuit padding. Part of ticket - 28636. - diff --git a/changes/bug29018 b/changes/bug29018 deleted file mode 100644 index b006ae36a7..0000000000 --- a/changes/bug29018 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (stats): - - When ExtraInfoStatistics is 0, stop including bandwidth usage statistics, - GeoIPFile hashes, ServerTransportPlugin lines, and bridge statistics - by country in extra-info documents. Fixes bug 29018; - bugfix on 0.2.4.1-alpha. diff --git a/changes/bug29061 b/changes/bug29061 deleted file mode 100644 index 58fc4f22e9..0000000000 --- a/changes/bug29061 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (testing): - - Call setrlimit() to disable core dumps in test_bt_cl.c instead of - using `ulimit -c` in test_bt.sh, which violates POSIX shell - compatibility. Fixes bug 29061; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug29063 b/changes/bug29063 deleted file mode 100644 index 8cbcbebc6e..0000000000 --- a/changes/bug29063 +++ /dev/null @@ -1,2 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Fix issues shellcheck found in test_rebind.sh. Resolves issue 29063. diff --git a/changes/bug29085 b/changes/bug29085 deleted file mode 100644 index b17c06378f..0000000000 --- a/changes/bug29085 +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring (circuit padding): - - Avoid calling monotime_absolute_usec() in circuit padding machines - that do not use token removal or circuit RTT estimation. Fixes bug - 29085; bugfix on 0.4.0.1-alpha. diff --git a/changes/bug29204 b/changes/bug29204 deleted file mode 100644 index ec2cf67b2f..0000000000 --- a/changes/bug29204 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (circuitpadding): - - Inspect circuit-level cell queue before sending padding, to avoid - sending padding while too much data is queued. Fixes bug 29204; - bugfix on 0.4.0.1-alpha. diff --git a/changes/bug29221 b/changes/bug29221 deleted file mode 100644 index fbe08aa9a0..0000000000 --- a/changes/bug29221 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (development tools): - - Tor's test scripts now check for files and functions that seem - too long and complicated. Existing overlong functions and files are - accepted for now, but should eventually be refactored. Closes - ticket 29221. diff --git a/changes/bug29231 b/changes/bug29231 deleted file mode 100644 index bcc19e1b48..0000000000 --- a/changes/bug29231 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (Channel padding statistics): - - Channel padding write totals and padding-enabled totals are now - counted properly in relay extrainfo descriptors. Fixes bug 29231; - bugfix on 0.3.1.1-alpha diff --git a/changes/bug29243 b/changes/bug29243 deleted file mode 100644 index b5694f7568..0000000000 --- a/changes/bug29243 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (testing, v3 onion services): - - Fix some incorrect code in the v3 onion service unit tests. - Fixes bug 29243; bugfix on 0.3.2.1-alpha. diff --git a/changes/bug29298 b/changes/bug29298 deleted file mode 100644 index 6e447b62dd..0000000000 --- a/changes/bug29298 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor features (circuit padding): - - Allow the padding machine designer to pick the edges of their histogram - instead of trying to compute them automatically using an exponential - formula. Resolves some undefined behavior in the case of small histograms - and allows greater flexibility on machine design. Closes ticket 29298; - bugfix on 0.4.0.1-alpha. \ No newline at end of file diff --git a/changes/bug29613 b/changes/bug29613 deleted file mode 100644 index e966973255..0000000000 --- a/changes/bug29613 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (relay): - - If we are are a relay and have IPv6Exit to 1 while ExitRelay is - auto, we act as if ExitRelay is 1. Previously, we ignored IPv6Exit - if ExitRelay was 0 or auto. Fixes bug 29613; bugfix on 0.3.5.1-alpha. - Patch by Neel Chauhan. diff --git a/changes/bug29640 b/changes/bug29640 deleted file mode 100644 index 81adeae32a..0000000000 --- a/changes/bug29640 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (documentation): - - Improve the monotonic time module and function documentation. Explain - what "monotonic" actually means, and document some results that have - surprised people. Fixes bug 29640; bugfix on 0.2.9.1-alpha. diff --git a/changes/bug29805 b/changes/bug29805 deleted file mode 100644 index 00c846e9af..0000000000 --- a/changes/bug29805 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (probability distributions): - - Refactor and improve parts of the probability distribution code that made - Coverity complain. Fixes bug 29805; bugfix on 0.4.0.1-alpha. \ No newline at end of file diff --git a/changes/bug29823 b/changes/bug29823 deleted file mode 100644 index d856cf1fef..0000000000 --- a/changes/bug29823 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (unit tests): - - Split test_utils_general() to several smaller test functions in - test_utils_general(). This makes it easier to perform resource - deallocation on assert failure and fixes Coverity warnings CID 1444117 - and CID 1444118. Fixes bug 29823; bugfix on 0.2.9.1-alpha. diff --git a/changes/bug29926 b/changes/bug29926 deleted file mode 100644 index ab1417c603..0000000000 --- a/changes/bug29926 +++ /dev/null @@ -1,2 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Fix shellcheck warnings in asciidoc-helper.sh. Resolves issue 29926. diff --git a/changes/bug29939 b/changes/bug29939 deleted file mode 100644 index 0e9b46c075..0000000000 --- a/changes/bug29939 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (unit tests): - - In the "routerkeys/*" tests, check the return values of mkdir() for - possible failures. Fixes bug 29939; bugfix on 0.2.7.2-alpha. Found by - Coverity as CID 1444254. diff --git a/changes/bug30002 b/changes/bug30002 deleted file mode 100644 index da61c9e4b2..0000000000 --- a/changes/bug30002 +++ /dev/null @@ -1,2 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Fix shellcheck warnings in test_key_expiration.sh. Resolves issue 30002. diff --git a/changes/bug30109 b/changes/bug30109 deleted file mode 100644 index b25aa803bb..0000000000 --- a/changes/bug30109 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (documentation): - - Improve the documentation for MapAddress .exit. - Fixes bug 30109; bugfix on 0.1.0.1-rc. diff --git a/changes/bug30148 b/changes/bug30148 deleted file mode 100644 index 7d0257e3fe..0000000000 --- a/changes/bug30148 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (memory leak): - - Avoid a minor memory leak that could occur on relays when - creating a keys directory failed. Fixes bug 30148; bugfix on - 0.3.3.1-alpha. diff --git a/changes/bug30151 b/changes/bug30151 deleted file mode 100644 index 8ac9a320a0..0000000000 --- a/changes/bug30151 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (tor-resolve): - - Fix a memory leak in tor-resolve that could happen if Tor gave it a - malformed SOCKS response. (Memory leaks in tor-resolve don't actually - matter, but it's good to fix them anyway.) Fixes bug 30151; bugfix on - 0.4.0.1-alpha. diff --git a/changes/bug30189 b/changes/bug30189 deleted file mode 100644 index f8c932a5f9..0000000000 --- a/changes/bug30189 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (compilation, unusual configuration): - - Avoid failures when building with ALL_BUGS_ARE_FAILED due to - missing declarations of abort(), and prevent other such failures - in the future. Fixes bug 30189; bugfix on 0.3.4.1-alpha. diff --git a/changes/bug30190 b/changes/bug30190 deleted file mode 100644 index e2352c3b9c..0000000000 --- a/changes/bug30190 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (lib): - do not log a warning for OpenSSL versions that should be compatible - Fixes bug 30190; bugfix on 0.2.4.2-alpha diff --git a/changes/bug30236 b/changes/bug30236 deleted file mode 100644 index ceaa98c8f1..0000000000 --- a/changes/bug30236 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Refactor and encapsulate parts of the codebase that manipulate - crypt_path_t objects. Resolves issue 30236. \ No newline at end of file diff --git a/changes/bug30309 b/changes/bug30309 deleted file mode 100644 index 6cbbe8d156..0000000000 --- a/changes/bug30309 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Rename tor_mem_is_zero() to fast_mem_is_zero(), to emphasize that - it is not a constant-time function. Closes ticket 30309. diff --git a/changes/bug30452 b/changes/bug30452 deleted file mode 100644 index 2bb401d87d..0000000000 --- a/changes/bug30452 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (compile-time modules): - - Add a --list-modules command to print a list of which compile-time - modules are enabled. Closes ticket 30452. diff --git a/changes/bug30475 b/changes/bug30475 deleted file mode 100644 index 839597b885..0000000000 --- a/changes/bug30475 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (): - - Avoid a GCC 9.1.1 warning (and possible crash depending on libc - implemenation) when failing to load a hidden service client authorization - file. Fixes bug 30475; bugfix on 0.3.5.1-alpha. diff --git a/changes/bugs28693+30173+29203 b/changes/bugs28693+30173+29203 deleted file mode 100644 index 9faa6279bf..0000000000 --- a/changes/bugs28693+30173+29203 +++ /dev/null @@ -1,12 +0,0 @@ - o Minor bugfixes (circuit padding): - - Add a torrc option to disable circuit padding. Fixes bug 28693; bugfix - on 0.4.0.1-alpha. - o Minor bugfixes (circuit padding): - - Provide consensus parameter to fully disable circuit padding, to be used - in emergency network overload situations. Fixes bug 30173; bugfix on - 0.4.0.1-alpha. - o Minor bugfixes (circuit padding): - - Allow circuit padding machines to specify that they do not contribute - much overhead, and provide consensus flags and torrc options to force - clients to only use low overhead machines. Fixes bug 29203; bugfix on - 0.4.0.1-alpha. diff --git a/changes/coverity_falsepos b/changes/coverity_falsepos deleted file mode 100644 index 9fbb01a0c1..0000000000 --- a/changes/coverity_falsepos +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring: - - Refactor several places in our code that coverity incorrectly believed - that we might have memory leaks, so that we can analyze our software - more easily. Closes ticket 30147. diff --git a/changes/feature29532 b/changes/feature29532 deleted file mode 100644 index 4d95e6bca8..0000000000 --- a/changes/feature29532 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (developer tooling): - - Modify git pre-push hook script to disallow pushing branches other than - master, release-* and maint-* to origin remote. Implements feature - 29532. diff --git a/changes/geoip-2019-05-13 b/changes/geoip-2019-05-13 deleted file mode 100644 index 0a2fa18971..0000000000 --- a/changes/geoip-2019-05-13 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (geoip): - - Update geoip and geoip6 to the May 13 2019 Maxmind GeoLite2 - Country database. Closes ticket 30522. - diff --git a/changes/pubsub b/changes/pubsub deleted file mode 100644 index f67b36b988..0000000000 --- a/changes/pubsub +++ /dev/null @@ -1,5 +0,0 @@ - o Major features (code organization): - - Tor now includes a generic publish-subscribe message-passing subsystem - that we can use to organize intermodule dependencies. We hope to use - this to reduce dependencies between modules that don't need to be - related, and to generally simplify our codebase. Closes ticket 28226. diff --git a/changes/ticket25110 b/changes/ticket25110 deleted file mode 100644 index 298e33287f..0000000000 --- a/changes/ticket25110 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (logging, configuration): - - Warn operators when MyFamily option is set but ContactInfo - is missing, as the latter should be set too. - Fixes bug 25110; bugfix on 0.3.3.1-alpha. diff --git a/changes/ticket25417 b/changes/ticket25417 deleted file mode 100644 index 41f2acc988..0000000000 --- a/changes/ticket25417 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (controller): - - Add onion service version 3 support to HSFETCH. Previously, only - version 2 onion services were supported. Closes ticket 25417. - Patch by Neel Chauhan diff --git a/changes/ticket25614 b/changes/ticket25614 deleted file mode 100644 index 82988eeace..0000000000 --- a/changes/ticket25614 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (pluggable transports): - - Tor now sets TOR_PT_EXIT_ON_STDIN_CLOSE=1 for client transports as - well as servers. Fixes bug 25614; bugfix on 0.2.7.1-alpha. diff --git a/changes/ticket26069 b/changes/ticket26069 deleted file mode 100644 index caed9be348..0000000000 --- a/changes/ticket26069 +++ /dev/null @@ -1,2 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Cleanup autogen.sh to silence shellcheck warnings. Closes ticket 26069. diff --git a/changes/ticket26288 b/changes/ticket26288 deleted file mode 100644 index 59bb856dd2..0000000000 --- a/changes/ticket26288 +++ /dev/null @@ -1,6 +0,0 @@ - o Major features (flow control): - - Implement authenticated SENDMEs detailed in proposal 289. A SENDME cell - now includes the digest of the last cell received so once the end point - receives the SENDME, it can confirm the other side's knowledge of the - previous cells that were sent. This behavior is controlled by two new - consensus parameters, see proposal for more details. Fixes ticket 26288. diff --git a/changes/ticket27251 b/changes/ticket27251 deleted file mode 100644 index 7ce296e8da..0000000000 --- a/changes/ticket27251 +++ /dev/null @@ -1,4 +0,0 @@ - o Testing (chutney): - - In "make test-network-all", test IPv6-only v3 single onion services, - using the chutney network single-onion-v23-ipv6-md. This test will - not pass until 23588 has been merged. Closes ticket 27251. diff --git a/changes/ticket27821 b/changes/ticket27821 deleted file mode 100644 index 158f308fbf..0000000000 --- a/changes/ticket27821 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (HTTP tunnel): - - Return an informative web page when the HTTPTunnelPort is used as an - HTTP proxy. Closes ticket 27821, patch by "eighthave". diff --git a/changes/ticket28634 b/changes/ticket28634 deleted file mode 100644 index 7ba05e5c55..0000000000 --- a/changes/ticket28634 +++ /dev/null @@ -1,10 +0,0 @@ - o Major features (Circuit padding): - - Onion service clients will now add padding cells to the initial portions - of their INTRODUCE and RENDEZVOUS circuits, to make those circuits' - traffic patterns look more like general purpose Exit traffic. The - overhead for this is 2 extra cells in each direction for RENDEZVOUS - circuits, and 1 extra upstream cell and 10 downstream cells for INTRODUCE - circuits. This will only be enabled if the circuit's middle node supports - this feature, too. (Clients may specify fixed middle nodes with the MiddleNodes - torrc directive, and may force-disable this feature with the CircuitPadding - torrc directive). Closes ticket 28634. diff --git a/changes/ticket28780 b/changes/ticket28780 deleted file mode 100644 index d7c6693f8c..0000000000 --- a/changes/ticket28780 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (circuit padding): - - Provide the ability for circuit padding machines to hold a circuit open - until they are done padding it. Closes ticket 28780. diff --git a/changes/ticket28816 b/changes/ticket28816 deleted file mode 100644 index 02878ccfdc..0000000000 --- a/changes/ticket28816 +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring: - - Introduce a connection_dir_buf_add() helper function that checks for - compress_state of dir_connection_t and automatically writes a string to - directory connection with or without compression. Resolves issue 28816. diff --git a/changes/ticket28837 b/changes/ticket28837 deleted file mode 100644 index 3bc8f12597..0000000000 --- a/changes/ticket28837 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (performance): - - Use OpenSSL's implementations of SHA3 when available (in OpenSSL 1.1.1 - and later), since they tend to be faster than tiny-keccak. Closes - ticket 28837. diff --git a/changes/ticket28913 b/changes/ticket28913 deleted file mode 100644 index e09847464d..0000000000 --- a/changes/ticket28913 +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring: - - Make the base32_decode() API return the number of bytes written, - for consistency with base64_decode(). - Closes ticket 28913. diff --git a/changes/ticket29059 b/changes/ticket29059 deleted file mode 100644 index d47d0e2a3b..0000000000 --- a/changes/ticket29059 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Fix shellcheck warnings in fuzz_static_testcases.sh. Resolves ticket - 29059. diff --git a/changes/ticket29060 b/changes/ticket29060 deleted file mode 100644 index 380cc8eb11..0000000000 --- a/changes/ticket29060 +++ /dev/null @@ -1,2 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Fix shellcheck warnings in test-network.sh. Resolves issue 29060. diff --git a/changes/ticket29062 b/changes/ticket29062 deleted file mode 100644 index de05c621f1..0000000000 --- a/changes/ticket29062 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Cleanup test_keygen.sh to silence all shellcheck warnings. Closes - ticket 29062. diff --git a/changes/ticket29064 b/changes/ticket29064 deleted file mode 100644 index 616b8aa77e..0000000000 --- a/changes/ticket29064 +++ /dev/null @@ -1,2 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Fix shellcheck warning in test_rust.sh. Fixes issue 29064. diff --git a/changes/ticket29065 b/changes/ticket29065 deleted file mode 100644 index edf00ac99c..0000000000 --- a/changes/ticket29065 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Cleanup test_switch_id.sh to silence shellcheck warnings. Closes - ticket 29065. diff --git a/changes/ticket29067 b/changes/ticket29067 deleted file mode 100644 index a660648775..0000000000 --- a/changes/ticket29067 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Fix test_workqueue_*.sh scripts to silence shellcheck SC2086 - warnings. Fixes issue 29067. diff --git a/changes/ticket29068 b/changes/ticket29068 deleted file mode 100644 index 77ef304f1d..0000000000 --- a/changes/ticket29068 +++ /dev/null @@ -1,2 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Fix shellcheck warnings in zero_length_keys.sh. Resolves issue 29068. diff --git a/changes/ticket29070 b/changes/ticket29070 deleted file mode 100644 index 2716915359..0000000000 --- a/changes/ticket29070 +++ /dev/null @@ -1,2 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Fix shellcheck warning in torify script. Resolves issue 29070. diff --git a/changes/ticket29071 b/changes/ticket29071 deleted file mode 100644 index 0997a8d22f..0000000000 --- a/changes/ticket29071 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Fix shellcheck warnings in nagios-check-tor-authority-cert script. - Resolves issue 29071. diff --git a/changes/ticket29108 b/changes/ticket29108 deleted file mode 100644 index 7adb08ecb1..0000000000 --- a/changes/ticket29108 +++ /dev/null @@ -1,5 +0,0 @@ - o Code simplification and refactoring: - - Split crypto_digest.c into three parts: 1) general code that does not - depend on either NSS or OpenSSL (stays in crypto_digest.c); 2) code that - depends on NSS API (moved to crypto_digest_nss.c); 3) code that depends - on OpenSSL API (moved to crypto_digest_openssl.c). Resolves ticket 29108. diff --git a/changes/ticket29391 b/changes/ticket29391 deleted file mode 100644 index f00fa61c47..0000000000 --- a/changes/ticket29391 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor feature (maintenance scripts): - - Add to scripts/maint/ helper maintainer scripts used for git maintenance. - Closes ticket 29391. diff --git a/changes/ticket29434 b/changes/ticket29434 deleted file mode 100644 index 8037044f0b..0000000000 --- a/changes/ticket29434 +++ /dev/null @@ -1,3 +0,0 @@ - o Removed features: - - Remove linux-tor-prio.sh script from contrib/operator-tools directory. - Resolves issue 29434. diff --git a/changes/ticket29436 b/changes/ticket29436 deleted file mode 100644 index 025be619e5..0000000000 --- a/changes/ticket29436 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (testing): - - We now have a script, cov-test-determinism.sh, to identify places - where our unit test coverage has become nondeterministic. - Closes ticket 29436. diff --git a/changes/ticket29536 b/changes/ticket29536 deleted file mode 100644 index a5ae26b701..0000000000 --- a/changes/ticket29536 +++ /dev/null @@ -1,9 +0,0 @@ - o Minor features (performance, RNG): - - Tor now constructs a fast secure pseudorandom number generator for - each thread, to use for cases where performance is critical. This PRNG - is based on AES-CTR, using a buffering construction similar to - libottery and the (newer) OpenBSD arc4random() code. It outperforms - OpenSSL 1.1.1a's CSPRNG by roughly a factor of 100 for small outputs. - Although we believe it to be cryptographically strong, we are only - using it when necessary for reasonable performance. Implements tickets - 29023 and 29536. diff --git a/changes/ticket29537 b/changes/ticket29537 deleted file mode 100644 index afe2308205..0000000000 --- a/changes/ticket29537 +++ /dev/null @@ -1,3 +0,0 @@ - o Testing: - - Check that representative subsets of values of `int` and `unsigned int` - can be represented by `void *`. Resolves issue 29537. diff --git a/changes/ticket29542 b/changes/ticket29542 deleted file mode 100644 index 465a8e31bc..0000000000 --- a/changes/ticket29542 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (defense in depth): - - Tor now uses a fast cryptographically strong PRNG even for decisions - that we do not believe are security-sensitive. Previously, for - performance reasons, we had used a trivially predictable linear - congruential generator algorithm for certain load-balancing and - statistical sampling decisions. Now we use our fast RNG in those cases. - Closes ticket 29542. diff --git a/changes/ticket29553 b/changes/ticket29553 deleted file mode 100644 index af441b92b0..0000000000 --- a/changes/ticket29553 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (developer tools): - - Update our pre-commit.git-hook script to work correctly on older Tor - branches and release branches without any changes files, - and to actually exit when something fails. Fixes bug 29553; bugfix on - 0.4.0.2-alpha. diff --git a/changes/ticket29588 b/changes/ticket29588 deleted file mode 100644 index c81bccb00d..0000000000 --- a/changes/ticket29588 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (developer tools): - - Introduce a post-merge git hook script to check if we're pulling in any - changes to our git workspace management scripts from upstream. Resolves - issue 29588. diff --git a/changes/ticket29635 b/changes/ticket29635 deleted file mode 100644 index cbadbf648a..0000000000 --- a/changes/ticket29635 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (documentation, manpage): - - Use proper formatting when providing an example on quoting options that - contain whitespace. Fixes bug 29635; bugfix on 0.2.3.18-rc. diff --git a/changes/ticket29660 b/changes/ticket29660 deleted file mode 100644 index 84b8059106..0000000000 --- a/changes/ticket29660 +++ /dev/null @@ -1,5 +0,0 @@ - o Code simplification and refactoring: - - Remove redundant return values in crypto_format, and the associated - return value checks elsewhere in the code. Make the implementations in - crypto_format consistent, and remove redundant code. - Resolves ticket 29660. diff --git a/changes/ticket29662 b/changes/ticket29662 deleted file mode 100644 index 872df9ad82..0000000000 --- a/changes/ticket29662 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (debugging): - - Introduce tor_assertf() and tor_assertf_nonfatal() to enable logging of - additional information during assert failure. Now we can use format - strings to include pieces of information that are relevant for trouble - shooting. Resolves ticket 29662. diff --git a/changes/ticket29732 b/changes/ticket29732 deleted file mode 100644 index bb72361c48..0000000000 --- a/changes/ticket29732 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (testing): - - Tor's unit test code now contains a standard set of functions to - replace the PRNG with a deterministic or reproducible version for - testing. Previously, various tests implemented this in various ways. - Implements ticket 29732. diff --git a/changes/ticket29756 b/changes/ticket29756 deleted file mode 100644 index 79995b4995..0000000000 --- a/changes/ticket29756 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (developer tools): - - Add a script to check that each header has a well-formed and unique - guard marco. Closes ticket 29756. diff --git a/changes/ticket29894 b/changes/ticket29894 deleted file mode 100644 index 6392598ec6..0000000000 --- a/changes/ticket29894 +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring: - - Split up the control.c file into several submodules, in preparation - for distributing its current responsibilities throughout the codebase. - Closes ticket 29894. diff --git a/changes/ticket29913 b/changes/ticket29913 deleted file mode 100644 index a713b0ccef..0000000000 --- a/changes/ticket29913 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (python): - - Stop assuming that /usr/bin/python3 exists. For scripts that work with - python2, use /usr/bin/python. Otherwise, use /usr/bin/env python3. - Fixes bug 29913; bugfix on 0.2.5.3-alpha. diff --git a/changes/ticket29984 b/changes/ticket29984 deleted file mode 100644 index 8631dff27b..0000000000 --- a/changes/ticket29984 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (controller protocol): - - Teach the controller parser to correctly distinguish an object - preceded by an argument list from one without. Previously, it - couldn't distinguish an argument list from the first line of a - multiline object. Fixes bug 29984; bugfix on 0.2.3.8-alpha. diff --git a/changes/ticket30007 b/changes/ticket30007 deleted file mode 100644 index e87f6b956f..0000000000 --- a/changes/ticket30007 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Abstract out the low-level formatting of replies on the control - port. Implements ticket 30007. diff --git a/changes/ticket30033 b/changes/ticket30033 deleted file mode 100644 index 3f66d049c8..0000000000 --- a/changes/ticket30033 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (developer tooling): - - Call pre-commit git hook from pre-push hook to make sure we're - running documentation and code style checks before pushing to remote - git repository. Implements feature 30033. diff --git a/changes/ticket30051 b/changes/ticket30051 deleted file mode 100644 index 87b6d7611f..0000000000 --- a/changes/ticket30051 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (developer tooling): - - Call practracker from pre-push and pre-commit git hooks to let a - developer know if they made any code style violations in their last - commit. This should help preventing code style violations appearing - upstream. Closes ticket 30051. diff --git a/changes/ticket30075 b/changes/ticket30075 deleted file mode 100644 index 288abd7674..0000000000 --- a/changes/ticket30075 +++ /dev/null @@ -1,3 +0,0 @@ - o Removed features: - - Remove the obsolete script at contrib/dist/tor.sh.in. Resolves issue - 30075. diff --git a/changes/ticket30076 b/changes/ticket30076 deleted file mode 100644 index 1334bc4603..0000000000 --- a/changes/ticket30076 +++ /dev/null @@ -1,2 +0,0 @@ - o Removed features: - - Remove obsolete OpenSUSE initscript. Resolves issue 30076. diff --git a/changes/ticket30077 b/changes/ticket30077 deleted file mode 100644 index 9be014730e..0000000000 --- a/changes/ticket30077 +++ /dev/null @@ -1,2 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Fix shellcheck warnings in fuzz_multi.sh. Resolves issue 30077. diff --git a/changes/ticket30078 b/changes/ticket30078 deleted file mode 100644 index 5ab5abdbfd..0000000000 --- a/changes/ticket30078 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Fix shellcheck warnings in src/test/fuzz/fixup_filenames.sh. Resolves - issue 30078. diff --git a/changes/ticket30079 b/changes/ticket30079 deleted file mode 100644 index 56b88e7f53..0000000000 --- a/changes/ticket30079 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring (shell scripts): - - Fix shellcheck warning SC2006 in src/test/fuzz/minimize.sh. Resolves - issue 30079. diff --git a/changes/ticket30091 b/changes/ticket30091 deleted file mode 100644 index 968ea01f4a..0000000000 --- a/changes/ticket30091 +++ /dev/null @@ -1,4 +0,0 @@ - o Major features (controller protocol): - - Controller commands are now parsed using a generalized parsing - subsystem. Previously, each controller command was responsible for - parsing its own input. Closes ticket 30091. diff --git a/changes/ticket30114 b/changes/ticket30114 deleted file mode 100644 index a80f7f4dcf..0000000000 --- a/changes/ticket30114 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (git scripts): - - In git-pull-all.sh, also fetch the latest tor-github pull requests. - Implements ticket 30114. diff --git a/changes/ticket30149 b/changes/ticket30149 deleted file mode 100644 index a21687ac2f..0000000000 --- a/changes/ticket30149 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Add several assertions in an attempt to fix some Coverity warnings. - Closes ticket 30149. diff --git a/changes/ticket30176 b/changes/ticket30176 deleted file mode 100644 index da23760ce5..0000000000 --- a/changes/ticket30176 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (defense in depth): - - In smartlist_remove_keeporder(), set any pointers that become - unused to NULL, in case a bug causes them to be used later. Closes - ticket 30176. Patch from Tobias Stoeckmann. diff --git a/changes/ticket30213 b/changes/ticket30213 deleted file mode 100644 index acb7614807..0000000000 --- a/changes/ticket30213 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (continuous integration): - - Remove sudo configuration lines from .travis.yml as they are no longer - needed with current Travis build environment. Resolves issue 30213. diff --git a/changes/ticket30234 b/changes/ticket30234 deleted file mode 100644 index 5a0076bad2..0000000000 --- a/changes/ticket30234 +++ /dev/null @@ -1,2 +0,0 @@ - o Testing (continuous integration): - - In Travis, show stem's tor log after failure. Closes ticket 30234. diff --git a/changes/ticket30261 b/changes/ticket30261 deleted file mode 100644 index e4a2643c88..0000000000 --- a/changes/ticket30261 +++ /dev/null @@ -1,4 +0,0 @@ - o Documentation: - - Document how to find git commits and tags for bug fixes in - CodingStandards.md. And update some changes file documentation. - Closes ticket 30261. diff --git a/changes/ticket30293 b/changes/ticket30293 deleted file mode 100644 index c74b6cd346..0000000000 --- a/changes/ticket30293 +++ /dev/null @@ -1,5 +0,0 @@ - o Code simplification and refactoring: - - Start move responsibility for knowing about periodic events to the - appropriate subsystems, so that the mainloop doesn't need to know all - the periodic events in the rest of the codebase. Implements tickets - 30293 and 30294. diff --git a/changes/ticket30307 b/changes/ticket30307 deleted file mode 100644 index abcacb6085..0000000000 --- a/changes/ticket30307 +++ /dev/null @@ -1,4 +0,0 @@ - o Major features (performance): - - Update our node selection algorithm to exclude nodes in linear time. - Previously, the algorithm was quadratic, which could slow down heavily - used onion services. Closes ticket 30307. diff --git a/changes/ticket30308 b/changes/ticket30308 deleted file mode 100644 index b78e6b3e9f..0000000000 --- a/changes/ticket30308 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (performance): - - When checking a node for bridge status, use a fast check to make sure - that its identity is set. Previously, we used a constant-time check, - which is not necessary when verifying a BUG() condition that causes - a stack trace. Fixes bug 30308; bugfix on 0.3.5.1-alpha. diff --git a/changes/ticket30345 b/changes/ticket30345 deleted file mode 100644 index 639db8d7ee..0000000000 --- a/changes/ticket30345 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (modularity): - - The --disable-module-dirauth compile-time option now disables - even more dirauth-only code. Closes ticket 30345. diff --git a/changes/ticket30414 b/changes/ticket30414 deleted file mode 100644 index 029ed1311f..0000000000 --- a/changes/ticket30414 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Move most relay-only periodic events out of mainloop.c into the - relay subsystem. Closes ticket 30414. -- cgit v1.2.3-54-g00ecf From e2d3d444969abe2a2b802f4f42512b71a5a45468 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 20 May 2019 12:08:30 -0400 Subject: Add a new "autostyle" make target to run all of our reformatting Closes ticket 30539. --- Makefile.am | 31 ++++++++++++++++++++++++++----- changes/ticket30539 | 4 ++++ 2 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 changes/ticket30539 (limited to 'changes') diff --git a/Makefile.am b/Makefile.am index 827cf3dc9b..7a0d40d6a5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -334,11 +334,8 @@ coverage-html-full: all lcov --remove "$(HTML_COVER_DIR)/lcov.tmp" --rc lcov_branch_coverage=1 'test/*' 'ext/tinytest*' '/usr/*' --output-file "$(HTML_COVER_DIR)/lcov.info" genhtml --branch-coverage -o "$(HTML_COVER_DIR)" "$(HTML_COVER_DIR)/lcov.info" -# Avoid strlcpy.c, strlcat.c, aes.c, OpenBSD_malloc_Linux.c, sha256.c, -# tinytest*.[ch] -check-spaces: -if USE_PERL - $(PERL) $(top_srcdir)/scripts/maint/checkSpace.pl -C \ +# For scripts: avoid src/ext and src/trunnel. +OWNED_TOR_C_FILES=\ $(top_srcdir)/src/lib/*/*.[ch] \ $(top_srcdir)/src/core/*/*.[ch] \ $(top_srcdir)/src/feature/*/*.[ch] \ @@ -346,6 +343,11 @@ if USE_PERL $(top_srcdir)/src/test/*.[ch] \ $(top_srcdir)/src/test/*/*.[ch] \ $(top_srcdir)/src/tools/*.[ch] + +check-spaces: +if USE_PERL + $(PERL) $(top_srcdir)/scripts/maint/checkSpace.pl -C \ + $(OWNED_TOR_C_FILES) endif check-includes: @@ -456,6 +458,25 @@ version: (cd "$(top_srcdir)" && git rev-parse --short=16 HEAD); \ fi +.PHONY: autostyle-ifdefs +autostyle-ifdefs: + $(PYTHON) scripts/maint/annotate_ifdef_directives $(OWNED_TOR_C_FILES) + +.PHONY: autostyle-ifdefs +autostyle-operators: + $(PERL) scripts/coccinelle/test-operator-cleanup $(OWNED_TOR_C_FILES) + +.PHONY: rectify-includes +rectify-includes: + $(PYTHON) scripts/maint/rectify_include_paths.py + +.PHONY: update-copyright +update-copyright: + $(PERL) scripts/maint/updateCopyright.pl $(OWNED_TOR_C_FILES) + +.PHONY: autostyle +autostyle: update-versions rustfmt autostyle-ifdefs rectify-includes + mostlyclean-local: rm -f $(top_builddir)/src/*/*.gc{da,no} $(top_builddir)/src/*/*/*.gc{da,no} rm -rf $(HTML_COVER_DIR) diff --git a/changes/ticket30539 b/changes/ticket30539 new file mode 100644 index 0000000000..8d105eacb9 --- /dev/null +++ b/changes/ticket30539 @@ -0,0 +1,4 @@ + o Minor features (maintenance): + - Add a new "make autostyle" target that developers can use to + apply all automatic Tor style and consistency conversions to the + codebase. Closes ticket 30539. -- cgit v1.2.3-54-g00ecf From fb91e1c6efed6e5526170df3650fac65b701524b Mon Sep 17 00:00:00 2001 From: rl1987 Date: Tue, 21 May 2019 14:56:53 +0300 Subject: Remove torctl.in from contrib/dist --- changes/ticket30550 | 2 + configure.ac | 1 - contrib/dist/torctl.in | 195 ------------------------------------------------- contrib/include.am | 1 - 4 files changed, 2 insertions(+), 197 deletions(-) create mode 100644 changes/ticket30550 delete mode 100644 contrib/dist/torctl.in (limited to 'changes') diff --git a/changes/ticket30550 b/changes/ticket30550 new file mode 100644 index 0000000000..f356c4048e --- /dev/null +++ b/changes/ticket30550 @@ -0,0 +1,2 @@ + o Removed features: + - Remove torctl.in from contrib/dist directory. Resolves ticket 30550. diff --git a/configure.ac b/configure.ac index e65e960d7f..3c4ce438e0 100644 --- a/configure.ac +++ b/configure.ac @@ -2458,7 +2458,6 @@ AC_CONFIG_FILES([ Makefile config.rust contrib/operator-tools/tor.logrotate - contrib/dist/torctl contrib/dist/tor.service src/config/torrc.sample src/config/torrc.minimal diff --git a/contrib/dist/torctl.in b/contrib/dist/torctl.in deleted file mode 100644 index 4cc137da46..0000000000 --- a/contrib/dist/torctl.in +++ /dev/null @@ -1,195 +0,0 @@ -#!/bin/sh -# -# TOR control script designed to allow an easy command line interface -# to controlling The Onion Router -# -# The exit codes returned are: -# 0 - operation completed successfully. For "status", tor running. -# 1 - For "status", tor not running. -# 2 - Command not supported -# 3 - Could not be started or reloaded -# 4 - Could not be stopped -# 5 - -# 6 - -# 7 - -# 8 - -# -# When multiple arguments are given, only the error from the _last_ -# one is reported. -# -# -# |||||||||||||||||||| START CONFIGURATION SECTION |||||||||||||||||||| -# -------------------- -------------------- -# Name of the executable -EXEC=tor -# -# the path to your binary, including options if necessary -TORBIN="@BINDIR@/$EXEC" -# -# the path to the configuration file -TORCONF="@CONFDIR@/torrc" -# -# the path to your PID file -PIDFILE="@LOCALSTATEDIR@/run/tor/tor.pid" -# -# The path to the log file -LOGFILE="@LOCALSTATEDIR@/log/tor/tor.log" -# -# The path to the datadirectory -TORDATA="@LOCALSTATEDIR@/lib/tor" -# -TORARGS="--pidfile $PIDFILE --log \"notice file $LOGFILE\" --runasdaemon 1" -TORARGS="$TORARGS --datadirectory $TORDATA" - -# If user name is set in the environment, then use it; -# otherwise run as the invoking user (or whatever user the config -# file says)... unless the invoking user is root. The idea here is to -# let an unprivileged user run tor for her own use using this script, -# while still providing for it to be used as a system daemon. -if [ "x`id -u`" = "x0" ]; then - TORUSER=@TORUSER@ -fi - -if [ "x$TORUSER" != "x" ]; then - TORARGS="$TORARGS --user $TORUSER" -fi - -# We no longer wrap the Tor daemon startup in an su when running as -# root, because it's too painful to make the use of su portable. -# Just let the daemon set the UID and GID. -START="$TORBIN -f $TORCONF $TORARGS" - -# -# -------------------- -------------------- -# |||||||||||||||||||| END CONFIGURATION SECTION |||||||||||||||||||| - -ERROR=0 -ARGV="$@" -if [ "x$ARGV" = "x" ] ; then - ARGS="help" -fi - -checkIfRunning ( ) { - # check for pidfile - PID=unknown - if [ -f $PIDFILE ] ; then - PID=`/bin/cat $PIDFILE` - if [ "x$PID" != "x" ] ; then - if kill -0 $PID 2>/dev/null ; then - STATUS="$EXEC (pid $PID) running" - RUNNING=1 - else - STATUS="PID file ($PIDFILE) present, but $EXEC ($PID) not running" - RUNNING=0 - fi - else - STATUS="$EXEC (pid $PID?) not running" - RUNNING=0 - fi - else - STATUS="$EXEC apparently not running (no pid file)" - RUNNING=0 - fi - return -} - -for ARG in $@ $ARGS -do - checkIfRunning - - case $ARG in - start) - if [ $RUNNING -eq 1 ]; then - echo "$0 $ARG: $EXEC (pid $PID) already running" - continue - fi - if eval "$START" ; then - echo "$0 $ARG: $EXEC started" - # Make sure it stayed up! - /bin/sleep 1 - checkIfRunning - if [ $RUNNING -eq 0 ]; then - echo "$0 $ARG: $EXEC (pid $PID) quit unexpectedly" - fi - else - echo "$0 $ARG: $EXEC could not be started" - ERROR=3 - fi - ;; - stop) - if [ $RUNNING -eq 0 ]; then - echo "$0 $ARG: $STATUS" - continue - fi - if kill -15 $PID ; then - echo "$0 $ARG: $EXEC stopped" - else - /bin/sleep 1 - if kill -9 $PID ; then - echo "$0 $ARG: $EXEC stopped" - else - echo "$0 $ARG: $EXEC could not be stopped" - ERROR=4 - fi - fi - # Make sure it really died! - /bin/sleep 1 - checkIfRunning - if [ $RUNNING -eq 1 ]; then - echo "$0 $ARG: $EXEC (pid $PID) unexpectedly still running" - ERROR=4 - fi - ;; - restart) - $0 stop start - ;; - reload) - if [ $RUNNING -eq 0 ]; then - echo "$0 $ARG: $STATUS" - continue - fi - if kill -1 $PID; then - /bin/sleep 1 - echo "$EXEC (PID $PID) reloaded" - else - echo "Can't reload $EXEC" - ERROR=3 - fi - ;; - status) - echo $STATUS - if [ $RUNNING -eq 1 ]; then - ERROR=0 - else - ERROR=1 - fi - ;; - log) - cat $LOGFILE - ;; - help) - echo "usage: $0 (start|stop|restart|status|help)" - /bin/cat < Date: Wed, 22 May 2019 12:00:20 -0400 Subject: Fold last entry into changelog --- ChangeLog | 14 +++++++++++++- changes/ticket30454 | 10 ---------- 2 files changed, 13 insertions(+), 11 deletions(-) delete mode 100644 changes/ticket30454 (limited to 'changes') diff --git a/ChangeLog b/ChangeLog index b3562bf6a4..f70ce42a7a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -Changes in version 0.4.1.1-alpha - 2019-05-?? +Changes in version 0.4.1.1-alpha - 2019-05-22 This is the first alpha in the 0.4.1.x series. It introduces lightweight circuit padding to make some onion-service circuits harder to distinguish, includes a new "authenticated SENDME" feature to make @@ -53,6 +53,18 @@ Changes in version 0.4.1.1-alpha - 2019-05-?? strong, we are only using it when necessary for performance. Implements tickets 29023 and 29536. + o Major bugfixes (onion service v3): + - Fix an unreachable bug in which an introduction point would could + try to send an INTRODUCE_ACK with a status code that Trunnel would + refuse to encode, leading the relay to assert(). We've + consolidated the ABI values into trunnel now. Fixes bug 30454; + bugfix on 0.3.0.1-alpha. + - Client can now handle unknown status codes from a INTRODUCE_ACK + cells. (The NACK behavior will stay the same.) This will allow us + to extend status codes in the future without breaking the normal + client behavior. Fixes another part of bug 30454; bugfix + on 0.3.0.1-alpha. + o Minor features (circuit padding): - We now use a fast PRNG when scheduling circuit padding. Part of ticket 28636. diff --git a/changes/ticket30454 b/changes/ticket30454 deleted file mode 100644 index 77c45d0feb..0000000000 --- a/changes/ticket30454 +++ /dev/null @@ -1,10 +0,0 @@ - o Major bugfixes (hidden service v3): - - An intro point could try to send an INTRODUCE_ACK with a status code - that it wasn't able to encode leading to a hard assert() of the relay. - Fortunately, that specific code path can not be reached thus this issue - can't be triggered. We've consolidated the ABI values into trunnel now. - Fixes bug 30454; bugfix on 0.3.0.1-alpha. - - HSv3 client will now be able to properly handle unknown status code from - a INTRODUCE_ACK cell (nack) even if they do not know it. The NACK - behavior will stay the same. This will allow us to extend status code if - we want in the future without breaking the normal client behavior. -- cgit v1.2.3-54-g00ecf From 57ee0e3af98e5dce398e8bc7f6f2b77e53208288 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 23 May 2019 08:24:29 -0400 Subject: Only reject POSTDESCRIPTOR purpose= when the purpose is unrecognized Fixes bug 30580; bugfix on 0.4.1.1-alpha. --- changes/ticket30580 | 4 ++++ src/feature/control/control_cmd.c | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 changes/ticket30580 (limited to 'changes') diff --git a/changes/ticket30580 b/changes/ticket30580 new file mode 100644 index 0000000000..9ff1a33e41 --- /dev/null +++ b/changes/ticket30580 @@ -0,0 +1,4 @@ + o Minor bugfixes (controller): + - POSTDESCRIPTOR requests should work again. Previously, they were + broken if a "purpose=" flag was specified. Fixes bug 30580; + bugfix on 0.4.1.1-alpha. diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c index 5555a2c5c4..17d5b0c7f3 100644 --- a/src/feature/control/control_cmd.c +++ b/src/feature/control/control_cmd.c @@ -1049,9 +1049,11 @@ handle_control_postdescriptor(control_connection_t *conn, line = config_line_find_case(args->kwargs, "purpose"); if (line) { purpose = router_purpose_from_string(line->value); - control_printf_endreply(conn, 552, "Unknown purpose \"%s\"", - line->value); - goto done; + if (purpose == ROUTER_PURPOSE_UNKNOWN) { + control_printf_endreply(conn, 552, "Unknown purpose \"%s\"", + line->value); + goto done; + } } line = config_line_find_case(args->kwargs, "cache"); if (line) { -- cgit v1.2.3-54-g00ecf From 6d9e47702fe52b0817a593117a7f4a3eecf06ad7 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 24 May 2019 07:42:59 -0400 Subject: changes file for test coverage --- changes/ticket30519 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket30519 (limited to 'changes') diff --git a/changes/ticket30519 b/changes/ticket30519 new file mode 100644 index 0000000000..efb25b9294 --- /dev/null +++ b/changes/ticket30519 @@ -0,0 +1,4 @@ + o Minor features (testing): + - When running tests in coverage mode, take additional care to make + our coverage deterministic, so that we can accurately track changes in + code coverage. Closes ticket 30519. -- cgit v1.2.3-54-g00ecf From 0bc1241494a118d5319207a9f4683b993d389e77 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 17 May 2019 11:03:16 -0400 Subject: Make sure that we send at least some random data in RELAY_DATA cells Proposal 289 prevents SENDME-flooding by requiring the other side to authenticate the data it has received. But this data won't actually be random if they are downloading a known resource. "No problem", we said, "let's fell the empty parts of our cells with some randomness!" and we did that in #26871. Unfortunately, if the relay data payloads are all completely full, there won't be any empty parts for us to randomize. Therefore, we now pick random "randomness windows" between CIRCWINDOW_INCREMENT/2 and CIRCWINDOW_INCREMENT. We remember whether we have sent a cell containing at least 16 bytes of randomness in that window. If we haven't, then when the window is exhausted, we send one. (This window approach is designed to lower the number of rng checks we have to do. The number 16 is pulled out of a hat to change the attacker's guessing difficulty to "impossible".) Implements 28646. --- changes/ticket26846 | 6 +++ scripts/maint/practracker/exceptions.txt | 2 +- src/core/or/circuit_st.h | 11 +++++ src/core/or/circuitlist.c | 1 + src/core/or/circuitlist.h | 2 +- src/core/or/relay.c | 76 +++++++++++++++++++++++++++++--- src/core/or/relay.h | 1 + 7 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 changes/ticket26846 (limited to 'changes') diff --git a/changes/ticket26846 b/changes/ticket26846 new file mode 100644 index 0000000000..a18e231798 --- /dev/null +++ b/changes/ticket26846 @@ -0,0 +1,6 @@ + o Minor features (authenticated SENDME): + - Ensure that there is enough randomness on every circuit + to prevent an attacker from successfully predicting what SENDME cells + they will need to send: at a random interval, if we have not send + randomness already, leave some extra space at the end of a cell that + we can fill with random bytes. Closes ticket 26846. diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index 712e59dc5b..3a32e97beb 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -120,7 +120,7 @@ problem function-size /src/core/or/connection_or.c:connection_or_compute_authent problem file-size /src/core/or/policies.c 3249 problem function-size /src/core/or/policies.c:policy_summarize() 107 problem function-size /src/core/or/protover.c:protover_all_supported() 117 -problem file-size /src/core/or/relay.c 3173 +problem file-size /src/core/or/relay.c 3250 problem function-size /src/core/or/relay.c:circuit_receive_relay_cell() 127 problem function-size /src/core/or/relay.c:relay_send_command_from_edge_() 116 problem function-size /src/core/or/relay.c:connection_ap_process_end_not_open() 194 diff --git a/src/core/or/circuit_st.h b/src/core/or/circuit_st.h index 499bf93d6b..3c7b931614 100644 --- a/src/core/or/circuit_st.h +++ b/src/core/or/circuit_st.h @@ -92,6 +92,10 @@ struct circuit_t { /** True iff this circuit has received a DESTROY cell in either direction */ unsigned int received_destroy : 1; + /** True iff we have sent a sufficiently random data cell since last + * we reset send_randomness_after_n_cells. */ + unsigned int have_sent_sufficiently_random_cell : 1; + uint8_t state; /**< Current status of this circuit. */ uint8_t purpose; /**< Why are we creating this circuit? */ @@ -104,6 +108,13 @@ struct circuit_t { * circuit-level sendme cells to indicate that we're willing to accept * more. */ int deliver_window; + /** + * How many cells do we have until we need to send one that contains + * sufficient randomness? Used to ensure that authenticated SENDME cells + * will reflect some unpredictable information. + **/ + uint16_t send_randomness_after_n_cells; + /** FIFO containing the digest of the cells that are just before a SENDME is * sent by the client. It is done at the last cell before our package_window * goes down to 0 which is when we expect a SENDME. diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c index 72952a8a52..ebbe7f0824 100644 --- a/src/core/or/circuitlist.c +++ b/src/core/or/circuitlist.c @@ -993,6 +993,7 @@ init_circuit_base(circuit_t *circ) circ->package_window = circuit_initial_package_window(); circ->deliver_window = CIRCWINDOW_START; + circuit_reset_sendme_randomness(circ); cell_queue_init(&circ->n_chan_cells); smartlist_add(circuit_get_global_list(), circ); diff --git a/src/core/or/circuitlist.h b/src/core/or/circuitlist.h index 6f5fce4875..80c1f7ac4e 100644 --- a/src/core/or/circuitlist.h +++ b/src/core/or/circuitlist.h @@ -218,7 +218,7 @@ void circuit_mark_all_dirty_circs_as_unusable(void); void circuit_synchronize_written_or_bandwidth(const circuit_t *c, circuit_channel_direction_t dir); MOCK_DECL(void, circuit_mark_for_close_, (circuit_t *circ, int reason, - int line, const char *file)); + int line, const char *cfile)); int circuit_get_cpath_len(origin_circuit_t *circ); int circuit_get_cpath_opened_len(const origin_circuit_t *); void circuit_clear_cpath(origin_circuit_t *circ); diff --git a/src/core/or/relay.c b/src/core/or/relay.c index 7a121780af..c48147dff8 100644 --- a/src/core/or/relay.c +++ b/src/core/or/relay.c @@ -533,6 +533,10 @@ relay_command_to_string(uint8_t command) } } +/** When padding a cell with randomness, leave this many zeros after the + * payload. */ +#define CELL_PADDING_GAP 4 + /** Return the offset where the padding should start. The data_len is * the relay payload length expected to be put in the cell. It can not be * bigger than RELAY_PAYLOAD_SIZE else this function assert(). @@ -556,7 +560,7 @@ get_pad_cell_offset(size_t data_len) /* If the offset is larger than the cell payload size, we return an offset * of zero indicating that no padding needs to be added. */ - size_t offset = RELAY_HEADER_SIZE + data_len + 4; + size_t offset = RELAY_HEADER_SIZE + data_len + CELL_PADDING_GAP; if (offset >= CELL_PAYLOAD_SIZE) { return 0; } @@ -2027,27 +2031,82 @@ uint64_t stats_n_data_cells_received = 0; * ever received were completely full of data. */ uint64_t stats_n_data_bytes_received = 0; +/** + * Called when initializing a circuit, or when we have reached the end of the + * window in which we need to send some randomness so that incoming sendme + * cells will be unpredictable. Resets the flags and picks a new window. + */ +void +circuit_reset_sendme_randomness(circuit_t *circ) +{ + circ->have_sent_sufficiently_random_cell = 0; + circ->send_randomness_after_n_cells = CIRCWINDOW_INCREMENT / 2 + + crypto_fast_rng_get_uint(get_thread_fast_rng(), CIRCWINDOW_INCREMENT / 2); +} + +/** + * Any relay data payload containing fewer than this many real bytes is + * considered to have enough randomness to. + **/ +#define RELAY_PAYLOAD_LENGTH_FOR_RANDOM_SENDMES \ + (RELAY_PAYLOAD_SIZE - CELL_PADDING_GAP - 16) + /** * Helper. Return the number of bytes that should be put into a cell from a * given edge connection on which n_available bytes are available. */ static size_t connection_edge_get_inbuf_bytes_to_package(size_t n_available, - int package_partial) + int package_partial, + circuit_t *on_circuit) { if (!n_available) return 0; - size_t length = RELAY_PAYLOAD_SIZE; + /* Do we need to force this payload to have space for randomness? */ + const bool force_random_bytes = + (on_circuit->send_randomness_after_n_cells == 0) && + (! on_circuit->have_sent_sufficiently_random_cell); - if (n_available < length) { /* not a full payload available */ + /* At most how much would we like to send in this cell? */ + size_t target_length; + if (force_random_bytes) { + target_length = RELAY_PAYLOAD_LENGTH_FOR_RANDOM_SENDMES; + } else { + target_length = RELAY_PAYLOAD_SIZE; + } + + /* Decide how many bytes we will actually put into this cell. */ + size_t package_length; + if (n_available >= target_length) { /* A full payload is available. */ + package_length = target_length; + } else { /* not a full payload available */ if (package_partial) - length = n_available; /* just take whatever's available now */ + package_length = n_available; /* just take whatever's available now */ else return 0; /* nothing to do until we have a full payload */ } - return length; + /* If we reach this point, we will be definitely sending the cell. */ + tor_assert_nonfatal(package_length > 0); + + if (package_length <= RELAY_PAYLOAD_LENGTH_FOR_RANDOM_SENDMES) { + /* This cell will have enough randomness in the padding to make a future + * sendme cell unpredictable. */ + on_circuit->have_sent_sufficiently_random_cell = 1; + } + + if (on_circuit->send_randomness_after_n_cells == 0) { + /* Either this cell, or some previous cell, had enough padding to + * ensure sendme unpredictability. */ + tor_assert_nonfatal(on_circuit->have_sent_sufficiently_random_cell); + /* Pick a new interval in which we need to send randomness. */ + circuit_reset_sendme_randomness(on_circuit); + } + + --on_circuit->send_randomness_after_n_cells; + + return package_length; } /** If conn has an entire relay payload of bytes on its inbuf (or @@ -2123,10 +2182,13 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, } length = connection_edge_get_inbuf_bytes_to_package(bytes_to_process, - package_partial); + package_partial, circ); if (!length) return 0; + /* If we reach this point, we will definitely be packaging bytes into + * a cell. */ + stats_n_data_bytes_packaged += length; stats_n_data_cells_packaged += 1; diff --git a/src/core/or/relay.h b/src/core/or/relay.h index 97d5d6d0f2..0fc308f7df 100644 --- a/src/core/or/relay.h +++ b/src/core/or/relay.h @@ -42,6 +42,7 @@ int connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, int *max_cells); void connection_edge_consider_sending_sendme(edge_connection_t *conn); +void circuit_reset_sendme_randomness(circuit_t *circ); extern uint64_t stats_n_data_cells_packaged; extern uint64_t stats_n_data_bytes_packaged; -- cgit v1.2.3-54-g00ecf From bdf685e47614ef5dca935b9fe9a608ffdd63a816 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 29 May 2019 09:05:26 -0400 Subject: Changes file for bug 30614 --- changes/bug30614 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/bug30614 (limited to 'changes') diff --git a/changes/bug30614 b/changes/bug30614 new file mode 100644 index 0000000000..9f904bd115 --- /dev/null +++ b/changes/bug30614 @@ -0,0 +1,4 @@ + o Minor bugfixes (NetBSD): + - Fix usage of minherit() on NetBSD and other platforms that define + MAP_INHERIT_{ZERO,NONE} instead of INHERIT_{ZERO,NONE}. Fixes bug + 30614; bugfix on 0.4.0.2-alpha. Patch from Taylor Campbell. -- cgit v1.2.3-54-g00ecf From 3789f22bcbfbc6de415a838e4c4bfb2555c7d6c3 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 28 May 2019 09:44:06 -0400 Subject: hs: Implement a helper to repurpose a circuit When we repurpose a hidden service circuit, we need to clean up from the HS circuit map and any HS related data structured contained in the circuit. This commit adds an helper function that does it when repurposing a hidden service circuit. Fixes #29034 Signed-off-by: David Goulet --- changes/bug29034 | 5 +++++ src/core/or/circuituse.c | 6 ++++++ src/feature/hs/hs_circuit.c | 31 +++++++++++++++++++++++++++++++ src/feature/hs/hs_circuit.h | 1 + src/feature/rend/rendcommon.c | 11 +++++++++++ src/feature/rend/rendcommon.h | 2 ++ 6 files changed, 56 insertions(+) create mode 100644 changes/bug29034 (limited to 'changes') diff --git a/changes/bug29034 b/changes/bug29034 new file mode 100644 index 0000000000..816b615009 --- /dev/null +++ b/changes/bug29034 @@ -0,0 +1,5 @@ + o Major bugfixes (Onion service reachability): + - Properly clean up the introduction point map and associated state when + circuits change purpose from onion service circuits to pathbias, + measurement, or other circuit types. This should fix some instances of + introduction point failure. Fixes bug 29034; bugfix on 0.3.2.1-alpha. diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c index 02bfa15fb3..465d64215b 100644 --- a/src/core/or/circuituse.c +++ b/src/core/or/circuituse.c @@ -3052,6 +3052,12 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose) if (circ->purpose == new_purpose) return; + /* Take specific actions if we are repurposing a hidden service circuit. */ + if (circuit_purpose_is_hidden_service(circ->purpose) && + !circuit_purpose_is_hidden_service(new_purpose)) { + hs_circ_repurpose(circ); + } + if (CIRCUIT_IS_ORIGIN(circ)) { char old_purpose_desc[80] = ""; diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c index e3873d2f18..2e59a357b3 100644 --- a/src/feature/hs/hs_circuit.c +++ b/src/feature/hs/hs_circuit.c @@ -24,6 +24,7 @@ #include "feature/nodelist/describe.h" #include "feature/nodelist/nodelist.h" #include "feature/rend/rendservice.h" +#include "feature/rend/rendcommon.h" #include "feature/stats/rephist.h" #include "lib/crypt_ops/crypto_dh.h" #include "lib/crypt_ops/crypto_rand.h" @@ -1269,3 +1270,33 @@ hs_circ_cleanup(circuit_t *circ) hs_circuitmap_remove_circuit(circ); } } + +/* The given circuit will be repurposed so take the appropriate actions. A + * cleanup from the HS maps and of all HS related structures is done. + * + * Once this function returns, the circuit can be safely repurposed. */ +void +hs_circ_repurpose(circuit_t *circ) +{ + origin_circuit_t *origin_circ; + + tor_assert(circ); + + /* Only repurposing an origin circuit is possible for HS. */ + if (!CIRCUIT_IS_ORIGIN(circ)) { + return; + } + origin_circ = TO_ORIGIN_CIRCUIT(circ); + + /* First, cleanup the circuit from the HS maps. */ + hs_circ_cleanup(circ); + + /* Depending on the version, different cleanup is done. */ + if (origin_circ->rend_data) { + /* v2. */ + rend_circ_cleanup(origin_circ); + } else if (origin_circ->hs_ident) { + /* v3. */ + hs_ident_circuit_free(origin_circ->hs_ident); + } +} diff --git a/src/feature/hs/hs_circuit.h b/src/feature/hs/hs_circuit.h index b8d8b25add..0786f3ee45 100644 --- a/src/feature/hs/hs_circuit.h +++ b/src/feature/hs/hs_circuit.h @@ -16,6 +16,7 @@ /* Cleanup function when the circuit is closed or/and freed. */ void hs_circ_cleanup(circuit_t *circ); +void hs_circ_repurpose(circuit_t *circ); /* Circuit API. */ int hs_circ_service_intro_has_opened(hs_service_t *service, diff --git a/src/feature/rend/rendcommon.c b/src/feature/rend/rendcommon.c index de48af795f..b10a5863b4 100644 --- a/src/feature/rend/rendcommon.c +++ b/src/feature/rend/rendcommon.c @@ -1045,3 +1045,14 @@ rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc, match: return 1; } + +/* Cleanup the given circuit of all HS v2 data structure. */ +void +rend_circ_cleanup(origin_circuit_t *circ) +{ + tor_assert(circ); + + /* Both fields are set to NULL with these. */ + crypto_pk_free(circ->intro_key); + rend_data_free(circ->rend_data); +} diff --git a/src/feature/rend/rendcommon.h b/src/feature/rend/rendcommon.h index f136863c7a..c9a04846d7 100644 --- a/src/feature/rend/rendcommon.h +++ b/src/feature/rend/rendcommon.h @@ -71,6 +71,8 @@ int rend_non_anonymous_mode_enabled(const or_options_t *options); void assert_circ_anonymity_ok(const origin_circuit_t *circ, const or_options_t *options); +void rend_circ_cleanup(origin_circuit_t *circ); + #ifdef RENDCOMMON_PRIVATE STATIC int -- cgit v1.2.3-54-g00ecf From 2d66250d8acfc61210442df94fe04df09c2dbab6 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 29 May 2019 10:10:57 -0400 Subject: Remove want_cmddata from HSFETCH, which does not in fact want data This looks a copy-and-paste error to me. Fixes bug 30646; bugfix on 0.4.1.1-alpha. --- changes/bug30646 | 4 ++++ src/feature/control/control_cmd.c | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/bug30646 (limited to 'changes') diff --git a/changes/bug30646 b/changes/bug30646 new file mode 100644 index 0000000000..e95a54e3ef --- /dev/null +++ b/changes/bug30646 @@ -0,0 +1,4 @@ + o Minor bugfixes (controller): + - Repair the HSFETCH command so that it works again. Previously, it + expected a body when it shouldn't have. Fixes bug 30646; bugfix on + 0.4.1.1-alpha. diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c index 17d5b0c7f3..abb579bd43 100644 --- a/src/feature/control/control_cmd.c +++ b/src/feature/control/control_cmd.c @@ -1385,7 +1385,6 @@ static const control_cmd_syntax_t hsfetch_syntax = { .min_args = 1, .max_args = 1, .accept_keywords = true, .allowed_keywords = hsfetch_keywords, - .want_cmddata = true, }; /** Implementation for the HSFETCH command. */ -- cgit v1.2.3-54-g00ecf From 66eae4afffb35afe891ec14a3389a484ecb7b373 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 29 May 2019 16:08:33 -0400 Subject: Check whether gcc-hardening is runnable, and log an error if not Closes ticket 27530. --- changes/ticket27530 | 4 ++++ configure.ac | 11 +++++++++++ 2 files changed, 15 insertions(+) create mode 100644 changes/ticket27530 (limited to 'changes') diff --git a/changes/ticket27530 b/changes/ticket27530 new file mode 100644 index 0000000000..8ae4f52668 --- /dev/null +++ b/changes/ticket27530 @@ -0,0 +1,4 @@ + o Minor features (compilation): + - Log a more useful error message when we are compiling and one of the + compile-time hardening options we have selected can be linked but + not executed. Closes ticket 27530. diff --git a/configure.ac b/configure.ac index e7f959f17a..1ecf82c662 100644 --- a/configure.ac +++ b/configure.ac @@ -1188,6 +1188,17 @@ m4_ifdef([AS_VAR_IF],[ TOR_CHECK_LDFLAGS(-pie, "$all_ldflags_for_check", "$all_libs_for_check") fi TOR_TRY_COMPILE_WITH_CFLAGS(-fwrapv, also_link, CFLAGS_FWRAPV="-fwrapv", true) + + AC_MSG_CHECKING([whether we can run hardened binaries]) + AC_RUN_IFELSE([AC_LANG_PROGRAM([], [return 0;])], + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no]) + AC_MSG_ERROR([dnl + We can link with compiler hardening options, but we can't run with them. + That's a bad sign! If you must, you can pass --disable-gcc-hardening to + configure, but it would be better to figure out what the underlying problem + is.])], + [AC_MSG_RESULT([cross])]) fi if test "$fragile_hardening" = "yes"; then -- cgit v1.2.3-54-g00ecf From 8f3430fc28be9ac16909fd02e0d48aad4ccc128e Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 30 May 2019 12:58:12 -0400 Subject: changes file for 30629 --- changes/bug30629 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/bug30629 (limited to 'changes') diff --git a/changes/bug30629 b/changes/bug30629 new file mode 100644 index 0000000000..59fa96ee68 --- /dev/null +++ b/changes/bug30629 @@ -0,0 +1,6 @@ + o Minor bugfixes (shutdown, libevent, memory safety): + - Avoid use-after-free bugs when shutting down, by making sure that we + shut down libevent only after shutting down all of its users. We + believe these are harmless in practice, since they only occur on the + shutdown path, and do not involve any attacker-controlled data. Fixes + bug 30629; bugfix on 0.4.1.1-alpha. -- cgit v1.2.3-54-g00ecf From 9bef75a29a009f057c69c730b6bf3eccfc0c4b45 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Thu, 30 May 2019 15:18:16 -0700 Subject: Bug 30649: Changes file. --- changes/bug30649 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/bug30649 (limited to 'changes') diff --git a/changes/bug30649 b/changes/bug30649 new file mode 100644 index 0000000000..3f5768bcb4 --- /dev/null +++ b/changes/bug30649 @@ -0,0 +1,4 @@ + o Minor bugfixes (circuit padding): + - On relays, properly check that a padding machine is absent before + logging a warn about it being absent. Fixes bug 30649; + bugfix on 0.4.1.1-alpha. -- cgit v1.2.3-54-g00ecf From 5d4b4f948a338a41966bb2e15af5875d4df8a08f Mon Sep 17 00:00:00 2001 From: rl1987 Date: Fri, 31 May 2019 09:35:19 +0300 Subject: Mention Travis/Appveyor/Jenkins URLs in ReleasingTor.md --- changes/doc30630 | 3 +++ doc/HACKING/ReleasingTor.md | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 changes/doc30630 (limited to 'changes') diff --git a/changes/doc30630 b/changes/doc30630 new file mode 100644 index 0000000000..0fbd8d4dd4 --- /dev/null +++ b/changes/doc30630 @@ -0,0 +1,3 @@ + o Documentation: + - Mention URLs for Travis/Appveyor/Jenkins in ReleasingTor.md. Closes + ticket 30630. diff --git a/doc/HACKING/ReleasingTor.md b/doc/HACKING/ReleasingTor.md index 4c87a366cc..d9864dba27 100644 --- a/doc/HACKING/ReleasingTor.md +++ b/doc/HACKING/ReleasingTor.md @@ -20,8 +20,11 @@ new Tor release: === I. Make sure it works -1. Make sure that CI passes: have a look at Travis, Appveyor, and - Jenkins. Make sure you're looking at the right branches. +1. Make sure that CI passes: have a look at Travis + (https://travis-ci.org/torproject/tor/branches), Appveyor + (https://ci.appveyor.com/project/torproject/tor/history), and + Jenkins (https://jenkins.torproject.org/view/tor/). + Make sure you're looking at the right branches. If there are any unexplained failures, try to fix them or figure them out. @@ -244,3 +247,5 @@ new Tor release: master branch. 3. Keep an eye on the blog post, to moderate comments and answer questions. + + -- cgit v1.2.3-54-g00ecf From 33382184b67d43b859de2f50d24cc7955b9f0db7 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Mon, 3 Jun 2019 14:31:51 -0400 Subject: sendme: Do not decrement window in a log_debug() If "Log debug ..." is not set, the decrement never happens. This lead to the package/deliver window to be out of sync at the stream level and thus breaking the connection after 50+ cells. Fixes #30628 Signed-off-by: David Goulet --- changes/ticket30628 | 5 +++++ src/core/or/sendme.c | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 changes/ticket30628 (limited to 'changes') diff --git a/changes/ticket30628 b/changes/ticket30628 new file mode 100644 index 0000000000..7128c5acf7 --- /dev/null +++ b/changes/ticket30628 @@ -0,0 +1,5 @@ + o Major bugfixes (Flow Control, SENDME): + - The decrement of the stream-level package window was done in a log_debug() + statement meaning that if the debug logs were not enabled, the decrement + would never happen and thus the window would be out of sync with the other + end point. Fixes bug 30628; bugfix on 0.4.1.1-alpha. diff --git a/src/core/or/sendme.c b/src/core/or/sendme.c index 7d409a16ad..47ac95f3cf 100644 --- a/src/core/or/sendme.c +++ b/src/core/or/sendme.c @@ -619,7 +619,9 @@ int sendme_note_stream_data_packaged(edge_connection_t *conn) { tor_assert(conn); - log_debug(LD_APP, "Stream package_window now %d.", --conn->package_window); + + --conn->package_window; + log_debug(LD_APP, "Stream package_window now %d.", conn->package_window); return conn->package_window; } -- cgit v1.2.3-54-g00ecf From 8cb6b2b9ab74d187e4839d298fbce06dafeb33f0 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 5 Jun 2019 14:56:28 +0300 Subject: Fix typo in #29670 changes file. --- changes/bug29670 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'changes') diff --git a/changes/bug29670 b/changes/bug29670 index 00b0c33327..288bbbf62f 100644 --- a/changes/bug29670 +++ b/changes/bug29670 @@ -1,4 +1,4 @@ o Minor bugfixes (configuration, proxies): - Fix a bug that prevented us from supporting SOCKS5 proxies that want - authentication along with configued (but unused!) + authentication along with configured (but unused!) ClientTransportPlugins. Fixes bug 29670; bugfix on 0.2.6.1-alpha. -- cgit v1.2.3-54-g00ecf From 0982d0136996179e1c4bcf26d2890e12301f6aad Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 5 Jun 2019 09:24:18 -0400 Subject: Start a changelog for 0.4.1.2-alpha --- ChangeLog | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++ changes/bug29034 | 5 --- changes/bug29670 | 4 -- changes/bug29875 | 11 ----- changes/bug30286 | 4 -- changes/bug30316 | 4 -- changes/bug30561 | 6 --- changes/bug30614 | 4 -- changes/bug30629 | 6 --- changes/bug30646 | 4 -- changes/ticket26846 | 6 --- changes/ticket28878 | 11 ----- changes/ticket29617 | 4 -- changes/ticket29702 | 4 -- changes/ticket30150 | 4 -- changes/ticket30519 | 4 -- changes/ticket30539 | 4 -- changes/ticket30580 | 4 -- changes/ticket30628 | 5 --- 19 files changed, 115 insertions(+), 94 deletions(-) delete mode 100644 changes/bug29034 delete mode 100644 changes/bug29670 delete mode 100644 changes/bug29875 delete mode 100644 changes/bug30286 delete mode 100644 changes/bug30316 delete mode 100644 changes/bug30561 delete mode 100644 changes/bug30614 delete mode 100644 changes/bug30629 delete mode 100644 changes/bug30646 delete mode 100644 changes/ticket26846 delete mode 100644 changes/ticket28878 delete mode 100644 changes/ticket29617 delete mode 100644 changes/ticket29702 delete mode 100644 changes/ticket30150 delete mode 100644 changes/ticket30519 delete mode 100644 changes/ticket30539 delete mode 100644 changes/ticket30580 delete mode 100644 changes/ticket30628 (limited to 'changes') diff --git a/ChangeLog b/ChangeLog index 86f39bfd71..f3eac65d52 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,118 @@ +Changes in version 0.4.1.2-alpha - 2019-06-05 + Tor 0.4.1.2-alpha resolves numerous bugs--some of them from the previous + alpha, and some much older. It also contains minor testing improvements, + and an improvement to the security of our authenticated sendme + implementation. + + o Major bugfixes (bridges): + - Consider our directory information to have changed when our list of + bridges changes. Previously, Tor would not re-compute the status of its + directory information when bridges changed, and therefore would not + realize that it was no longer able to build circuits. Fixes part of bug + 29875. + - Do not count previously configured working bridges towards our total of + working bridges. Previously, when Tor's list of bridges changed, it + would think that the old bridges were still usable, and delay fetching + router descriptors for the new ones. Fixes part of bug 29875; bugfix + on 0.3.0.1-alpha. + + o Major bugfixes (Flow Control, SENDME): + - The decrement of the stream-level package window was done in a log_debug() + statement meaning that if the debug logs were not enabled, the decrement + would never happen and thus the window would be out of sync with the other + end point. Fixes bug 30628; bugfix on 0.4.1.1-alpha. + + o Major bugfixes (Onion service reachability): + - Properly clean up the introduction point map and associated state when + circuits change purpose from onion service circuits to pathbias, + measurement, or other circuit types. This should fix some instances of + introduction point failure. Fixes bug 29034; bugfix on 0.3.2.1-alpha. + + o Minor features (authenticated SENDME): + - Ensure that there is enough randomness on every circuit + to prevent an attacker from successfully predicting what SENDME cells + they will need to send: at a random interval, if we have not send + randomness already, leave some extra space at the end of a cell that + we can fill with random bytes. Closes ticket 26846. + + o Minor features (continuous integration): + - When running coverage builds on Travis, we now set TOR_TEST_RNG_SEED, + to avoid RNG-based coverage differences. + Part of ticket 28878. + + o Minor features (maintenance): + - Add a new "make autostyle" target that developers can use to + apply all automatic Tor style and consistency conversions to the + codebase. Closes ticket 30539. + + o Minor features (testing): + - The circuitpadding tests now use a reproducible RNG implementation, + so that if a test fails, we can learn why. Part of ticket 28878. + - Tor's tests now support an environment variable, TOR_TEST_RNG_SEED, + to set the RNG seed for tests that use a reproducible RNG. + Part of ticket 28878. + - When running tests in coverage mode, take additional care to make + our coverage deterministic, so that we can accurately track changes in + code coverage. Closes ticket 30519. + + o Minor bugfixes (configuration, proxies): + - Fix a bug that prevented us from supporting SOCKS5 proxies that want + authentication along with configured (but unused!) + ClientTransportPlugins. Fixes bug 29670; bugfix on 0.2.6.1-alpha. + + o Minor bugfixes (controller): + - POSTDESCRIPTOR requests should work again. Previously, they were + broken if a "purpose=" flag was specified. Fixes bug 30580; + bugfix on 0.4.1.1-alpha. + - Repair the HSFETCH command so that it works again. Previously, it + expected a body when it shouldn't have. Fixes bug 30646; bugfix on + 0.4.1.1-alpha. + + o Minor bugfixes (developer tooling): + - Fix pre-push hook to refrain from rejecting fixup and squash commits + when pushing to non-upstream git remote. Fixes bug 30286; bugfix on + 0.4.0.1-alpha. + + o Minor bugfixes (directory authority): + - Move the "bandwidth-file-headers" line in directory authority votes + so that it conforms to dir-spec.txt. Fixes bug 30316; bugfix on + 0.3.5.1-alpha. + + o Minor bugfixes (NetBSD): + - Fix usage of minherit() on NetBSD and other platforms that define + MAP_INHERIT_{ZERO,NONE} instead of INHERIT_{ZERO,NONE}. Fixes bug + 30614; bugfix on 0.4.0.2-alpha. Patch from Taylor Campbell. + + o Minor bugfixes (out-of-memory handler): + - When purging the DNS cache because of an out-of-memory condition, + try purging just the older entries at first. Previously, we would + purge the whole thing. Fixes bug 29617; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (portability): + - Avoid crashing in our tor_vasprintf() implementation on systems that + define neither vasprintf() nor _vscprintf(). (This bug has been here + long enough that we question whether people are running Tor on such + systems, but we're applying the fix out of caution.) Fixes bug 30561; + bugfix on 0.2.8.2-alpha. Found and fixed by Tobias Stoeckmann. + + o Minor bugfixes (shutdown, libevent, memory safety): + - Avoid use-after-free bugs when shutting down, by making sure that we + shut down libevent only after shutting down all of its users. We + believe these are harmless in practice, since they only occur on the + shutdown path, and do not involve any attacker-controlled data. Fixes + bug 30629; bugfix on 0.4.1.1-alpha. + + o Minor bugfixes (static analysis): + - Fix several spurious Coverity warnings about the unit tests, to lower our + chances of missing any real warnings in the future. Fixes bug 30150; + bugfix on 0.3.5.1-alpha and various other Tor versions. + + o Testing: + - Specify torrc paths (with empty files) when launching tor in + integration tests; refrain from reading user and system torrcs. + Resolves issue 29702. + + Changes in version 0.4.1.1-alpha - 2019-05-22 This is the first alpha in the 0.4.1.x series. It introduces lightweight circuit padding to make some onion-service circuits harder diff --git a/changes/bug29034 b/changes/bug29034 deleted file mode 100644 index 816b615009..0000000000 --- a/changes/bug29034 +++ /dev/null @@ -1,5 +0,0 @@ - o Major bugfixes (Onion service reachability): - - Properly clean up the introduction point map and associated state when - circuits change purpose from onion service circuits to pathbias, - measurement, or other circuit types. This should fix some instances of - introduction point failure. Fixes bug 29034; bugfix on 0.3.2.1-alpha. diff --git a/changes/bug29670 b/changes/bug29670 deleted file mode 100644 index 288bbbf62f..0000000000 --- a/changes/bug29670 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (configuration, proxies): - - Fix a bug that prevented us from supporting SOCKS5 proxies that want - authentication along with configured (but unused!) - ClientTransportPlugins. Fixes bug 29670; bugfix on 0.2.6.1-alpha. diff --git a/changes/bug29875 b/changes/bug29875 deleted file mode 100644 index 58a1c871cd..0000000000 --- a/changes/bug29875 +++ /dev/null @@ -1,11 +0,0 @@ - o Major bugfixes (bridges): - - Do not count previously configured working bridges towards our total of - working bridges. Previously, when Tor's list of bridges changed, it - would think that the old bridges were still usable, and delay fetching - router descriptors for the new ones. Fixes part of bug 29875; bugfix - on 0.3.0.1-alpha. - - Consider our directory information to have changed when our list of - bridges changes. Previously, Tor would not re-compute the status of its - directory information when bridges changed, and therefore would not - realize that it was no longer able to build circuits. Fixes part of bug - 29875. diff --git a/changes/bug30286 b/changes/bug30286 deleted file mode 100644 index f2fc67a484..0000000000 --- a/changes/bug30286 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (developer tooling): - - Fix pre-push hook to refrain from rejecting fixup and squash commits - when pushing to non-upstream git remote. Fixes bug 30286; bugfix on - 0.4.0.1-alpha. diff --git a/changes/bug30316 b/changes/bug30316 deleted file mode 100644 index 3e396318ad..0000000000 --- a/changes/bug30316 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (directory authority): - - Move the "bandwidth-file-headers" line in directory authority votes - so that it conforms to dir-spec.txt. Fixes bug 30316; bugfix on - 0.3.5.1-alpha. diff --git a/changes/bug30561 b/changes/bug30561 deleted file mode 100644 index afb3f02c62..0000000000 --- a/changes/bug30561 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (portability): - - Avoid crashing in our tor_vasprintf() implementation on systems that - define neither vasprintf() nor _vscprintf(). (This bug has been here - long enough that we question whether people are running Tor on such - systems, but we're applying the fix out of caution.) Fixes bug 30561; - bugfix on 0.2.8.2-alpha. Found and fixed by Tobias Stoeckmann. diff --git a/changes/bug30614 b/changes/bug30614 deleted file mode 100644 index 9f904bd115..0000000000 --- a/changes/bug30614 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (NetBSD): - - Fix usage of minherit() on NetBSD and other platforms that define - MAP_INHERIT_{ZERO,NONE} instead of INHERIT_{ZERO,NONE}. Fixes bug - 30614; bugfix on 0.4.0.2-alpha. Patch from Taylor Campbell. diff --git a/changes/bug30629 b/changes/bug30629 deleted file mode 100644 index 59fa96ee68..0000000000 --- a/changes/bug30629 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (shutdown, libevent, memory safety): - - Avoid use-after-free bugs when shutting down, by making sure that we - shut down libevent only after shutting down all of its users. We - believe these are harmless in practice, since they only occur on the - shutdown path, and do not involve any attacker-controlled data. Fixes - bug 30629; bugfix on 0.4.1.1-alpha. diff --git a/changes/bug30646 b/changes/bug30646 deleted file mode 100644 index e95a54e3ef..0000000000 --- a/changes/bug30646 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (controller): - - Repair the HSFETCH command so that it works again. Previously, it - expected a body when it shouldn't have. Fixes bug 30646; bugfix on - 0.4.1.1-alpha. diff --git a/changes/ticket26846 b/changes/ticket26846 deleted file mode 100644 index a18e231798..0000000000 --- a/changes/ticket26846 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor features (authenticated SENDME): - - Ensure that there is enough randomness on every circuit - to prevent an attacker from successfully predicting what SENDME cells - they will need to send: at a random interval, if we have not send - randomness already, leave some extra space at the end of a cell that - we can fill with random bytes. Closes ticket 26846. diff --git a/changes/ticket28878 b/changes/ticket28878 deleted file mode 100644 index 73ca47c72f..0000000000 --- a/changes/ticket28878 +++ /dev/null @@ -1,11 +0,0 @@ - o Minor features (testing): - - The circuitpadding tests now use a reproducible RNG implementation, - so that if a test fails, we can learn why. Part of ticket 28878. - - Tor's tests now support an environment variable, TOR_TEST_RNG_SEED, - to set the RNG seed for tests that use a reproducible RNG. - Part of ticket 28878. - - o Minor features (continuous integration): - - When running coverage builds on Travis, we now set TOR_TEST_RNG_SEED, - to avoid RNG-based coverage differences. - Part of ticket 28878. diff --git a/changes/ticket29617 b/changes/ticket29617 deleted file mode 100644 index 4d50ea9627..0000000000 --- a/changes/ticket29617 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (out-of-memory handler): - - When purging the DNS cache because of an out-of-memory condition, - try purging just the older entries at first. Previously, we would - purge the whole thing. Fixes bug 29617; bugfix on 0.3.5.1-alpha. diff --git a/changes/ticket29702 b/changes/ticket29702 deleted file mode 100644 index e1cc1f867b..0000000000 --- a/changes/ticket29702 +++ /dev/null @@ -1,4 +0,0 @@ - o Testing: - - Specify torrc paths (with empty files) when launching tor in - integration tests; refrain from reading user and system torrcs. - Resolves issue 29702. diff --git a/changes/ticket30150 b/changes/ticket30150 deleted file mode 100644 index 70808fa5db..0000000000 --- a/changes/ticket30150 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (static analysis): - - Fix several spurious Coverity warnings about the unit tests, to lower our - chances of missing any real warnings in the future. Fixes bug 30150; - bugfix on 0.3.5.1-alpha and various other Tor versions. diff --git a/changes/ticket30519 b/changes/ticket30519 deleted file mode 100644 index efb25b9294..0000000000 --- a/changes/ticket30519 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (testing): - - When running tests in coverage mode, take additional care to make - our coverage deterministic, so that we can accurately track changes in - code coverage. Closes ticket 30519. diff --git a/changes/ticket30539 b/changes/ticket30539 deleted file mode 100644 index 8d105eacb9..0000000000 --- a/changes/ticket30539 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (maintenance): - - Add a new "make autostyle" target that developers can use to - apply all automatic Tor style and consistency conversions to the - codebase. Closes ticket 30539. diff --git a/changes/ticket30580 b/changes/ticket30580 deleted file mode 100644 index 9ff1a33e41..0000000000 --- a/changes/ticket30580 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (controller): - - POSTDESCRIPTOR requests should work again. Previously, they were - broken if a "purpose=" flag was specified. Fixes bug 30580; - bugfix on 0.4.1.1-alpha. diff --git a/changes/ticket30628 b/changes/ticket30628 deleted file mode 100644 index 7128c5acf7..0000000000 --- a/changes/ticket30628 +++ /dev/null @@ -1,5 +0,0 @@ - o Major bugfixes (Flow Control, SENDME): - - The decrement of the stream-level package window was done in a log_debug() - statement meaning that if the debug logs were not enabled, the decrement - would never happen and thus the window would be out of sync with the other - end point. Fixes bug 30628; bugfix on 0.4.1.1-alpha. -- cgit v1.2.3-54-g00ecf From c525135dac354892a45ad3d2f6de9450d393f09f Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Wed, 5 Jun 2019 11:50:44 -0700 Subject: Bug 29034: Cleanup hs circuitmap when purpose changes. Leave the other rend and hs_ident data around until circuit free, since code may still try to inspect it after marking the circuit for close. The circuitmap is the important thing to clean up, since repurposed intropoints must be removed from this map to ensure validity. --- changes/bug29034 | 5 +++++ src/core/or/circuituse.c | 6 ++++++ 2 files changed, 11 insertions(+) create mode 100644 changes/bug29034 (limited to 'changes') diff --git a/changes/bug29034 b/changes/bug29034 new file mode 100644 index 0000000000..e7aa9af00b --- /dev/null +++ b/changes/bug29034 @@ -0,0 +1,5 @@ + o Major bugfixes (Onion service reachability): + - Properly clean up the introduction point map when circuits change purpose + from onion service circuits to pathbias, measurement, or other circuit types. + This should fix some service-side instances of introduction point failure. + Fixes bug 29034; bugfix on 0.3.2.1-alpha. diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c index 485c389054..18b419e99d 100644 --- a/src/core/or/circuituse.c +++ b/src/core/or/circuituse.c @@ -3082,6 +3082,12 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose) circ->purpose, circuit_purpose_to_string(new_purpose), new_purpose); + + /* Take specific actions if we are repurposing a hidden service circuit. */ + if (circuit_purpose_is_hidden_service(circ->purpose) && + !circuit_purpose_is_hidden_service(new_purpose)) { + hs_circ_cleanup(circ); + } } old_purpose = circ->purpose; -- cgit v1.2.3-54-g00ecf From 19bf5806adb80e513bb2707a1686216225fef420 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 6 Jun 2019 08:52:13 +1000 Subject: dirauth: Return a distinct status when formatting annotations fails Adds ROUTER_AUTHDIR_BUG_ANNOTATIONS to was_router_added_t. The out-of-order numbering is deliberate: it will be fixed by later commits for 16564. Fixes bug 30780; bugfix on 0.2.0.8-alpha. --- changes/bug30780 | 3 +++ src/feature/dirauth/process_descs.c | 4 +--- src/feature/nodelist/routerlist.h | 5 ++++- 3 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 changes/bug30780 (limited to 'changes') diff --git a/changes/bug30780 b/changes/bug30780 new file mode 100644 index 0000000000..5731d201a2 --- /dev/null +++ b/changes/bug30780 @@ -0,0 +1,3 @@ + o Minor bugfixes (directory authorities): + - Return a distinct status when formatting annotations fails. + Fixes bug 30780; bugfix on 0.2.0.8-alpha. diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c index 17936add5f..a68d155651 100644 --- a/src/feature/dirauth/process_descs.c +++ b/src/feature/dirauth/process_descs.c @@ -556,9 +556,7 @@ dirserv_add_multiple_descriptors(const char *desc, size_t desclen, !general ? router_purpose_to_string(purpose) : "", !general ? "\n" : "")<0) { *msg = "Couldn't format annotations"; - /* XXX Not cool: we return -1 below, but (was_router_added_t)-1 is - * ROUTER_BAD_EI, which isn't what's gone wrong here. :( */ - return -1; + return ROUTER_AUTHDIR_BUG_ANNOTATIONS; } s = desc; diff --git a/src/feature/nodelist/routerlist.h b/src/feature/nodelist/routerlist.h index d7f44cb807..dc9203e015 100644 --- a/src/feature/nodelist/routerlist.h +++ b/src/feature/nodelist/routerlist.h @@ -39,7 +39,10 @@ typedef enum was_router_added_t { * OLD_ROUTER_DESC_MAX_AGE. */ ROUTER_WAS_TOO_OLD = -7, /* note contrast with 'ROUTER_IS_ALREADY_KNOWN' */ /* Some certs on this router are expired. */ - ROUTER_CERTS_EXPIRED = -8 + ROUTER_CERTS_EXPIRED = -8, + /* We couldn't format the annotations for this router. This is a directory + * authority bug. */ + ROUTER_AUTHDIR_BUG_ANNOTATIONS = -10 } was_router_added_t; /** How long do we avoid using a directory server after it's given us a 503? */ -- cgit v1.2.3-54-g00ecf From c46e99c43c4ee032127f2229070e5c21c64d19be Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 7 Jun 2019 13:52:03 -0400 Subject: Tolerate net-unreachable failures in util/socketpair_ersatz This can happen when we have no network stack configured. Fixes bug 30804; bugfix on 0.2.5.1-alpha. --- changes/bug30804 | 4 ++++ src/test/test_util.c | 5 +++++ 2 files changed, 9 insertions(+) create mode 100644 changes/bug30804 (limited to 'changes') diff --git a/changes/bug30804 b/changes/bug30804 new file mode 100644 index 0000000000..ba4a3e8b8c --- /dev/null +++ b/changes/bug30804 @@ -0,0 +1,4 @@ + o Minor bugfixes (testing): + - Teach the util/socketpair_ersatz test to work correctly when we + have no network stack configured. Fixes bug 30804; bugfix on + 0.2.5.1-alpha. diff --git a/src/test/test_util.c b/src/test/test_util.c index 2faadd4e19..41ecbfd388 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -5399,6 +5399,11 @@ test_util_socketpair(void *arg) tt_skip(); } #endif /* defined(__FreeBSD__) */ + if (ersatz && socketpair_result == -ENETUNREACH) { + /* We can also fail with -ENETUNREACH if we have no network stack at + * all. */ + tt_skip(); + } tt_int_op(0, OP_EQ, socketpair_result); tt_assert(SOCKET_OK(fds[0])); -- cgit v1.2.3-54-g00ecf From 973800b847844cfaacf48658d02fe3ada77cbcf6 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 11 Jun 2019 14:29:10 +1000 Subject: scripts/git: Stop hard-coding the bash path in the git scripts Some OSes don't have bash in /usr/bin, others have an ancient bash at this path. Fixes bug 30840; bugfix on 0.4.0.1-alpha. --- changes/bug30840 | 4 ++++ scripts/git/git-merge-forward.sh | 2 +- scripts/git/git-pull-all.sh | 2 +- scripts/git/git-push-all.sh | 2 +- scripts/git/pre-commit.git-hook | 2 +- scripts/git/pre-push.git-hook | 2 +- 6 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 changes/bug30840 (limited to 'changes') diff --git a/changes/bug30840 b/changes/bug30840 new file mode 100644 index 0000000000..562b0fbd93 --- /dev/null +++ b/changes/bug30840 @@ -0,0 +1,4 @@ + o Minor bugfixes (git scripts): + - Stop hard-coding the bash path in the git scripts. Some OSes don't + have bash in /usr/bin, others have an ancient bash at this path. + Fixes bug 30840; bugfix on 0.4.0.1-alpha. diff --git a/scripts/git/git-merge-forward.sh b/scripts/git/git-merge-forward.sh index 15af6f3dba..c9ec55ac6f 100755 --- a/scripts/git/git-merge-forward.sh +++ b/scripts/git/git-merge-forward.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash ############################## # Configuration (change me!) # diff --git a/scripts/git/git-pull-all.sh b/scripts/git/git-pull-all.sh index 6fe7e59812..e5ba96a059 100755 --- a/scripts/git/git-pull-all.sh +++ b/scripts/git/git-pull-all.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash ################################## # User configuration (change me) # diff --git a/scripts/git/git-push-all.sh b/scripts/git/git-push-all.sh index 0701b27b59..2030a600ff 100755 --- a/scripts/git/git-push-all.sh +++ b/scripts/git/git-push-all.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # The remote upstream branch on which git.torproject.org/tor.git points to. UPSTREAM_BRANCH=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"} diff --git a/scripts/git/pre-commit.git-hook b/scripts/git/pre-commit.git-hook index b285776c04..2a29837198 100755 --- a/scripts/git/pre-commit.git-hook +++ b/scripts/git/pre-commit.git-hook @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # To install this script, copy it to .git/hooks/pre-commit in local copy of # tor git repo and make sure it has permission to execute. diff --git a/scripts/git/pre-push.git-hook b/scripts/git/pre-push.git-hook index c9e72a4d43..51b0c896c8 100755 --- a/scripts/git/pre-push.git-hook +++ b/scripts/git/pre-push.git-hook @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # git pre-push hook script to: # 1) prevent "fixup!" and "squash!" commit from ending up in master, release-* -- cgit v1.2.3-54-g00ecf From 396134188f21b3f8bdfe35171f14c6b70446ea3e Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 11 Jun 2019 14:34:44 +1000 Subject: Stop hard-coding env vars in the git scripts Set the env vars: * TOR_MASTER_NAME to override the tor master branch name, and * TOR_WKT_NAME to override the worktree path Fixes bug 30841; bugfix on 0.4.0.1-alpha. --- changes/bug30841 | 3 +++ scripts/git/git-merge-forward.sh | 4 ++-- scripts/git/git-pull-all.sh | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 changes/bug30841 (limited to 'changes') diff --git a/changes/bug30841 b/changes/bug30841 new file mode 100644 index 0000000000..c6d1c51469 --- /dev/null +++ b/changes/bug30841 @@ -0,0 +1,3 @@ + o Minor bugfixes (git scripts): + - Stop hard-coding the tor master branch name and worktree path in the + git scripts. Fixes bug 30841; bugfix on 0.4.0.1-alpha. diff --git a/scripts/git/git-merge-forward.sh b/scripts/git/git-merge-forward.sh index c9ec55ac6f..ba29983284 100755 --- a/scripts/git/git-merge-forward.sh +++ b/scripts/git/git-merge-forward.sh @@ -17,9 +17,9 @@ GIT_PATH=${TOR_FULL_GIT_PATH:-"FULL_PATH_TO_GIT_REPOSITORY_DIRECTORY"} # The tor master git repository directory from which all the worktree have # been created. -TOR_MASTER_NAME="tor" +TOR_MASTER_NAME=${TOR_MASTER_NAME:-"tor"} # The worktrees location (directory). -TOR_WKT_NAME="tor-wkt" +TOR_WKT_NAME=${TOR_WKT_NAME:-"tor-wkt"} ######################### # End of configuration. # diff --git a/scripts/git/git-pull-all.sh b/scripts/git/git-pull-all.sh index e5ba96a059..8eb42c7c18 100755 --- a/scripts/git/git-pull-all.sh +++ b/scripts/git/git-pull-all.sh @@ -17,9 +17,9 @@ GIT_PATH=${TOR_FULL_GIT_PATH:-"FULL_PATH_TO_GIT_REPOSITORY_DIRECTORY"} # The tor master git repository directory from which all the worktree have # been created. -TOR_MASTER_NAME="tor" +TOR_MASTER_NAME=${TOR_MASTER_NAME:-"tor"} # The worktrees location (directory). -TOR_WKT_NAME="tor-wkt" +TOR_WKT_NAME=${TOR_WKT_NAME:-"tor-wkt"} ######################### # End of configuration. # -- cgit v1.2.3-54-g00ecf From bff42c86cd3e054ee14885f7eb4896340828f7be Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 11 Jun 2019 15:15:19 +1000 Subject: changes: file for 30799 Note that this memory leak is in unreachable code. --- changes/bug30799 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/bug30799 (limited to 'changes') diff --git a/changes/bug30799 b/changes/bug30799 new file mode 100644 index 0000000000..b10420a953 --- /dev/null +++ b/changes/bug30799 @@ -0,0 +1,4 @@ + o Minor bugfixes (memory management): + - Stop leaking a small amount of memory in nt_service_install(), in + unreachable code. Fixes bug 30799; bugfix on 0.2.0.7-alpha. + Patch by Xiaoyin Liu. -- cgit v1.2.3-54-g00ecf From 7cf9d54e6d7a08f169a27f7d76731e61ebe63fb0 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 29 May 2019 11:34:07 -0400 Subject: token-bucket: Implement a single counter object Closes #30687. Signed-off-by: David Goulet --- changes/ticket30687 | 3 + src/lib/evloop/token_bucket.c | 52 +++++++++++++++ src/lib/evloop/token_bucket.h | 29 ++++++++ src/test/include.am | 1 + src/test/test.c | 1 + src/test/test.h | 1 + src/test/test_token_bucket.c | 152 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 239 insertions(+) create mode 100644 changes/ticket30687 create mode 100644 src/test/test_token_bucket.c (limited to 'changes') diff --git a/changes/ticket30687 b/changes/ticket30687 new file mode 100644 index 0000000000..c3124eb64b --- /dev/null +++ b/changes/ticket30687 @@ -0,0 +1,3 @@ + o Minor feature (token bucket): + - Implement a generic token bucket that uses a single counter. This will be + useful for the anti-DoS onion service work. Closes ticket 30687. diff --git a/src/lib/evloop/token_bucket.c b/src/lib/evloop/token_bucket.c index ee6d631e3b..ec62d1b018 100644 --- a/src/lib/evloop/token_bucket.c +++ b/src/lib/evloop/token_bucket.c @@ -256,3 +256,55 @@ token_bucket_rw_dec(token_bucket_rw_t *bucket, flags |= TB_WRITE; return flags; } + +/** Initialize a token bucket in bucket, set up to allow rate + * per second, with a maximum burst of burst. The bucket is created + * such that now_ts is the current timestamp. The bucket starts out + * full. */ +void +token_bucket_ctr_init(token_bucket_ctr_t *bucket, uint32_t rate, + uint32_t burst, uint32_t now_ts) +{ + memset(bucket, 0, sizeof(token_bucket_ctr_t)); + token_bucket_ctr_adjust(bucket, rate, burst); + token_bucket_ctr_reset(bucket, now_ts); +} + +/** Change the configured rate and burst of the given token bucket object in + * bucket. */ +void +token_bucket_ctr_adjust(token_bucket_ctr_t *bucket, uint32_t rate, + uint32_t burst) +{ + token_bucket_cfg_init(&bucket->cfg, rate, burst); + token_bucket_raw_adjust(&bucket->counter, &bucket->cfg); +} + +/** Reset bucket to be full, as of timestamp now_ts. */ +void +token_bucket_ctr_reset(token_bucket_ctr_t *bucket, uint32_t now_ts) +{ + token_bucket_raw_reset(&bucket->counter, &bucket->cfg); + bucket->last_refilled_at_timestamp = now_ts; +} + +/** Refill bucket as appropriate, given that the current timestamp is + * now_ts. */ +void +token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts) +{ + const uint32_t elapsed_ticks = + (now_ts - bucket->last_refilled_at_timestamp); + if (elapsed_ticks > UINT32_MAX-(300*1000)) { + /* Either about 48 days have passed since the last refill, or the + * monotonic clock has somehow moved backwards. (We're looking at you, + * Windows.). We accept up to a 5 minute jump backwards as + * "unremarkable". + */ + return; + } + + token_bucket_raw_refill_steps(&bucket->counter, &bucket->cfg, + elapsed_ticks); + bucket->last_refilled_at_timestamp = now_ts; +} diff --git a/src/lib/evloop/token_bucket.h b/src/lib/evloop/token_bucket.h index 9398d2baa3..35b4246b12 100644 --- a/src/lib/evloop/token_bucket.h +++ b/src/lib/evloop/token_bucket.h @@ -103,6 +103,35 @@ token_bucket_rw_get_write(const token_bucket_rw_t *bucket) return token_bucket_raw_get(&bucket->write_bucket); } +/** + * A specialized bucket containing a single counter. + */ + +typedef struct token_bucket_ctr_t { + token_bucket_cfg_t cfg; + token_bucket_raw_t counter; + uint32_t last_refilled_at_timestamp; +} token_bucket_ctr_t; + +void token_bucket_ctr_init(token_bucket_ctr_t *bucket, uint32_t rate, + uint32_t burst, uint32_t now_ts); +void token_bucket_ctr_adjust(token_bucket_ctr_t *bucket, uint32_t rate, + uint32_t burst); +void token_bucket_ctr_reset(token_bucket_ctr_t *bucket, uint32_t now_ts); +void token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts); + +static inline bool +token_bucket_ctr_dec(token_bucket_ctr_t *bucket, ssize_t n) +{ + return token_bucket_raw_dec(&bucket->counter, n); +} + +static inline size_t +token_bucket_ctr_get(const token_bucket_ctr_t *bucket) +{ + return token_bucket_raw_get(&bucket->counter); +} + #ifdef TOKEN_BUCKET_PRIVATE /* To avoid making the rates too small, we consider units of "steps", diff --git a/src/test/include.am b/src/test/include.am index 85f9c9f880..624bca66d9 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -193,6 +193,7 @@ src_test_test_SOURCES += \ src/test/test_status.c \ src/test/test_storagedir.c \ src/test/test_threads.c \ + src/test/test_token_bucket.c \ src/test/test_tortls.c \ src/test/test_util.c \ src/test/test_util_format.c \ diff --git a/src/test/test.c b/src/test/test.c index cac98dd839..cc08531702 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -916,6 +916,7 @@ struct testgroup_t testgroups[] = { { "socks/", socks_tests }, { "status/" , status_tests }, { "storagedir/", storagedir_tests }, + { "token_bucket/", token_bucket_tests }, { "tortls/", tortls_tests }, #ifndef ENABLE_NSS { "tortls/openssl/", tortls_openssl_tests }, diff --git a/src/test/test.h b/src/test/test.h index 167fd090ac..85e8b07ff7 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -272,6 +272,7 @@ extern struct testcase_t sr_tests[]; extern struct testcase_t status_tests[]; extern struct testcase_t storagedir_tests[]; extern struct testcase_t thread_tests[]; +extern struct testcase_t token_bucket_tests[]; extern struct testcase_t tortls_openssl_tests[]; extern struct testcase_t tortls_tests[]; extern struct testcase_t util_format_tests[]; diff --git a/src/test/test_token_bucket.c b/src/test/test_token_bucket.c new file mode 100644 index 0000000000..d3ce591388 --- /dev/null +++ b/src/test/test_token_bucket.c @@ -0,0 +1,152 @@ +/* Copyright (c) 2018-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file test_bwmgt.c + * \brief tests for bandwidth management / token bucket functions + */ + +#define TOKEN_BUCKET_PRIVATE + +#include "core/or/or.h" +#include "test/test.h" + +#include "lib/evloop/token_bucket.h" + +// an imaginary time, in timestamp units. Chosen so it will roll over. +static const uint32_t START_TS = UINT32_MAX - 1000; +static const uint32_t RATE = 10; +static const uint32_t BURST = 50; + +static void +test_token_bucket_ctr_init(void *arg) +{ + (void) arg; + token_bucket_ctr_t tb; + + token_bucket_ctr_init(&tb, RATE, BURST, START_TS); + tt_uint_op(tb.cfg.rate, OP_EQ, RATE); + tt_uint_op(tb.cfg.burst, OP_EQ, BURST); + tt_uint_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS); + tt_int_op(tb.counter.bucket, OP_EQ, BURST); + + done: + ; +} + +static void +test_token_bucket_ctr_adjust(void *arg) +{ + (void) arg; + token_bucket_ctr_t tb; + + token_bucket_ctr_init(&tb, RATE, BURST, START_TS); + + /* Increase burst. */ + token_bucket_ctr_adjust(&tb, RATE, BURST * 2); + tt_uint_op(tb.cfg.rate, OP_EQ, RATE); + tt_uint_op(tb.counter.bucket, OP_EQ, BURST); + tt_uint_op(tb.cfg.burst, OP_EQ, BURST * 2); + + /* Decrease burst but still above bucket value. */ + token_bucket_ctr_adjust(&tb, RATE, BURST + 10); + tt_uint_op(tb.cfg.rate, OP_EQ, RATE); + tt_uint_op(tb.counter.bucket, OP_EQ, BURST); + tt_uint_op(tb.cfg.burst, OP_EQ, BURST + 10); + + /* Decrease burst below bucket value. */ + token_bucket_ctr_adjust(&tb, RATE, BURST - 1); + tt_uint_op(tb.cfg.rate, OP_EQ, RATE); + tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1); + tt_uint_op(tb.cfg.burst, OP_EQ, BURST - 1); + + /* Change rate. */ + token_bucket_ctr_adjust(&tb, RATE * 2, BURST); + tt_uint_op(tb.cfg.rate, OP_EQ, RATE * 2); + tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1); + tt_uint_op(tb.cfg.burst, OP_EQ, BURST); + + done: + ; +} + +static void +test_token_bucket_ctr_dec(void *arg) +{ + (void) arg; + token_bucket_ctr_t tb; + + token_bucket_ctr_init(&tb, RATE, BURST, START_TS); + + /* Simple decrement by one. */ + tt_uint_op(0, OP_EQ, token_bucket_ctr_dec(&tb, 1)); + tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1); + + /* Down to 0. Becomes empty. */ + tt_uint_op(true, OP_EQ, token_bucket_ctr_dec(&tb, BURST - 1)); + tt_uint_op(tb.counter.bucket, OP_EQ, 0); + + /* Reset and try to underflow. */ + token_bucket_ctr_init(&tb, RATE, BURST, START_TS); + tt_uint_op(true, OP_EQ, token_bucket_ctr_dec(&tb, BURST + 1)); + tt_int_op(tb.counter.bucket, OP_EQ, -1); + + /* Keep underflowing shouldn't flag the bucket as empty. */ + tt_uint_op(false, OP_EQ, token_bucket_ctr_dec(&tb, BURST)); + tt_int_op(tb.counter.bucket, OP_EQ, (int32_t) ((BURST + 1) * -1)); + + done: + ; +} + +static void +test_token_bucket_ctr_refill(void *arg) +{ + (void) arg; + token_bucket_ctr_t tb; + + token_bucket_ctr_init(&tb, RATE, BURST, START_TS); + + /* Reduce of half the bucket and let a single second go before refill. */ + token_bucket_ctr_dec(&tb, BURST / 2); + tt_int_op(tb.counter.bucket, OP_EQ, BURST / 2); + token_bucket_ctr_refill(&tb, START_TS + 1); + tt_int_op(tb.counter.bucket, OP_EQ, (BURST / 2) + RATE); + tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 1); + + /* No time change, nothing should move. */ + token_bucket_ctr_refill(&tb, START_TS + 1); + tt_int_op(tb.counter.bucket, OP_EQ, (BURST / 2) + RATE); + tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 1); + + /* Add 99 seconds, bucket should be back to a full BURST. */ + token_bucket_ctr_refill(&tb, START_TS + 99); + tt_int_op(tb.counter.bucket, OP_EQ, BURST); + tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 99); + + /* Empty bucket at once. */ + token_bucket_ctr_dec(&tb, BURST); + tt_int_op(tb.counter.bucket, OP_EQ, 0); + /* On second passes. */ + token_bucket_ctr_refill(&tb, START_TS + 100); + tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 100); + tt_int_op(tb.counter.bucket, OP_EQ, RATE); + /* A second second passes. */ + token_bucket_ctr_refill(&tb, START_TS + 101); + tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 101); + tt_int_op(tb.counter.bucket, OP_EQ, RATE * 2); + + done: + ; +} + +#define TOKEN_BUCKET(name) \ + { #name, test_token_bucket_ ## name , 0, NULL, NULL } + +struct testcase_t token_bucket_tests[] = { + TOKEN_BUCKET(ctr_init), + TOKEN_BUCKET(ctr_adjust), + TOKEN_BUCKET(ctr_dec), + TOKEN_BUCKET(ctr_refill), + END_OF_TESTCASES +}; -- cgit v1.2.3-54-g00ecf From c1359b32a43b09be96e0388c12b75a9deda17e4f Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 5 Jun 2019 09:57:52 -0400 Subject: trunnel: Rename sendme.trunnel to sendme_cell.trunnel This is to avoid having two sendme.{c|h} in the repository since the subsystem is implemented in src/core/or/sendme.{c|h}. Fixes #30769 Signed-off-by: David Goulet --- changes/ticket30769 | 4 + src/core/or/sendme.c | 2 +- src/ext/trunnel/trunnel-impl.h | 2 +- src/ext/trunnel/trunnel.c | 2 +- src/ext/trunnel/trunnel.h | 2 +- src/trunnel/channelpadding_negotiation.c | 2 +- src/trunnel/channelpadding_negotiation.h | 2 +- src/trunnel/circpad_negotiation.c | 2 +- src/trunnel/circpad_negotiation.h | 2 +- src/trunnel/ed25519_cert.c | 2 +- src/trunnel/ed25519_cert.h | 2 +- src/trunnel/hs/cell_common.c | 2 +- src/trunnel/hs/cell_common.h | 2 +- src/trunnel/hs/cell_establish_intro.c | 2 +- src/trunnel/hs/cell_establish_intro.h | 2 +- src/trunnel/hs/cell_introduce1.c | 2 +- src/trunnel/hs/cell_introduce1.h | 2 +- src/trunnel/hs/cell_rendezvous.c | 2 +- src/trunnel/hs/cell_rendezvous.h | 2 +- src/trunnel/include.am | 6 +- src/trunnel/link_handshake.c | 2 +- src/trunnel/link_handshake.h | 2 +- src/trunnel/netinfo.c | 2 +- src/trunnel/netinfo.h | 2 +- src/trunnel/pwbox.c | 2 +- src/trunnel/pwbox.h | 2 +- src/trunnel/sendme.c | 347 ------------------------------- src/trunnel/sendme.h | 101 --------- src/trunnel/sendme.trunnel | 19 -- src/trunnel/sendme_cell.c | 347 +++++++++++++++++++++++++++++++ src/trunnel/sendme_cell.h | 101 +++++++++ src/trunnel/sendme_cell.trunnel | 19 ++ src/trunnel/socks5.c | 2 +- src/trunnel/socks5.h | 2 +- 34 files changed, 500 insertions(+), 496 deletions(-) create mode 100644 changes/ticket30769 delete mode 100644 src/trunnel/sendme.c delete mode 100644 src/trunnel/sendme.h delete mode 100644 src/trunnel/sendme.trunnel create mode 100644 src/trunnel/sendme_cell.c create mode 100644 src/trunnel/sendme_cell.h create mode 100644 src/trunnel/sendme_cell.trunnel (limited to 'changes') diff --git a/changes/ticket30769 b/changes/ticket30769 new file mode 100644 index 0000000000..74f63a1465 --- /dev/null +++ b/changes/ticket30769 @@ -0,0 +1,4 @@ + o Minor bugfixes (sendme, code structure): + - Rename the trunnel SENDME file definition from sendme.trunnel to + sendme_cell.trunnel to avoid having twice sendme.{c|h} in the repository. + Fixes bug 30769; bugfix on 0.4.1.1-alpha. diff --git a/src/core/or/sendme.c b/src/core/or/sendme.c index 47ac95f3cf..0757ce3d52 100644 --- a/src/core/or/sendme.c +++ b/src/core/or/sendme.c @@ -23,7 +23,7 @@ #include "core/or/sendme.h" #include "feature/nodelist/networkstatus.h" #include "lib/ctime/di_ops.h" -#include "trunnel/sendme.h" +#include "trunnel/sendme_cell.h" /* Return the minimum version given by the consensus (if any) that should be * used when emitting a SENDME cell. */ diff --git a/src/ext/trunnel/trunnel-impl.h b/src/ext/trunnel/trunnel-impl.h index 15d1c8633e..52afa9ccd4 100644 --- a/src/ext/trunnel/trunnel-impl.h +++ b/src/ext/trunnel/trunnel-impl.h @@ -1,4 +1,4 @@ -/* trunnel-impl.h -- copied from Trunnel v1.5.2 +/* trunnel-impl.h -- copied from Trunnel v1.5.3 * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/ext/trunnel/trunnel.c b/src/ext/trunnel/trunnel.c index 3ae3fe02c8..01a55c5bec 100644 --- a/src/ext/trunnel/trunnel.c +++ b/src/ext/trunnel/trunnel.c @@ -1,4 +1,4 @@ -/* trunnel.c -- copied from Trunnel v1.5.2 +/* trunnel.c -- copied from Trunnel v1.5.3 * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/ext/trunnel/trunnel.h b/src/ext/trunnel/trunnel.h index 9b708437b8..87c75f4ec3 100644 --- a/src/ext/trunnel/trunnel.h +++ b/src/ext/trunnel/trunnel.h @@ -1,4 +1,4 @@ -/* trunnel.h -- copied from Trunnel v1.5.2 +/* trunnel.h -- copied from Trunnel v1.5.3 * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/channelpadding_negotiation.c b/src/trunnel/channelpadding_negotiation.c index 59e6b38384..d96496e90c 100644 --- a/src/trunnel/channelpadding_negotiation.c +++ b/src/trunnel/channelpadding_negotiation.c @@ -1,4 +1,4 @@ -/* channelpadding_negotiation.c -- generated by Trunnel v1.5.2. +/* channelpadding_negotiation.c -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/channelpadding_negotiation.h b/src/trunnel/channelpadding_negotiation.h index fcfc232fea..3f96174f68 100644 --- a/src/trunnel/channelpadding_negotiation.h +++ b/src/trunnel/channelpadding_negotiation.h @@ -1,4 +1,4 @@ -/* channelpadding_negotiation.h -- generated by Trunnel v1.5.2. +/* channelpadding_negotiation.h -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/circpad_negotiation.c b/src/trunnel/circpad_negotiation.c index 236be06ada..547818f2ec 100644 --- a/src/trunnel/circpad_negotiation.c +++ b/src/trunnel/circpad_negotiation.c @@ -1,4 +1,4 @@ -/* circpad_negotiation.c -- generated by Trunnel v1.5.2. +/* circpad_negotiation.c -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/circpad_negotiation.h b/src/trunnel/circpad_negotiation.h index d09080dc16..ba9155019e 100644 --- a/src/trunnel/circpad_negotiation.h +++ b/src/trunnel/circpad_negotiation.h @@ -1,4 +1,4 @@ -/* circpad_negotiation.h -- generated by Trunnel v1.5.2. +/* circpad_negotiation.h -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/ed25519_cert.c b/src/trunnel/ed25519_cert.c index 1276c7a505..86b79ef9b6 100644 --- a/src/trunnel/ed25519_cert.c +++ b/src/trunnel/ed25519_cert.c @@ -1,4 +1,4 @@ -/* ed25519_cert.c -- generated by Trunnel v1.5.2. +/* ed25519_cert.c -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/ed25519_cert.h b/src/trunnel/ed25519_cert.h index e086c6fced..bd91ce1055 100644 --- a/src/trunnel/ed25519_cert.h +++ b/src/trunnel/ed25519_cert.h @@ -1,4 +1,4 @@ -/* ed25519_cert.h -- generated by Trunnel v1.5.2. +/* ed25519_cert.h -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/hs/cell_common.c b/src/trunnel/hs/cell_common.c index af223560c1..830af5c78b 100644 --- a/src/trunnel/hs/cell_common.c +++ b/src/trunnel/hs/cell_common.c @@ -1,4 +1,4 @@ -/* cell_common.c -- generated by Trunnel v1.5.2. +/* cell_common.c -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/hs/cell_common.h b/src/trunnel/hs/cell_common.h index e08eedfdb3..c84d17d8e5 100644 --- a/src/trunnel/hs/cell_common.h +++ b/src/trunnel/hs/cell_common.h @@ -1,4 +1,4 @@ -/* cell_common.h -- generated by Trunnel v1.5.2. +/* cell_common.h -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/hs/cell_establish_intro.c b/src/trunnel/hs/cell_establish_intro.c index ae3b7b1bc8..99ceadbda4 100644 --- a/src/trunnel/hs/cell_establish_intro.c +++ b/src/trunnel/hs/cell_establish_intro.c @@ -1,4 +1,4 @@ -/* cell_establish_intro.c -- generated by Trunnel v1.5.2. +/* cell_establish_intro.c -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/hs/cell_establish_intro.h b/src/trunnel/hs/cell_establish_intro.h index ccaef5488c..1908645aa6 100644 --- a/src/trunnel/hs/cell_establish_intro.h +++ b/src/trunnel/hs/cell_establish_intro.h @@ -1,4 +1,4 @@ -/* cell_establish_intro.h -- generated by Trunnel v1.5.2. +/* cell_establish_intro.h -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/hs/cell_introduce1.c b/src/trunnel/hs/cell_introduce1.c index 53b3d299f2..016c9fa8d6 100644 --- a/src/trunnel/hs/cell_introduce1.c +++ b/src/trunnel/hs/cell_introduce1.c @@ -1,4 +1,4 @@ -/* cell_introduce1.c -- generated by Trunnel v1.5.2. +/* cell_introduce1.c -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/hs/cell_introduce1.h b/src/trunnel/hs/cell_introduce1.h index 986a531ca7..8dabff3cb5 100644 --- a/src/trunnel/hs/cell_introduce1.h +++ b/src/trunnel/hs/cell_introduce1.h @@ -1,4 +1,4 @@ -/* cell_introduce1.h -- generated by Trunnel v1.5.2. +/* cell_introduce1.h -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/hs/cell_rendezvous.c b/src/trunnel/hs/cell_rendezvous.c index 53cb609138..1204e93cfc 100644 --- a/src/trunnel/hs/cell_rendezvous.c +++ b/src/trunnel/hs/cell_rendezvous.c @@ -1,4 +1,4 @@ -/* cell_rendezvous.c -- generated by Trunnel v1.5.2. +/* cell_rendezvous.c -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/hs/cell_rendezvous.h b/src/trunnel/hs/cell_rendezvous.h index 39e14da25b..5a8c2ff52a 100644 --- a/src/trunnel/hs/cell_rendezvous.h +++ b/src/trunnel/hs/cell_rendezvous.h @@ -1,4 +1,4 @@ -/* cell_rendezvous.h -- generated by Trunnel v1.5.2. +/* cell_rendezvous.h -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/include.am b/src/trunnel/include.am index ce15570b15..6c3a5ff06b 100644 --- a/src/trunnel/include.am +++ b/src/trunnel/include.am @@ -11,7 +11,7 @@ TRUNNELINPUTS = \ src/trunnel/link_handshake.trunnel \ src/trunnel/pwbox.trunnel \ src/trunnel/channelpadding_negotiation.trunnel \ - src/trunnel/sendme.trunnel \ + src/trunnel/sendme_cell.trunnel \ src/trunnel/socks5.trunnel \ src/trunnel/circpad_negotiation.trunnel @@ -25,7 +25,7 @@ TRUNNELSOURCES = \ src/trunnel/hs/cell_introduce1.c \ src/trunnel/hs/cell_rendezvous.c \ src/trunnel/channelpadding_negotiation.c \ - src/trunnel/sendme.c \ + src/trunnel/sendme_cell.c \ src/trunnel/socks5.c \ src/trunnel/netinfo.c \ src/trunnel/circpad_negotiation.c @@ -42,7 +42,7 @@ TRUNNELHEADERS = \ src/trunnel/hs/cell_introduce1.h \ src/trunnel/hs/cell_rendezvous.h \ src/trunnel/channelpadding_negotiation.h \ - src/trunnel/sendme.h \ + src/trunnel/sendme_cell.h \ src/trunnel/socks5.h \ src/trunnel/netinfo.h \ src/trunnel/circpad_negotiation.h diff --git a/src/trunnel/link_handshake.c b/src/trunnel/link_handshake.c index 03ead31c62..76db4b0e29 100644 --- a/src/trunnel/link_handshake.c +++ b/src/trunnel/link_handshake.c @@ -1,4 +1,4 @@ -/* link_handshake.c -- generated by Trunnel v1.5.2. +/* link_handshake.c -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/link_handshake.h b/src/trunnel/link_handshake.h index 6a23483adc..0c7ac36b1b 100644 --- a/src/trunnel/link_handshake.h +++ b/src/trunnel/link_handshake.h @@ -1,4 +1,4 @@ -/* link_handshake.h -- generated by Trunnel v1.5.2. +/* link_handshake.h -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/netinfo.c b/src/trunnel/netinfo.c index 5d815b9b12..d7d0cddc89 100644 --- a/src/trunnel/netinfo.c +++ b/src/trunnel/netinfo.c @@ -1,4 +1,4 @@ -/* netinfo.c -- generated by Trunnel v1.5.2. +/* netinfo.c -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/netinfo.h b/src/trunnel/netinfo.h index ac46e603ba..37c2ae3c2d 100644 --- a/src/trunnel/netinfo.h +++ b/src/trunnel/netinfo.h @@ -1,4 +1,4 @@ -/* netinfo.h -- generated by Trunnel v1.5.2. +/* netinfo.h -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/pwbox.c b/src/trunnel/pwbox.c index c356515d36..c159a5e687 100644 --- a/src/trunnel/pwbox.c +++ b/src/trunnel/pwbox.c @@ -1,4 +1,4 @@ -/* pwbox.c -- generated by Trunnel v1.5.2. +/* pwbox.c -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/pwbox.h b/src/trunnel/pwbox.h index a9a421408a..36d595f4ef 100644 --- a/src/trunnel/pwbox.h +++ b/src/trunnel/pwbox.h @@ -1,4 +1,4 @@ -/* pwbox.h -- generated by Trunnel v1.5.2. +/* pwbox.h -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/sendme.c b/src/trunnel/sendme.c deleted file mode 100644 index 262b915234..0000000000 --- a/src/trunnel/sendme.c +++ /dev/null @@ -1,347 +0,0 @@ -/* sendme.c -- generated by Trunnel v1.5.2. - * https://gitweb.torproject.org/trunnel.git - * You probably shouldn't edit this file. - */ -#include -#include "trunnel-impl.h" - -#include "sendme.h" - -#define TRUNNEL_SET_ERROR_CODE(obj) \ - do { \ - (obj)->trunnel_error_code_ = 1; \ - } while (0) - -#if defined(__COVERITY__) || defined(__clang_analyzer__) -/* If we're running a static analysis tool, we don't want it to complain - * that some of our remaining-bytes checks are dead-code. */ -int sendme_deadcode_dummy__ = 0; -#define OR_DEADCODE_DUMMY || sendme_deadcode_dummy__ -#else -#define OR_DEADCODE_DUMMY -#endif - -#define CHECK_REMAINING(nbytes, label) \ - do { \ - if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ - goto label; \ - } \ - } while (0) - -sendme_cell_t * -sendme_cell_new(void) -{ - sendme_cell_t *val = trunnel_calloc(1, sizeof(sendme_cell_t)); - if (NULL == val) - return NULL; - return val; -} - -/** Release all storage held inside 'obj', but do not free 'obj'. - */ -static void -sendme_cell_clear(sendme_cell_t *obj) -{ - (void) obj; -} - -void -sendme_cell_free(sendme_cell_t *obj) -{ - if (obj == NULL) - return; - sendme_cell_clear(obj); - trunnel_memwipe(obj, sizeof(sendme_cell_t)); - trunnel_free_(obj); -} - -uint8_t -sendme_cell_get_version(const sendme_cell_t *inp) -{ - return inp->version; -} -int -sendme_cell_set_version(sendme_cell_t *inp, uint8_t val) -{ - if (! ((val == 0 || val == 1))) { - TRUNNEL_SET_ERROR_CODE(inp); - return -1; - } - inp->version = val; - return 0; -} -uint16_t -sendme_cell_get_data_len(const sendme_cell_t *inp) -{ - return inp->data_len; -} -int -sendme_cell_set_data_len(sendme_cell_t *inp, uint16_t val) -{ - inp->data_len = val; - return 0; -} -size_t -sendme_cell_getlen_data_v1_digest(const sendme_cell_t *inp) -{ - (void)inp; return TRUNNEL_SENDME_V1_DIGEST_LEN; -} - -uint8_t -sendme_cell_get_data_v1_digest(sendme_cell_t *inp, size_t idx) -{ - trunnel_assert(idx < TRUNNEL_SENDME_V1_DIGEST_LEN); - return inp->data_v1_digest[idx]; -} - -uint8_t -sendme_cell_getconst_data_v1_digest(const sendme_cell_t *inp, size_t idx) -{ - return sendme_cell_get_data_v1_digest((sendme_cell_t*)inp, idx); -} -int -sendme_cell_set_data_v1_digest(sendme_cell_t *inp, size_t idx, uint8_t elt) -{ - trunnel_assert(idx < TRUNNEL_SENDME_V1_DIGEST_LEN); - inp->data_v1_digest[idx] = elt; - return 0; -} - -uint8_t * -sendme_cell_getarray_data_v1_digest(sendme_cell_t *inp) -{ - return inp->data_v1_digest; -} -const uint8_t * -sendme_cell_getconstarray_data_v1_digest(const sendme_cell_t *inp) -{ - return (const uint8_t *)sendme_cell_getarray_data_v1_digest((sendme_cell_t*)inp); -} -const char * -sendme_cell_check(const sendme_cell_t *obj) -{ - if (obj == NULL) - return "Object was NULL"; - if (obj->trunnel_error_code_) - return "A set function failed on this object"; - if (! (obj->version == 0 || obj->version == 1)) - return "Integer out of bounds"; - switch (obj->version) { - - case 0: - break; - - case 1: - break; - - default: - return "Bad tag for union"; - break; - } - return NULL; -} - -ssize_t -sendme_cell_encoded_len(const sendme_cell_t *obj) -{ - ssize_t result = 0; - - if (NULL != sendme_cell_check(obj)) - return -1; - - - /* Length of u8 version IN [0, 1] */ - result += 1; - - /* Length of u16 data_len */ - result += 2; - switch (obj->version) { - - case 0: - break; - - case 1: - - /* Length of u8 data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN] */ - result += TRUNNEL_SENDME_V1_DIGEST_LEN; - break; - - default: - trunnel_assert(0); - break; - } - return result; -} -int -sendme_cell_clear_errors(sendme_cell_t *obj) -{ - int r = obj->trunnel_error_code_; - obj->trunnel_error_code_ = 0; - return r; -} -ssize_t -sendme_cell_encode(uint8_t *output, const size_t avail, const sendme_cell_t *obj) -{ - ssize_t result = 0; - size_t written = 0; - uint8_t *ptr = output; - const char *msg; -#ifdef TRUNNEL_CHECK_ENCODED_LEN - const ssize_t encoded_len = sendme_cell_encoded_len(obj); -#endif - - uint8_t *backptr_data_len = NULL; - - if (NULL != (msg = sendme_cell_check(obj))) - goto check_failed; - -#ifdef TRUNNEL_CHECK_ENCODED_LEN - trunnel_assert(encoded_len >= 0); -#endif - - /* Encode u8 version IN [0, 1] */ - trunnel_assert(written <= avail); - if (avail - written < 1) - goto truncated; - trunnel_set_uint8(ptr, (obj->version)); - written += 1; ptr += 1; - - /* Encode u16 data_len */ - backptr_data_len = ptr; - trunnel_assert(written <= avail); - if (avail - written < 2) - goto truncated; - trunnel_set_uint16(ptr, trunnel_htons(obj->data_len)); - written += 2; ptr += 2; - { - size_t written_before_union = written; - - /* Encode union data[version] */ - trunnel_assert(written <= avail); - switch (obj->version) { - - case 0: - break; - - case 1: - - /* Encode u8 data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN] */ - trunnel_assert(written <= avail); - if (avail - written < TRUNNEL_SENDME_V1_DIGEST_LEN) - goto truncated; - memcpy(ptr, obj->data_v1_digest, TRUNNEL_SENDME_V1_DIGEST_LEN); - written += TRUNNEL_SENDME_V1_DIGEST_LEN; ptr += TRUNNEL_SENDME_V1_DIGEST_LEN; - break; - - default: - trunnel_assert(0); - break; - } - /* Write the length field back to data_len */ - trunnel_assert(written >= written_before_union); -#if UINT16_MAX < SIZE_MAX - if (written - written_before_union > UINT16_MAX) - goto check_failed; -#endif - trunnel_set_uint16(backptr_data_len, trunnel_htons(written - written_before_union)); - } - - - trunnel_assert(ptr == output + written); -#ifdef TRUNNEL_CHECK_ENCODED_LEN - { - trunnel_assert(encoded_len >= 0); - trunnel_assert((size_t)encoded_len == written); - } - -#endif - - return written; - - truncated: - result = -2; - goto fail; - check_failed: - (void)msg; - result = -1; - goto fail; - fail: - trunnel_assert(result < 0); - return result; -} - -/** As sendme_cell_parse(), but do not allocate the output object. - */ -static ssize_t -sendme_cell_parse_into(sendme_cell_t *obj, const uint8_t *input, const size_t len_in) -{ - const uint8_t *ptr = input; - size_t remaining = len_in; - ssize_t result = 0; - (void)result; - - /* Parse u8 version IN [0, 1] */ - CHECK_REMAINING(1, truncated); - obj->version = (trunnel_get_uint8(ptr)); - remaining -= 1; ptr += 1; - if (! (obj->version == 0 || obj->version == 1)) - goto fail; - - /* Parse u16 data_len */ - CHECK_REMAINING(2, truncated); - obj->data_len = trunnel_ntohs(trunnel_get_uint16(ptr)); - remaining -= 2; ptr += 2; - { - size_t remaining_after; - CHECK_REMAINING(obj->data_len, truncated); - remaining_after = remaining - obj->data_len; - remaining = obj->data_len; - - /* Parse union data[version] */ - switch (obj->version) { - - case 0: - /* Skip to end of union */ - ptr += remaining; remaining = 0; - break; - - case 1: - - /* Parse u8 data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN] */ - CHECK_REMAINING(TRUNNEL_SENDME_V1_DIGEST_LEN, fail); - memcpy(obj->data_v1_digest, ptr, TRUNNEL_SENDME_V1_DIGEST_LEN); - remaining -= TRUNNEL_SENDME_V1_DIGEST_LEN; ptr += TRUNNEL_SENDME_V1_DIGEST_LEN; - break; - - default: - goto fail; - break; - } - if (remaining != 0) - goto fail; - remaining = remaining_after; - } - trunnel_assert(ptr + remaining == input + len_in); - return len_in - remaining; - - truncated: - return -2; - fail: - result = -1; - return result; -} - -ssize_t -sendme_cell_parse(sendme_cell_t **output, const uint8_t *input, const size_t len_in) -{ - ssize_t result; - *output = sendme_cell_new(); - if (NULL == *output) - return -1; - result = sendme_cell_parse_into(*output, input, len_in); - if (result < 0) { - sendme_cell_free(*output); - *output = NULL; - } - return result; -} diff --git a/src/trunnel/sendme.h b/src/trunnel/sendme.h deleted file mode 100644 index f3c3dd78c4..0000000000 --- a/src/trunnel/sendme.h +++ /dev/null @@ -1,101 +0,0 @@ -/* sendme.h -- generated by Trunnel v1.5.2. - * https://gitweb.torproject.org/trunnel.git - * You probably shouldn't edit this file. - */ -#ifndef TRUNNEL_SENDME_H -#define TRUNNEL_SENDME_H - -#include -#include "trunnel.h" - -#define TRUNNEL_SENDME_V1_DIGEST_LEN 20 -#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_SENDME_CELL) -struct sendme_cell_st { - uint8_t version; - uint16_t data_len; - uint8_t data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN]; - uint8_t trunnel_error_code_; -}; -#endif -typedef struct sendme_cell_st sendme_cell_t; -/** Return a newly allocated sendme_cell with all elements set to - * zero. - */ -sendme_cell_t *sendme_cell_new(void); -/** Release all storage held by the sendme_cell in 'victim'. (Do - * nothing if 'victim' is NULL.) - */ -void sendme_cell_free(sendme_cell_t *victim); -/** Try to parse a sendme_cell from the buffer in 'input', using up to - * 'len_in' bytes from the input buffer. On success, return the number - * of bytes consumed and set *output to the newly allocated - * sendme_cell_t. On failure, return -2 if the input appears - * truncated, and -1 if the input is otherwise invalid. - */ -ssize_t sendme_cell_parse(sendme_cell_t **output, const uint8_t *input, const size_t len_in); -/** Return the number of bytes we expect to need to encode the - * sendme_cell in 'obj'. On failure, return a negative value. Note - * that this value may be an overestimate, and can even be an - * underestimate for certain unencodeable objects. - */ -ssize_t sendme_cell_encoded_len(const sendme_cell_t *obj); -/** Try to encode the sendme_cell from 'input' into the buffer at - * 'output', using up to 'avail' bytes of the output buffer. On - * success, return the number of bytes used. On failure, return -2 if - * the buffer was not long enough, and -1 if the input was invalid. - */ -ssize_t sendme_cell_encode(uint8_t *output, size_t avail, const sendme_cell_t *input); -/** Check whether the internal state of the sendme_cell in 'obj' is - * consistent. Return NULL if it is, and a short message if it is not. - */ -const char *sendme_cell_check(const sendme_cell_t *obj); -/** Clear any errors that were set on the object 'obj' by its setter - * functions. Return true iff errors were cleared. - */ -int sendme_cell_clear_errors(sendme_cell_t *obj); -/** Return the value of the version field of the sendme_cell_t in - * 'inp' - */ -uint8_t sendme_cell_get_version(const sendme_cell_t *inp); -/** Set the value of the version field of the sendme_cell_t in 'inp' - * to 'val'. Return 0 on success; return -1 and set the error code on - * 'inp' on failure. - */ -int sendme_cell_set_version(sendme_cell_t *inp, uint8_t val); -/** Return the value of the data_len field of the sendme_cell_t in - * 'inp' - */ -uint16_t sendme_cell_get_data_len(const sendme_cell_t *inp); -/** Set the value of the data_len field of the sendme_cell_t in 'inp' - * to 'val'. Return 0 on success; return -1 and set the error code on - * 'inp' on failure. - */ -int sendme_cell_set_data_len(sendme_cell_t *inp, uint16_t val); -/** Return the (constant) length of the array holding the - * data_v1_digest field of the sendme_cell_t in 'inp'. - */ -size_t sendme_cell_getlen_data_v1_digest(const sendme_cell_t *inp); -/** Return the element at position 'idx' of the fixed array field - * data_v1_digest of the sendme_cell_t in 'inp'. - */ -uint8_t sendme_cell_get_data_v1_digest(sendme_cell_t *inp, size_t idx); -/** As sendme_cell_get_data_v1_digest, but take and return a const - * pointer - */ -uint8_t sendme_cell_getconst_data_v1_digest(const sendme_cell_t *inp, size_t idx); -/** Change the element at position 'idx' of the fixed array field - * data_v1_digest of the sendme_cell_t in 'inp', so that it will hold - * the value 'elt'. - */ -int sendme_cell_set_data_v1_digest(sendme_cell_t *inp, size_t idx, uint8_t elt); -/** Return a pointer to the TRUNNEL_SENDME_V1_DIGEST_LEN-element array - * field data_v1_digest of 'inp'. - */ -uint8_t * sendme_cell_getarray_data_v1_digest(sendme_cell_t *inp); -/** As sendme_cell_get_data_v1_digest, but take and return a const - * pointer - */ -const uint8_t * sendme_cell_getconstarray_data_v1_digest(const sendme_cell_t *inp); - - -#endif diff --git a/src/trunnel/sendme.trunnel b/src/trunnel/sendme.trunnel deleted file mode 100644 index 300963e679..0000000000 --- a/src/trunnel/sendme.trunnel +++ /dev/null @@ -1,19 +0,0 @@ -/* This file contains the SENDME cell definition. */ - -/* v1 digest length in bytes. */ -const TRUNNEL_SENDME_V1_DIGEST_LEN = 20; - -/* SENDME cell declaration. */ -struct sendme_cell { - /* Version field. */ - u8 version IN [0x00, 0x01]; - - /* Length of data contained in this cell. */ - u16 data_len; - - /* The data content depends on the version. */ - union data[version] with length data_len { - 0x00: ignore; - 0x01: u8 v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN]; - }; -} diff --git a/src/trunnel/sendme_cell.c b/src/trunnel/sendme_cell.c new file mode 100644 index 0000000000..b9f8fe967f --- /dev/null +++ b/src/trunnel/sendme_cell.c @@ -0,0 +1,347 @@ +/* sendme_cell.c -- generated by Trunnel v1.5.3. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#include +#include "trunnel-impl.h" + +#include "sendme_cell.h" + +#define TRUNNEL_SET_ERROR_CODE(obj) \ + do { \ + (obj)->trunnel_error_code_ = 1; \ + } while (0) + +#if defined(__COVERITY__) || defined(__clang_analyzer__) +/* If we're running a static analysis tool, we don't want it to complain + * that some of our remaining-bytes checks are dead-code. */ +int sendmecell_deadcode_dummy__ = 0; +#define OR_DEADCODE_DUMMY || sendmecell_deadcode_dummy__ +#else +#define OR_DEADCODE_DUMMY +#endif + +#define CHECK_REMAINING(nbytes, label) \ + do { \ + if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ + goto label; \ + } \ + } while (0) + +sendme_cell_t * +sendme_cell_new(void) +{ + sendme_cell_t *val = trunnel_calloc(1, sizeof(sendme_cell_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +sendme_cell_clear(sendme_cell_t *obj) +{ + (void) obj; +} + +void +sendme_cell_free(sendme_cell_t *obj) +{ + if (obj == NULL) + return; + sendme_cell_clear(obj); + trunnel_memwipe(obj, sizeof(sendme_cell_t)); + trunnel_free_(obj); +} + +uint8_t +sendme_cell_get_version(const sendme_cell_t *inp) +{ + return inp->version; +} +int +sendme_cell_set_version(sendme_cell_t *inp, uint8_t val) +{ + if (! ((val == 0 || val == 1))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->version = val; + return 0; +} +uint16_t +sendme_cell_get_data_len(const sendme_cell_t *inp) +{ + return inp->data_len; +} +int +sendme_cell_set_data_len(sendme_cell_t *inp, uint16_t val) +{ + inp->data_len = val; + return 0; +} +size_t +sendme_cell_getlen_data_v1_digest(const sendme_cell_t *inp) +{ + (void)inp; return TRUNNEL_SENDME_V1_DIGEST_LEN; +} + +uint8_t +sendme_cell_get_data_v1_digest(sendme_cell_t *inp, size_t idx) +{ + trunnel_assert(idx < TRUNNEL_SENDME_V1_DIGEST_LEN); + return inp->data_v1_digest[idx]; +} + +uint8_t +sendme_cell_getconst_data_v1_digest(const sendme_cell_t *inp, size_t idx) +{ + return sendme_cell_get_data_v1_digest((sendme_cell_t*)inp, idx); +} +int +sendme_cell_set_data_v1_digest(sendme_cell_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < TRUNNEL_SENDME_V1_DIGEST_LEN); + inp->data_v1_digest[idx] = elt; + return 0; +} + +uint8_t * +sendme_cell_getarray_data_v1_digest(sendme_cell_t *inp) +{ + return inp->data_v1_digest; +} +const uint8_t * +sendme_cell_getconstarray_data_v1_digest(const sendme_cell_t *inp) +{ + return (const uint8_t *)sendme_cell_getarray_data_v1_digest((sendme_cell_t*)inp); +} +const char * +sendme_cell_check(const sendme_cell_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + if (! (obj->version == 0 || obj->version == 1)) + return "Integer out of bounds"; + switch (obj->version) { + + case 0: + break; + + case 1: + break; + + default: + return "Bad tag for union"; + break; + } + return NULL; +} + +ssize_t +sendme_cell_encoded_len(const sendme_cell_t *obj) +{ + ssize_t result = 0; + + if (NULL != sendme_cell_check(obj)) + return -1; + + + /* Length of u8 version IN [0, 1] */ + result += 1; + + /* Length of u16 data_len */ + result += 2; + switch (obj->version) { + + case 0: + break; + + case 1: + + /* Length of u8 data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN] */ + result += TRUNNEL_SENDME_V1_DIGEST_LEN; + break; + + default: + trunnel_assert(0); + break; + } + return result; +} +int +sendme_cell_clear_errors(sendme_cell_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +sendme_cell_encode(uint8_t *output, const size_t avail, const sendme_cell_t *obj) +{ + ssize_t result = 0; + size_t written = 0; + uint8_t *ptr = output; + const char *msg; +#ifdef TRUNNEL_CHECK_ENCODED_LEN + const ssize_t encoded_len = sendme_cell_encoded_len(obj); +#endif + + uint8_t *backptr_data_len = NULL; + + if (NULL != (msg = sendme_cell_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 version IN [0, 1] */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->version)); + written += 1; ptr += 1; + + /* Encode u16 data_len */ + backptr_data_len = ptr; + trunnel_assert(written <= avail); + if (avail - written < 2) + goto truncated; + trunnel_set_uint16(ptr, trunnel_htons(obj->data_len)); + written += 2; ptr += 2; + { + size_t written_before_union = written; + + /* Encode union data[version] */ + trunnel_assert(written <= avail); + switch (obj->version) { + + case 0: + break; + + case 1: + + /* Encode u8 data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN] */ + trunnel_assert(written <= avail); + if (avail - written < TRUNNEL_SENDME_V1_DIGEST_LEN) + goto truncated; + memcpy(ptr, obj->data_v1_digest, TRUNNEL_SENDME_V1_DIGEST_LEN); + written += TRUNNEL_SENDME_V1_DIGEST_LEN; ptr += TRUNNEL_SENDME_V1_DIGEST_LEN; + break; + + default: + trunnel_assert(0); + break; + } + /* Write the length field back to data_len */ + trunnel_assert(written >= written_before_union); +#if UINT16_MAX < SIZE_MAX + if (written - written_before_union > UINT16_MAX) + goto check_failed; +#endif + trunnel_set_uint16(backptr_data_len, trunnel_htons(written - written_before_union)); + } + + + trunnel_assert(ptr == output + written); +#ifdef TRUNNEL_CHECK_ENCODED_LEN + { + trunnel_assert(encoded_len >= 0); + trunnel_assert((size_t)encoded_len == written); + } + +#endif + + return written; + + truncated: + result = -2; + goto fail; + check_failed: + (void)msg; + result = -1; + goto fail; + fail: + trunnel_assert(result < 0); + return result; +} + +/** As sendme_cell_parse(), but do not allocate the output object. + */ +static ssize_t +sendme_cell_parse_into(sendme_cell_t *obj, const uint8_t *input, const size_t len_in) +{ + const uint8_t *ptr = input; + size_t remaining = len_in; + ssize_t result = 0; + (void)result; + + /* Parse u8 version IN [0, 1] */ + CHECK_REMAINING(1, truncated); + obj->version = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->version == 0 || obj->version == 1)) + goto fail; + + /* Parse u16 data_len */ + CHECK_REMAINING(2, truncated); + obj->data_len = trunnel_ntohs(trunnel_get_uint16(ptr)); + remaining -= 2; ptr += 2; + { + size_t remaining_after; + CHECK_REMAINING(obj->data_len, truncated); + remaining_after = remaining - obj->data_len; + remaining = obj->data_len; + + /* Parse union data[version] */ + switch (obj->version) { + + case 0: + /* Skip to end of union */ + ptr += remaining; remaining = 0; + break; + + case 1: + + /* Parse u8 data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN] */ + CHECK_REMAINING(TRUNNEL_SENDME_V1_DIGEST_LEN, fail); + memcpy(obj->data_v1_digest, ptr, TRUNNEL_SENDME_V1_DIGEST_LEN); + remaining -= TRUNNEL_SENDME_V1_DIGEST_LEN; ptr += TRUNNEL_SENDME_V1_DIGEST_LEN; + break; + + default: + goto fail; + break; + } + if (remaining != 0) + goto fail; + remaining = remaining_after; + } + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + fail: + result = -1; + return result; +} + +ssize_t +sendme_cell_parse(sendme_cell_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = sendme_cell_new(); + if (NULL == *output) + return -1; + result = sendme_cell_parse_into(*output, input, len_in); + if (result < 0) { + sendme_cell_free(*output); + *output = NULL; + } + return result; +} diff --git a/src/trunnel/sendme_cell.h b/src/trunnel/sendme_cell.h new file mode 100644 index 0000000000..45efb9f10d --- /dev/null +++ b/src/trunnel/sendme_cell.h @@ -0,0 +1,101 @@ +/* sendme_cell.h -- generated by Trunnel v1.5.3. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#ifndef TRUNNEL_SENDME_CELL_H +#define TRUNNEL_SENDME_CELL_H + +#include +#include "trunnel.h" + +#define TRUNNEL_SENDME_V1_DIGEST_LEN 20 +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_SENDME_CELL) +struct sendme_cell_st { + uint8_t version; + uint16_t data_len; + uint8_t data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN]; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct sendme_cell_st sendme_cell_t; +/** Return a newly allocated sendme_cell with all elements set to + * zero. + */ +sendme_cell_t *sendme_cell_new(void); +/** Release all storage held by the sendme_cell in 'victim'. (Do + * nothing if 'victim' is NULL.) + */ +void sendme_cell_free(sendme_cell_t *victim); +/** Try to parse a sendme_cell from the buffer in 'input', using up to + * 'len_in' bytes from the input buffer. On success, return the number + * of bytes consumed and set *output to the newly allocated + * sendme_cell_t. On failure, return -2 if the input appears + * truncated, and -1 if the input is otherwise invalid. + */ +ssize_t sendme_cell_parse(sendme_cell_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * sendme_cell in 'obj'. On failure, return a negative value. Note + * that this value may be an overestimate, and can even be an + * underestimate for certain unencodeable objects. + */ +ssize_t sendme_cell_encoded_len(const sendme_cell_t *obj); +/** Try to encode the sendme_cell from 'input' into the buffer at + * 'output', using up to 'avail' bytes of the output buffer. On + * success, return the number of bytes used. On failure, return -2 if + * the buffer was not long enough, and -1 if the input was invalid. + */ +ssize_t sendme_cell_encode(uint8_t *output, size_t avail, const sendme_cell_t *input); +/** Check whether the internal state of the sendme_cell in 'obj' is + * consistent. Return NULL if it is, and a short message if it is not. + */ +const char *sendme_cell_check(const sendme_cell_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int sendme_cell_clear_errors(sendme_cell_t *obj); +/** Return the value of the version field of the sendme_cell_t in + * 'inp' + */ +uint8_t sendme_cell_get_version(const sendme_cell_t *inp); +/** Set the value of the version field of the sendme_cell_t in 'inp' + * to 'val'. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int sendme_cell_set_version(sendme_cell_t *inp, uint8_t val); +/** Return the value of the data_len field of the sendme_cell_t in + * 'inp' + */ +uint16_t sendme_cell_get_data_len(const sendme_cell_t *inp); +/** Set the value of the data_len field of the sendme_cell_t in 'inp' + * to 'val'. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int sendme_cell_set_data_len(sendme_cell_t *inp, uint16_t val); +/** Return the (constant) length of the array holding the + * data_v1_digest field of the sendme_cell_t in 'inp'. + */ +size_t sendme_cell_getlen_data_v1_digest(const sendme_cell_t *inp); +/** Return the element at position 'idx' of the fixed array field + * data_v1_digest of the sendme_cell_t in 'inp'. + */ +uint8_t sendme_cell_get_data_v1_digest(sendme_cell_t *inp, size_t idx); +/** As sendme_cell_get_data_v1_digest, but take and return a const + * pointer + */ +uint8_t sendme_cell_getconst_data_v1_digest(const sendme_cell_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * data_v1_digest of the sendme_cell_t in 'inp', so that it will hold + * the value 'elt'. + */ +int sendme_cell_set_data_v1_digest(sendme_cell_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the TRUNNEL_SENDME_V1_DIGEST_LEN-element array + * field data_v1_digest of 'inp'. + */ +uint8_t * sendme_cell_getarray_data_v1_digest(sendme_cell_t *inp); +/** As sendme_cell_get_data_v1_digest, but take and return a const + * pointer + */ +const uint8_t * sendme_cell_getconstarray_data_v1_digest(const sendme_cell_t *inp); + + +#endif diff --git a/src/trunnel/sendme_cell.trunnel b/src/trunnel/sendme_cell.trunnel new file mode 100644 index 0000000000..300963e679 --- /dev/null +++ b/src/trunnel/sendme_cell.trunnel @@ -0,0 +1,19 @@ +/* This file contains the SENDME cell definition. */ + +/* v1 digest length in bytes. */ +const TRUNNEL_SENDME_V1_DIGEST_LEN = 20; + +/* SENDME cell declaration. */ +struct sendme_cell { + /* Version field. */ + u8 version IN [0x00, 0x01]; + + /* Length of data contained in this cell. */ + u16 data_len; + + /* The data content depends on the version. */ + union data[version] with length data_len { + 0x00: ignore; + 0x01: u8 v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN]; + }; +} diff --git a/src/trunnel/socks5.c b/src/trunnel/socks5.c index 057a52b042..f32862e353 100644 --- a/src/trunnel/socks5.c +++ b/src/trunnel/socks5.c @@ -1,4 +1,4 @@ -/* socks5.c -- generated by Trunnel v1.5.2. +/* socks5.c -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ diff --git a/src/trunnel/socks5.h b/src/trunnel/socks5.h index d3bea152e7..23ac64faba 100644 --- a/src/trunnel/socks5.h +++ b/src/trunnel/socks5.h @@ -1,4 +1,4 @@ -/* socks5.h -- generated by Trunnel v1.5.2. +/* socks5.h -- generated by Trunnel v1.5.3. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ -- cgit v1.2.3-54-g00ecf From 5068ccab0b1849e836729c43a2ca891139cf107b Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 29 May 2019 09:23:13 -0400 Subject: Add a changes file for ticket 30686. --- changes/ticket30686 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/ticket30686 (limited to 'changes') diff --git a/changes/ticket30686 b/changes/ticket30686 new file mode 100644 index 0000000000..36473c1a02 --- /dev/null +++ b/changes/ticket30686 @@ -0,0 +1,5 @@ + o Minor features (logging): + - Give a more useful assertion failure message if we think we have + minherit() but we fail to make a region non-inheritable. Give a + compile-time warning if our support for minherit() is + incomplete. Closes ticket 30686. -- cgit v1.2.3-54-g00ecf From 5f5f6bb8fb68d171a39eb1e5c6e6649087ec551d Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Wed, 22 May 2019 16:33:04 -0500 Subject: Add changes file for 29976 --- changes/ticket29976 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket29976 (limited to 'changes') diff --git a/changes/ticket29976 b/changes/ticket29976 new file mode 100644 index 0000000000..9991bfb1ff --- /dev/null +++ b/changes/ticket29976 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Rework bootstrap tracking to use the new publish-subscribe + subsystem. Closes ticket 29976. -- cgit v1.2.3-54-g00ecf From e218da17229adcec3c0a4ce774c0963bfcf1f11e Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 14 Jun 2019 11:44:26 +1000 Subject: make: Improve the documentation for test-network-all "make test-network-all" shows the warnings from each test-network.sh run on the console, so developers see new warnings early. Improve the documentation for this feature, and rename a Makefile variable so the code is self-documenting. Fixes bug 30455; bugfix on 0.3.0.4-rc. --- Makefile.am | 19 +++++++++++-------- changes/bug30455 | 5 +++++ 2 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 changes/bug30455 (limited to 'changes') diff --git a/Makefile.am b/Makefile.am index 7a0d40d6a5..333fcf2e0a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -185,7 +185,7 @@ TEST_CFLAGS= TEST_CPPFLAGS=-DTOR_UNIT_TESTS @TOR_MODULES_ALL_ENABLED@ TEST_NETWORK_FLAGS=--hs-multi-client 1 endif -TEST_NETWORK_WARNING_FLAGS=--quiet --only-warnings +TEST_NETWORK_SHOW_WARNINGS_FOR_LAST_RUN_FLAGS=--quiet --only-warnings if LIBFUZZER_ENABLED TEST_CFLAGS += -fsanitize-coverage=trace-pc-guard,trace-cmp,trace-div @@ -250,12 +250,15 @@ test-network: need-chutney-path $(TESTING_TOR_BINARY) src/tools/tor-gencert $(top_srcdir)/src/test/test-network.sh $(TEST_NETWORK_FLAGS) # Run all available tests using automake's test-driver -# only run IPv6 tests if we can ping6 ::1 (localhost) -# only run IPv6 tests if we can ping ::1 (localhost) -# some IPv6 tests will fail without an IPv6 DNS server (see #16971 and #17011) -# only run mixed tests if we have a tor-stable binary -# Try the syntax for BSD ping6, Linux ping6, and Linux ping -6, -# because they're incompatible +# - only run IPv6 tests if we can ping6 or ping -6 ::1 (localhost) +# we try the syntax for BSD ping6, Linux ping6, and Linux ping -6, +# because they're incompatible +# - some IPv6 tests may fail without an IPv6 DNS server +# (see #16971 and #17011) +# - only run mixed tests if we have a tor-stable binary +# - show tor warnings on the console after each network run +# (otherwise, warnings go to the logs, and people don't see them unless +# there is a network failure) test-network-all: need-chutney-path test-driver $(TESTING_TOR_BINARY) src/tools/tor-gencert mkdir -p $(TEST_NETWORK_ALL_LOG_DIR) rm -f $(TEST_NETWORK_ALL_LOG_DIR)/*.log $(TEST_NETWORK_ALL_LOG_DIR)/*.trs @@ -279,7 +282,7 @@ test-network-all: need-chutney-path test-driver $(TESTING_TOR_BINARY) src/tools/ done; \ for f in $$flavors; do \ $(SHELL) $(top_srcdir)/test-driver --test-name $$f --log-file $(TEST_NETWORK_ALL_LOG_DIR)/$$f.log --trs-file $(TEST_NETWORK_ALL_LOG_DIR)/$$f.trs $(TEST_NETWORK_ALL_DRIVER_FLAGS) $(top_srcdir)/src/test/test-network.sh --flavor $$f $(TEST_NETWORK_FLAGS); \ - $(top_srcdir)/src/test/test-network.sh $(TEST_NETWORK_WARNING_FLAGS); \ + $(top_srcdir)/src/test/test-network.sh $(TEST_NETWORK_SHOW_WARNINGS_FOR_LAST_RUN_FLAGS); \ done; \ echo "Log and result files are available in $(TEST_NETWORK_ALL_LOG_DIR)."; \ ! grep -q FAIL $(TEST_NETWORK_ALL_LOG_DIR)/*.trs diff --git a/changes/bug30455 b/changes/bug30455 new file mode 100644 index 0000000000..aecbde5a33 --- /dev/null +++ b/changes/bug30455 @@ -0,0 +1,5 @@ + o Minor bugfixes (chutney, makefiles, documentation): + - "make test-network-all" shows the warnings from each test-network.sh + run on the console, so developers see new warnings early. Improve the + documentation for this feature, and rename a Makefile variable so the + code is self-documenting. Fixes bug 30455; bugfix on 0.3.0.4-rc. -- cgit v1.2.3-54-g00ecf From 990b434c4f4aa5e9c410bb083c1b98cead92bb59 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 7 Jun 2019 20:03:26 -0400 Subject: Make evloop into a subsystem. Note that the event base object is _not_ created from the initialize function, since it is configuration-dependent. This will wait until configuration is integrated into subsystems. Closes ticket 30806. --- changes/ticket30806 | 3 +++ src/app/main/main.c | 4 ---- src/app/main/shutdown.c | 2 -- src/app/main/subsystem_list.c | 3 +++ src/lib/evloop/.may_include | 1 + src/lib/evloop/evloop_sys.c | 49 +++++++++++++++++++++++++++++++++++++++++ src/lib/evloop/evloop_sys.h | 17 ++++++++++++++ src/lib/evloop/include.am | 2 ++ src/test/test_channelpadding.c | 7 ------ src/test/test_compat_libevent.c | 2 -- 10 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 changes/ticket30806 create mode 100644 src/lib/evloop/evloop_sys.c create mode 100644 src/lib/evloop/evloop_sys.h (limited to 'changes') diff --git a/changes/ticket30806 b/changes/ticket30806 new file mode 100644 index 0000000000..4f09ea2af3 --- /dev/null +++ b/changes/ticket30806 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Use the subsystems mechanism to manage the main event loop code. + Closes ticket 30806. diff --git a/src/app/main/main.c b/src/app/main/main.c index 6e325f0b10..17b0000d98 100644 --- a/src/app/main/main.c +++ b/src/app/main/main.c @@ -653,10 +653,6 @@ tor_init(int argc, char *argv[]) return -1; } - if (tor_init_libevent_rng() < 0) { - log_warn(LD_NET, "Problem initializing libevent RNG."); - } - /* Scan/clean unparseable descriptors; after reading config */ routerparse_init(); diff --git a/src/app/main/shutdown.c b/src/app/main/shutdown.c index cc0091a9ab..93d6351d1b 100644 --- a/src/app/main/shutdown.c +++ b/src/app/main/shutdown.c @@ -160,8 +160,6 @@ tor_free_all(int postfork) subsystems_shutdown(); - tor_libevent_free_all(); - /* Stuff in util.c and address.c*/ if (!postfork) { esc_router_info(NULL); diff --git a/src/app/main/subsystem_list.c b/src/app/main/subsystem_list.c index f595796232..95d96f78d2 100644 --- a/src/app/main/subsystem_list.c +++ b/src/app/main/subsystem_list.c @@ -25,6 +25,7 @@ #include "lib/time/time_sys.h" #include "lib/tls/tortls_sys.h" #include "lib/wallclock/wallclock_sys.h" +#include "lib/evloop/evloop_sys.h" #include "feature/dirauth/dirauth_sys.h" @@ -50,6 +51,8 @@ const subsys_fns_t *tor_subsystems[] = { &sys_ocirc_event, /* -32 */ &sys_btrack, /* -30 */ + &sys_evloop, /* -20 */ + &sys_mainloop, /* 5 */ &sys_or, /* 20 */ diff --git a/src/lib/evloop/.may_include b/src/lib/evloop/.may_include index 273de7bb94..54aa75fbff 100644 --- a/src/lib/evloop/.may_include +++ b/src/lib/evloop/.may_include @@ -8,6 +8,7 @@ lib/log/*.h lib/malloc/*.h lib/net/*.h lib/string/*.h +lib/subsys/*.h lib/testsupport/*.h lib/thread/*.h lib/time/*.h diff --git a/src/lib/evloop/evloop_sys.c b/src/lib/evloop/evloop_sys.c new file mode 100644 index 0000000000..56641a3175 --- /dev/null +++ b/src/lib/evloop/evloop_sys.c @@ -0,0 +1,49 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file evloop_sys.c + * @brief Subsystem definition for the event loop module + **/ + +#include "orconfig.h" +#include "lib/subsys/subsys.h" +#include "lib/evloop/compat_libevent.h" +#include "lib/evloop/evloop_sys.h" +#include "lib/log/log.h" + +static int +subsys_evloop_initialize(void) +{ + if (tor_init_libevent_rng() < 0) { + log_warn(LD_NET, "Problem initializing libevent RNG."); + return -1; + } + return 0; +} + +static void +subsys_evloop_postfork(void) +{ +#ifdef TOR_UNIT_TESTS + tor_libevent_postfork(); +#endif +} + +static void +subsys_evloop_shutdown(void) +{ + tor_libevent_free_all(); +} + +const struct subsys_fns_t sys_evloop = { + .name = "evloop", + .supported = true, + .level = -20, + .initialize = subsys_evloop_initialize, + .shutdown = subsys_evloop_shutdown, + .postfork = subsys_evloop_postfork, +}; diff --git a/src/lib/evloop/evloop_sys.h b/src/lib/evloop/evloop_sys.h new file mode 100644 index 0000000000..e6155c25b0 --- /dev/null +++ b/src/lib/evloop/evloop_sys.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file evloop_sys.h + * @brief Declare subsystem object for the event loop module. + **/ + +#ifndef TOR_LIB_EVLOOP_EVLOOP_SYS_H +#define TOR_LIB_EVLOOP_EVLOOP_SYS_H + +extern const struct subsys_fns_t sys_evloop; + +#endif /* !defined(TOR_LIB_EVLOOP_EVLOOP_SYS_H) */ diff --git a/src/lib/evloop/include.am b/src/lib/evloop/include.am index 6595b3a34b..41cd2f45c5 100644 --- a/src/lib/evloop/include.am +++ b/src/lib/evloop/include.am @@ -8,6 +8,7 @@ endif # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_evloop_a_SOURCES = \ src/lib/evloop/compat_libevent.c \ + src/lib/evloop/evloop_sys.c \ src/lib/evloop/procmon.c \ src/lib/evloop/timers.c \ src/lib/evloop/token_bucket.c \ @@ -21,6 +22,7 @@ src_lib_libtor_evloop_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/evloop/compat_libevent.h \ + src/lib/evloop/evloop_sys.h \ src/lib/evloop/procmon.h \ src/lib/evloop/timers.h \ src/lib/evloop/token_bucket.h \ diff --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c index 5d012e462b..885246628e 100644 --- a/src/test/test_channelpadding.c +++ b/src/test/test_channelpadding.c @@ -289,8 +289,6 @@ test_channelpadding_timers(void *arg) channel_t *chans[CHANNELS_TO_TEST]; (void)arg; - tor_libevent_postfork(); - if (!connection_array) connection_array = smartlist_new(); @@ -393,7 +391,6 @@ test_channelpadding_killonehop(void *arg) channelpadding_decision_t decision; int64_t new_time; (void)arg; - tor_libevent_postfork(); routerstatus_t *relay = tor_malloc_zero(sizeof(routerstatus_t)); monotime_init(); @@ -502,8 +499,6 @@ test_channelpadding_consensus(void *arg) int64_t new_time; (void)arg; - tor_libevent_postfork(); - /* * Params tested: * nf_pad_before_usage @@ -898,8 +893,6 @@ test_channelpadding_decide_to_pad_channel(void *arg) connection_array = smartlist_new(); (void)arg; - tor_libevent_postfork(); - monotime_init(); monotime_enable_test_mocking(); monotime_set_mock_time_nsec(1); diff --git a/src/test/test_compat_libevent.c b/src/test/test_compat_libevent.c index 5d625483da..ecd97e3474 100644 --- a/src/test/test_compat_libevent.c +++ b/src/test/test_compat_libevent.c @@ -151,8 +151,6 @@ test_compat_libevent_postloop_events(void *arg) mainloop_event_t *a = NULL, *b = NULL; periodic_timer_t *timed = NULL; - tor_libevent_postfork(); - /* If postloop events don't work, then these events will activate one * another ad infinitum and, and the periodic event will never occur. */ b = mainloop_event_postloop_new(activate_event_cb, &a); -- cgit v1.2.3-54-g00ecf From 4613159c61549a4901690da5ecd5101eb6a20736 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 15 Jun 2019 16:19:25 -0400 Subject: Changes file for ticket 30893 (confparse testing) --- changes/ticket30893 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket30893 (limited to 'changes') diff --git a/changes/ticket30893 b/changes/ticket30893 new file mode 100644 index 0000000000..e1b56d2182 --- /dev/null +++ b/changes/ticket30893 @@ -0,0 +1,3 @@ + o Minor features (testing)P: + - Improve test coverage for our existing configuration parsing and + management API. Closes ticket 30893. -- cgit v1.2.3-54-g00ecf From 66a15013fa5abf3c4d3345ca29c22ad13d45e22f Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sun, 16 Jun 2019 20:18:30 +0300 Subject: Allow excluding documentation from the build --- changes/ticket19381 | 4 ++++ configure.ac | 8 ++++++++ doc/include.am | 23 +++++++++++++++++++---- 3 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 changes/ticket19381 (limited to 'changes') diff --git a/changes/ticket19381 b/changes/ticket19381 new file mode 100644 index 0000000000..ee51e2a3e2 --- /dev/null +++ b/changes/ticket19381 @@ -0,0 +1,4 @@ + o Minor features (build system): + - Add --disable-manpage and --disable-html-manual options to configure + script. This will enable shortening build times by not building + documentation. Resolves issue 19381. diff --git a/configure.ac b/configure.ac index 75ca03d7d8..9ec123f51e 100644 --- a/configure.ac +++ b/configure.ac @@ -105,6 +105,12 @@ if test "$enable_memory_sentinels" = "no"; then [Defined if we're turning off memory safety code to look for bugs]) fi +AC_ARG_ENABLE(manpage, + AS_HELP_STRING(--disable-manpage, [Disable manpage generation.])) + +AC_ARG_ENABLE(html-manual, + AS_HELP_STRING(--disable-html-manual, [Disable HTML documentation.])) + AC_ARG_ENABLE(asciidoc, AS_HELP_STRING(--disable-asciidoc, [don't use asciidoc (disables building of manpages)]), [case "${enableval}" in @@ -299,6 +305,8 @@ AC_PATH_PROG([ASCIIDOC], [asciidoc], none) AC_PATH_PROGS([A2X], [a2x a2x.py], none) AM_CONDITIONAL(USE_ASCIIDOC, test "x$asciidoc" = "xtrue") +AM_CONDITIONAL(BUILD_MANPAGE, [test "x$enable_manpage" != "xno"]) +AM_CONDITIONAL(BUILD_HTML_DOCS, [test "x$enable_html_manual" != "xno"]) AM_PROG_CC_C_O AC_PROG_CC_C99 diff --git a/doc/include.am b/doc/include.am index 0a123aae11..a9d3fa1c98 100644 --- a/doc/include.am +++ b/doc/include.am @@ -15,17 +15,32 @@ 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) -doc_DATA = $(all_mans:=.html) +txt_in = $(all_mans:=.1.txt) + +if BUILD_HTML_DOCS html_in = $(all_mans:=.html.in) +doc_DATA = $(all_mans:=.html) +else +html_in = +doc_DATA = +endif + +if BUILD_MANPAGE +nodist_man1_MANS = $(all_mans:=.1) man_in = $(all_mans:=.1.in) -txt_in = $(all_mans:=.1.txt) else +nodist_man1_MANS = +man_in = +endif + +else + html_in = +doc_DATA = man_in = txt_in = nodist_man1_MANS = -doc_DATA = + endif EXTRA_DIST+= doc/asciidoc-helper.sh \ -- cgit v1.2.3-54-g00ecf From 86478be50f4364025310d2846d16d09c15962387 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sun, 9 Jun 2019 18:23:05 +0300 Subject: Add changes file --- changes/ticket29533 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket29533 (limited to 'changes') diff --git a/changes/ticket29533 b/changes/ticket29533 new file mode 100644 index 0000000000..27ef681218 --- /dev/null +++ b/changes/ticket29533 @@ -0,0 +1,3 @@ + o Testing: + - Run shellcheck for all non-third-party shell scripts that are shipped + with Tor. Closes ticket 29533. -- cgit v1.2.3-54-g00ecf From 6a0763cd665e50174df5a7ea6ae0a27db7c9945f Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 18 Jun 2019 13:32:45 -0400 Subject: guard: Ignore marked for close circuit when changing state to open When we consider all circuits in "waiting for guard" state to be promoted to an "open" state, we were considering all circuits, even the one marked for close. This ultiamtely triggers a "circuit_has_opened()" called on the circuit that is marked for close which then leads to possible undesirable behaviors within a subsystem. For instance, the HS subsystem would be unable to find the authentication key of the introduction point circuit leading to a BUG() warning and a duplicate mark for close on the circuit. This commit also adds a unit test to make sure we never select marked for close circuits when upgrading its guard state from waiting for guard to open. Fixes #30871 Signed-off-by: David Goulet --- changes/ticket30871 | 6 ++++++ src/feature/client/entrynodes.c | 4 ++++ src/test/test_circuitbuild.c | 47 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 changes/ticket30871 (limited to 'changes') diff --git a/changes/ticket30871 b/changes/ticket30871 new file mode 100644 index 0000000000..81c076bb02 --- /dev/null +++ b/changes/ticket30871 @@ -0,0 +1,6 @@ + o Major bugfixes (circuit build, guard): + - When considering upgrading circuits from "waiting for guard" to "open", + always ignore the ones that are mark for close. Else, we can end up in + the situation where a subsystem is notified of that circuit opening but + still marked for close leading to undesirable behavior. Fixes bug 30871; + bugfix on 0.3.0.1-alpha. diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c index 4afcee2021..54a9238d8f 100644 --- a/src/feature/client/entrynodes.c +++ b/src/feature/client/entrynodes.c @@ -2611,6 +2611,10 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs, entry_guard_t *guard = entry_guard_handle_get(state->guard); if (!guard || guard->in_selection != gs) continue; + if (TO_CIRCUIT(circ)->marked_for_close) { + /* Don't consider any marked for close circuits. */ + continue; + } smartlist_add(all_circuits, circ); } SMARTLIST_FOREACH_END(circ); diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c index 47218a559a..0c23091594 100644 --- a/src/test/test_circuitbuild.c +++ b/src/test/test_circuitbuild.c @@ -4,6 +4,8 @@ /* See LICENSE for licensing information */ #define CIRCUITBUILD_PRIVATE +#define CIRCUITLIST_PRIVATE +#define ENTRYNODES_PRIVATE #include "core/or/or.h" #include "test/test.h" @@ -13,7 +15,11 @@ #include "core/or/circuitbuild.h" #include "core/or/circuitlist.h" +#include "core/or/cpath_build_state_st.h" #include "core/or/extend_info_st.h" +#include "core/or/origin_circuit_st.h" + +#include "feature/client/entrynodes.h" /* Dummy nodes smartlist for testing */ static smartlist_t dummy_nodes; @@ -126,10 +132,51 @@ test_new_route_len_unhandled_exit(void *arg) UNMOCK(count_acceptable_nodes); } +static void +test_upgrade_from_guard_wait(void *arg) +{ + circuit_t *circ = NULL; + origin_circuit_t *orig_circ = NULL; + entry_guard_t *guard = NULL; + smartlist_t *list = NULL; + + (void) arg; + + circ = dummy_origin_circuit_new(0); + orig_circ = TO_ORIGIN_CIRCUIT(circ); + tt_assert(orig_circ); + + orig_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); + + circuit_set_state(circ, CIRCUIT_STATE_GUARD_WAIT); + + /* Put it in guard wait state. */ + guard = tor_malloc_zero(sizeof(*guard)); + guard->in_selection = get_guard_selection_info(); + + orig_circ->guard_state = + circuit_guard_state_new(guard, GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD, + NULL); + + /* Mark the circuit for close. */ + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + tt_int_op(circ->marked_for_close, OP_NE, 0); + + /* We shouldn't pick the mark for close circuit. */ + list = circuit_find_circuits_to_upgrade_from_guard_wait(); + tt_assert(!list); + + done: + circuit_free(circ); + entry_guard_free_(guard); +} + struct testcase_t circuitbuild_tests[] = { { "noexit", test_new_route_len_noexit, 0, NULL, NULL }, { "safe_exit", test_new_route_len_safe_exit, 0, NULL, NULL }, { "unsafe_exit", test_new_route_len_unsafe_exit, 0, NULL, NULL }, { "unhandled_exit", test_new_route_len_unhandled_exit, 0, NULL, NULL }, + { "upgrade_from_guard_wait", test_upgrade_from_guard_wait, TT_FORK, + NULL, NULL }, END_OF_TESTCASES }; -- cgit v1.2.3-54-g00ecf From 16a0b7ed6779bf72a8a471c558a5e09084921d8b Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 18 Jun 2019 13:32:45 -0400 Subject: guard: Ignore marked for close circuit when changing state to open When we consider all circuits in "waiting for guard" state to be promoted to an "open" state, we were considering all circuits, even the one marked for close. This ultiamtely triggers a "circuit_has_opened()" called on the circuit that is marked for close which then leads to possible undesirable behaviors within a subsystem. For instance, the HS subsystem would be unable to find the authentication key of the introduction point circuit leading to a BUG() warning and a duplicate mark for close on the circuit. This commit also adds a unit test to make sure we never select marked for close circuits when upgrading its guard state from waiting for guard to open. Fixes #30871 Signed-off-by: David Goulet --- changes/ticket30871 | 6 ++++++ src/feature/client/entrynodes.c | 4 ++++ src/test/test_circuitbuild.c | 47 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 changes/ticket30871 (limited to 'changes') diff --git a/changes/ticket30871 b/changes/ticket30871 new file mode 100644 index 0000000000..81c076bb02 --- /dev/null +++ b/changes/ticket30871 @@ -0,0 +1,6 @@ + o Major bugfixes (circuit build, guard): + - When considering upgrading circuits from "waiting for guard" to "open", + always ignore the ones that are mark for close. Else, we can end up in + the situation where a subsystem is notified of that circuit opening but + still marked for close leading to undesirable behavior. Fixes bug 30871; + bugfix on 0.3.0.1-alpha. diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c index 4afcee2021..54a9238d8f 100644 --- a/src/feature/client/entrynodes.c +++ b/src/feature/client/entrynodes.c @@ -2611,6 +2611,10 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs, entry_guard_t *guard = entry_guard_handle_get(state->guard); if (!guard || guard->in_selection != gs) continue; + if (TO_CIRCUIT(circ)->marked_for_close) { + /* Don't consider any marked for close circuits. */ + continue; + } smartlist_add(all_circuits, circ); } SMARTLIST_FOREACH_END(circ); diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c index 47218a559a..196d8cd355 100644 --- a/src/test/test_circuitbuild.c +++ b/src/test/test_circuitbuild.c @@ -4,6 +4,8 @@ /* See LICENSE for licensing information */ #define CIRCUITBUILD_PRIVATE +#define CIRCUITLIST_PRIVATE +#define ENTRYNODES_PRIVATE #include "core/or/or.h" #include "test/test.h" @@ -13,7 +15,11 @@ #include "core/or/circuitbuild.h" #include "core/or/circuitlist.h" +#include "core/or/cpath_build_state_st.h" #include "core/or/extend_info_st.h" +#include "core/or/origin_circuit_st.h" + +#include "feature/client/entrynodes.h" /* Dummy nodes smartlist for testing */ static smartlist_t dummy_nodes; @@ -126,10 +132,51 @@ test_new_route_len_unhandled_exit(void *arg) UNMOCK(count_acceptable_nodes); } +static void +test_upgrade_from_guard_wait(void *arg) +{ + circuit_t *circ = NULL; + origin_circuit_t *orig_circ = NULL; + entry_guard_t *guard = NULL; + smartlist_t *list = NULL; + + (void) arg; + + circ = dummy_origin_circuit_new(0); + orig_circ = TO_ORIGIN_CIRCUIT(circ); + tt_assert(orig_circ); + + orig_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); + + circuit_set_state(circ, CIRCUIT_STATE_GUARD_WAIT); + + /* Put it in guard wait state. */ + guard = tor_malloc_zero(sizeof(*guard)); + guard->in_selection = get_guard_selection_info(); + + orig_circ->guard_state = + circuit_guard_state_new(guard, GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD, + NULL); + + /* Mark the circuit for close. */ + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + tt_int_op(circ->marked_for_close, OP_NE, 0); + + /* We shouldn't pick the mark for close circuit. */ + list = circuit_find_circuits_to_upgrade_from_guard_wait(); + tt_assert(!list); + + done: + circuit_free(circ); + entry_guard_free_(guard); +} + struct testcase_t circuitbuild_tests[] = { { "noexit", test_new_route_len_noexit, 0, NULL, NULL }, { "safe_exit", test_new_route_len_safe_exit, 0, NULL, NULL }, { "unsafe_exit", test_new_route_len_unsafe_exit, 0, NULL, NULL }, { "unhandled_exit", test_new_route_len_unhandled_exit, 0, NULL, NULL }, + { "upgrade_from_guard_wait", test_upgrade_from_guard_wait, TT_FORK, + &helper_pubsub_setup, NULL }, END_OF_TESTCASES }; -- cgit v1.2.3-54-g00ecf From 91c7d395cf7c62f8ccf3261132cb5d71972f79ae Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 19 Jun 2019 07:50:02 -0400 Subject: changes: Fix typo in changes/ticket30893 Signed-off-by: David Goulet --- changes/ticket30893 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'changes') diff --git a/changes/ticket30893 b/changes/ticket30893 index e1b56d2182..638b99a9f7 100644 --- a/changes/ticket30893 +++ b/changes/ticket30893 @@ -1,3 +1,3 @@ - o Minor features (testing)P: + o Minor features (testing): - Improve test coverage for our existing configuration parsing and management API. Closes ticket 30893. -- cgit v1.2.3-54-g00ecf From 87511766873fd22ebeff1bc9dcfa78773a890083 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 19 Jun 2019 09:22:07 -0400 Subject: hs-v3: Close intro circuits when cleaning client cache Fixes #30921 Signed-off-by: David Goulet --- changes/ticket30921 | 5 +++ src/feature/hs/hs_cache.c | 5 +++ src/test/test_hs_client.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 changes/ticket30921 (limited to 'changes') diff --git a/changes/ticket30921 b/changes/ticket30921 new file mode 100644 index 0000000000..50ec570ffe --- /dev/null +++ b/changes/ticket30921 @@ -0,0 +1,5 @@ + o Minor bugfixes (onion service v3): + - When purging the client descriptor cache, always also close any + introduction point circuits associated with it. This avoids picking those + when connecting to them later while not having the descriptor to complete + the introduction. Fixes bug 30921; bugfix on 0.3.2.1-alpha. diff --git a/src/feature/hs/hs_cache.c b/src/feature/hs/hs_cache.c index 05f9940ae6..9817113b23 100644 --- a/src/feature/hs/hs_cache.c +++ b/src/feature/hs/hs_cache.c @@ -710,6 +710,11 @@ cache_clean_v3_as_client(time_t now) MAP_DEL_CURRENT(key); entry_size = cache_get_client_entry_size(entry); bytes_removed += entry_size; + /* We just removed an old descriptor. We need to close all intro circuits + * so we don't have leftovers that can be selected while lacking a + * descriptor. We leave the rendezvous circuits opened because they could + * be in use. */ + hs_client_close_intro_circuits_from_desc(entry->desc); /* Entry is not in the cache anymore, destroy it. */ cache_client_desc_free(entry); /* Update our OOM. We didn't use the remove() function because we are in diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c index 0d25a98bb3..fb497d52a1 100644 --- a/src/test/test_hs_client.c +++ b/src/test/test_hs_client.c @@ -37,6 +37,7 @@ #include "feature/hs/hs_config.h" #include "feature/hs/hs_ident.h" #include "feature/hs/hs_cache.h" +#include "feature/rend/rendcache.h" #include "core/or/circuitlist.h" #include "core/or/circuitbuild.h" #include "core/mainloop/connection.h" @@ -1007,6 +1008,92 @@ test_close_intro_circuits_new_desc(void *arg) UNMOCK(networkstatus_get_live_consensus); } +static void +test_close_intro_circuits_cache_clean(void *arg) +{ + int ret; + ed25519_keypair_t service_kp; + circuit_t *circ = NULL; + origin_circuit_t *ocirc = NULL; + hs_descriptor_t *desc1 = NULL; + + (void) arg; + + hs_init(); + rend_cache_init(); + + /* This is needed because of the client cache expiration timestamp is based + * on having a consensus. See cached_client_descriptor_has_expired(). */ + MOCK(networkstatus_get_live_consensus, + mock_networkstatus_get_live_consensus); + + /* Set consensus time */ + parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", + &mock_ns.valid_after); + parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", + &mock_ns.fresh_until); + parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC", + &mock_ns.valid_until); + + /* Generate service keypair */ + tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0)); + + /* Create and add to the global list a dummy client introduction circuits. + * We'll then make sure the hs_ident is attached to a dummy descriptor. */ + circ = dummy_origin_circuit_new(0); + tt_assert(circ); + circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING; + ocirc = TO_ORIGIN_CIRCUIT(circ); + + /* Build the first descriptor and cache it. */ + { + char *encoded; + desc1 = hs_helper_build_hs_desc_with_ip(&service_kp); + tt_assert(desc1); + ret = hs_desc_encode_descriptor(desc1, &service_kp, NULL, &encoded); + tt_int_op(ret, OP_EQ, 0); + tt_assert(encoded); + + /* Store it */ + ret = hs_cache_store_as_client(encoded, &service_kp.pubkey); + tt_int_op(ret, OP_EQ, 0); + tor_free(encoded); + tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey)); + } + + /* We'll pick one introduction point and associate it with the circuit. */ + { + const hs_desc_intro_point_t *ip = + smartlist_get(desc1->encrypted_data.intro_points, 0); + tt_assert(ip); + ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey, + HS_IDENT_CIRCUIT_INTRO); + ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, + &ip->auth_key_cert->signed_key); + } + + /* Before we are about to clean up the intro circuits, make sure it is + * actually there. */ + tt_assert(circuit_get_next_intro_circ(NULL, true)); + + /* Cleanup the client cache. The ns valid after time is what decides if the + * descriptor has expired so put it in the future enough (72h) so we are + * sure to always expire. */ + mock_ns.valid_after = approx_time() + (72 * 24 * 60 * 60); + hs_cache_clean_as_client(0); + + /* Once stored, our intro circuit should be closed because it is related to + * an old introduction point that doesn't exists anymore. */ + tt_assert(!circuit_get_next_intro_circ(NULL, true)); + + done: + circuit_free(circ); + hs_descriptor_free(desc1); + hs_free_all(); + rend_cache_free_all(); + UNMOCK(networkstatus_get_live_consensus); +} + struct testcase_t hs_client_tests[] = { { "e2e_rend_circuit_setup_legacy", test_e2e_rend_circuit_setup_legacy, TT_FORK, NULL, NULL }, @@ -1026,6 +1113,8 @@ struct testcase_t hs_client_tests[] = { TT_FORK, NULL, NULL }, { "close_intro_circuits_new_desc", test_close_intro_circuits_new_desc, TT_FORK, NULL, NULL }, + { "close_intro_circuits_cache_clean", test_close_intro_circuits_cache_clean, + TT_FORK, NULL, NULL }, END_OF_TESTCASES }; -- cgit v1.2.3-54-g00ecf From f2b1eb1f052c99e0be096b98888e9854cf57a64c Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 19 Jun 2019 11:09:14 -0400 Subject: hs: Disallow single hop client circuit when introducing This will effectively also deny any bridge to be used as a single hop to the introduction point since bridge do not authenticate like clients. Fixes #24963 Signed-off-by: David Goulet --- changes/ticket24963 | 5 +++++ src/feature/hs/hs_intropoint.c | 9 +++++++++ 2 files changed, 14 insertions(+) create mode 100644 changes/ticket24963 (limited to 'changes') diff --git a/changes/ticket24963 b/changes/ticket24963 new file mode 100644 index 0000000000..50adcfaaf4 --- /dev/null +++ b/changes/ticket24963 @@ -0,0 +1,5 @@ + o Minor feature (onion service): + - Disallow single hop clients to introduce directly at the introduction + point. We've removed Tor2web a while back and rendezvous are blocked at + the relays. This is to remove load off the network from spammy clients. + Close ticket 24963. diff --git a/src/feature/hs/hs_intropoint.c b/src/feature/hs/hs_intropoint.c index 9333060e7e..447f73b602 100644 --- a/src/feature/hs/hs_intropoint.c +++ b/src/feature/hs/hs_intropoint.c @@ -10,6 +10,7 @@ #include "core/or/or.h" #include "app/config/config.h" +#include "core/or/channel.h" #include "core/or/circuitlist.h" #include "core/or/circuituse.h" #include "core/or/relay.h" @@ -546,6 +547,14 @@ circuit_is_suitable_for_introduce1(const or_circuit_t *circ) return 0; } + /* Disallow single hop client circuit. */ + if (channel_is_client(circ->p_chan)) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Single hop client was rejected while trying to introduce. " + "Closing circuit."); + return 0; + } + return 1; } -- cgit v1.2.3-54-g00ecf From 1d504a408d129bf561138360a5d727b37c0e29a9 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Sun, 23 Jun 2019 13:38:49 +0300 Subject: Add changes file --- changes/ticket30102 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket30102 (limited to 'changes') diff --git a/changes/ticket30102 b/changes/ticket30102 new file mode 100644 index 0000000000..c8b1148da3 --- /dev/null +++ b/changes/ticket30102 @@ -0,0 +1,4 @@ + o Minor features (continuous integration): + - When running CI builds on Travis, put some random data in ~/.torrc, + to make sure no tests are dependent on default Tor configuration. + Resolves issue 30102. -- cgit v1.2.3-54-g00ecf From 8356cc5b514a5d6a0170927d7c3730e2e1164298 Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 24 Jun 2019 19:44:24 +1000 Subject: stats: Always publish pluggable transports in extra info documents Always publish bridge pluggable transport information in the extra info descriptor, even if ExtraInfoStatistics is 0. This information is needed by BridgeDB. Fixes bug 30956; bugfix on 0.4.1.1-alpha. --- changes/bug30956 | 4 ++++ doc/tor.1.txt | 6 ++++-- src/feature/relay/router.c | 17 +++++++++++------ 3 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 changes/bug30956 (limited to 'changes') diff --git a/changes/bug30956 b/changes/bug30956 new file mode 100644 index 0000000000..8f52a81de3 --- /dev/null +++ b/changes/bug30956 @@ -0,0 +1,4 @@ + o Minor bugfixes (pluggable transports): + - Always publish bridge pluggable transport information in the extra info + descriptor, even if ExtraInfoStatistics is 0. This information is + needed by BridgeDB. Fixes bug 30956; bugfix on 0.4.1.1-alpha. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 4bd365c774..95d56c6dbd 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -2451,8 +2451,10 @@ is non-zero): [[ExtraInfoStatistics]] **ExtraInfoStatistics** **0**|**1**:: When this option is enabled, Tor includes previously gathered statistics in its extra-info documents that it uploads to the directory authorities. - Disabling this option also disables bandwidth usage statistics, GeoIPFile - hashes, and ServerTransportPlugin lists in the extra-info file. + Disabling this option also removes bandwidth usage statistics, and + GeoIPFile and GeoIPv6File hashes from the extra-info file. Bridge + ServerTransportPlugin lines are always includes in the extra-info file, + because they are required by BridgeDB. (Default: 1) [[ExtendAllowPrivateAddresses]] **ExtendAllowPrivateAddresses** **0**|**1**:: diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index e0daf34db2..25bb1835c2 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -3175,6 +3175,15 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, published); smartlist_add(chunks, pre); + /* Add information about the pluggable transports we support, even if we + * are not publishing statistics. This information is needed by BridgeDB + * to distribute bridges. */ + if (options->ServerTransportPlugin) { + char *pluggable_transports = pt_get_extra_info_descriptor_string(); + if (pluggable_transports) + smartlist_add(chunks, pluggable_transports); + } + if (options->ExtraInfoStatistics && write_stats_to_extrainfo) { log_info(LD_GENERAL, "Adding stats to extra-info descriptor."); /* Bandwidth usage stats don't have their own option */ @@ -3182,6 +3191,7 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, contents = rep_hist_get_bandwidth_lines(); smartlist_add(chunks, contents); } + /* geoip hashes aren't useful unless we are publishing other stats */ if (geoip_is_loaded(AF_INET)) smartlist_add_asprintf(chunks, "geoip-db-digest %s\n", geoip_db_digest(AF_INET)); @@ -3223,12 +3233,7 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, if (contents) smartlist_add(chunks, contents); } - /* Add information about the pluggable transports we support. */ - if (options->ServerTransportPlugin) { - char *pluggable_transports = pt_get_extra_info_descriptor_string(); - if (pluggable_transports) - smartlist_add(chunks, pluggable_transports); - } + /* bridge statistics */ if (should_record_bridge_info(options)) { const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now); if (bridge_stats) { -- cgit v1.2.3-54-g00ecf From 45be44ed9c1b3ddbe2ad4caaebc3ae0076bdbd07 Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 24 Jun 2019 20:32:38 +1000 Subject: stats: Split extrainfo_dump_to_string() into smaller functions. Closes ticket 30956. --- changes/ticket30956_refactor | 3 + scripts/maint/practracker/exceptions.txt | 3 +- src/feature/relay/router.c | 186 +++++++++++++++++++++++-------- 3 files changed, 146 insertions(+), 46 deletions(-) create mode 100644 changes/ticket30956_refactor (limited to 'changes') diff --git a/changes/ticket30956_refactor b/changes/ticket30956_refactor new file mode 100644 index 0000000000..81151c6cc9 --- /dev/null +++ b/changes/ticket30956_refactor @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Split extrainfo_dump_to_string() into smaller functions. + Closes ticket 30956. diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index 815d0ed097..4db452b897 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -225,13 +225,12 @@ problem function-size /src/feature/nodelist/routerlist.c:update_extrainfo_downlo problem function-size /src/feature/relay/dns.c:dns_resolve_impl() 134 problem function-size /src/feature/relay/dns.c:configure_nameservers() 161 problem function-size /src/feature/relay/dns.c:evdns_callback() 109 -problem file-size /src/feature/relay/router.c 3407 +problem file-size /src/feature/relay/router.c 3510 problem include-count /src/feature/relay/router.c 56 problem function-size /src/feature/relay/router.c:init_keys() 252 problem function-size /src/feature/relay/router.c:get_my_declared_family() 114 problem function-size /src/feature/relay/router.c:router_build_fresh_unsigned_routerinfo() 136 problem function-size /src/feature/relay/router.c:router_dump_router_to_string() 371 -problem function-size /src/feature/relay/router.c:extrainfo_dump_to_string() 206 problem function-size /src/feature/relay/routerkeys.c:load_ed_keys() 294 problem function-size /src/feature/rend/rendcache.c:rend_cache_store_v2_desc_as_client() 193 problem function-size /src/feature/rend/rendclient.c:rend_client_send_introduction() 220 diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index 25bb1835c2..6b33265294 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -3113,33 +3113,22 @@ load_stats_file(const char *filename, const char *end_line, time_t now, return r; } -/** Write the contents of extrainfo, to * *s_out, signing them - * with ident_key. - * - * If ExtraInfoStatistics is 1, also write aggregated statistics and related - * configuration data before signing. Most statistics also have an option that - * enables or disables that particular statistic. - * - * Return 0 on success, negative on failure. */ -int -extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, - crypto_pk_t *ident_key, - const ed25519_keypair_t *signing_keypair) +/** Add header strings to chunks, based on the extrainfo object extrainfo, + * and ed25519 keypair signing_keypair, if emit_ed_sigs is true. + * Helper for extrainfo_dump_to_string(). + * Returns 0 on success, negative on failure. */ +static int +extrainfo_dump_to_string_header_helper( + smartlist_t *chunks, + const extrainfo_t *extrainfo, + const ed25519_keypair_t *signing_keypair, + int emit_ed_sigs) { - const or_options_t *options = get_options(); char identity[HEX_DIGEST_LEN+1]; char published[ISO_TIME_LEN+1]; - char digest[DIGEST_LEN]; - int result; - static int write_stats_to_extrainfo = 1; - char sig[DIROBJ_MAX_SIG_LEN+1]; - char *s = NULL, *pre, *contents, *cp, *s_dup = NULL; - time_t now = time(NULL); - smartlist_t *chunks = smartlist_new(); - extrainfo_t *ei_tmp = NULL; - const int emit_ed_sigs = signing_keypair && - extrainfo->cache_info.signing_key_cert; char *ed_cert_line = NULL; + char *pre = NULL; + int rv = -1; base16_encode(identity, sizeof(identity), extrainfo->cache_info.identity_digest, DIGEST_LEN); @@ -3175,6 +3164,29 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, published); smartlist_add(chunks, pre); + rv = 0; + goto done; + + err: + rv = -1; + + done: + tor_free(ed_cert_line); + return rv; +} + +/** Add pluggable transport and statistics strings to chunks, skipping + * statistics if write_stats_to_extrainfo is false. + * Helper for extrainfo_dump_to_string(). + * Can not fail. */ +static void +extrainfo_dump_to_string_stats_helper(smartlist_t *chunks, + int write_stats_to_extrainfo) +{ + const or_options_t *options = get_options(); + char *contents = NULL; + time_t now = time(NULL); + /* Add information about the pluggable transports we support, even if we * are not publishing statistics. This information is needed by BridgeDB * to distribute bridges. */ @@ -3241,21 +3253,113 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, } } } +} + +/** Add an ed25519 signature of chunks to chunks, using the ed25519 keypair + * signing_keypair. + * Helper for extrainfo_dump_to_string(). + * Returns 0 on success, negative on failure. */ +static int +extrainfo_dump_to_string_ed_sig_helper( + smartlist_t *chunks, + const ed25519_keypair_t *signing_keypair) +{ + char sha256_digest[DIGEST256_LEN]; + ed25519_signature_t ed_sig; + char buf[ED25519_SIG_BASE64_LEN+1]; + int rv = -1; + + smartlist_add_strdup(chunks, "router-sig-ed25519 "); + crypto_digest_smartlist_prefix(sha256_digest, DIGEST256_LEN, + ED_DESC_SIGNATURE_PREFIX, + chunks, "", DIGEST_SHA256); + if (ed25519_sign(&ed_sig, (const uint8_t*)sha256_digest, DIGEST256_LEN, + signing_keypair) < 0) + goto err; + ed25519_signature_to_base64(buf, &ed_sig); + + smartlist_add_asprintf(chunks, "%s\n", buf); + + rv = 0; + goto done; + + err: + rv = -1; + + done: + return rv; +} + +/** Add an RSA signature of extrainfo_string to chunks, using the RSA key + * ident_key. + * Helper for extrainfo_dump_to_string(). + * Returns 0 on success, negative on failure. */ +static int +extrainfo_dump_to_string_rsa_sig_helper(smartlist_t *chunks, + crypto_pk_t *ident_key, + const char *extrainfo_string) +{ + char sig[DIROBJ_MAX_SIG_LEN+1]; + char digest[DIGEST_LEN]; + int rv = -1; + + memset(sig, 0, sizeof(sig)); + if (router_get_extrainfo_hash(extrainfo_string, strlen(extrainfo_string), + digest) < 0 || + router_append_dirobj_signature(sig, sizeof(sig), digest, DIGEST_LEN, + ident_key) < 0) { + log_warn(LD_BUG, "Could not append signature to extra-info " + "descriptor."); + goto err; + } + smartlist_add_strdup(chunks, sig); + + rv = 0; + goto done; + + err: + rv = -1; + + done: + return rv; +} + +/** Write the contents of extrainfo, to * *s_out, signing them + * with ident_key. + * + * If ExtraInfoStatistics is 1, also write aggregated statistics and related + * configuration data before signing. Most statistics also have an option that + * enables or disables that particular statistic. + * + * Always write pluggable transport lines. + * + * Return 0 on success, negative on failure. */ +int +extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, + crypto_pk_t *ident_key, + const ed25519_keypair_t *signing_keypair) +{ + int result; + static int write_stats_to_extrainfo = 1; + char *s = NULL, *cp, *s_dup = NULL; + smartlist_t *chunks = smartlist_new(); + extrainfo_t *ei_tmp = NULL; + const int emit_ed_sigs = signing_keypair && + extrainfo->cache_info.signing_key_cert; + int rv = 0; + + rv = extrainfo_dump_to_string_header_helper(chunks, extrainfo, + signing_keypair, + emit_ed_sigs); + if (rv < 0) + goto err; + + extrainfo_dump_to_string_stats_helper(chunks, write_stats_to_extrainfo); if (emit_ed_sigs) { - char sha256_digest[DIGEST256_LEN]; - smartlist_add_strdup(chunks, "router-sig-ed25519 "); - crypto_digest_smartlist_prefix(sha256_digest, DIGEST256_LEN, - ED_DESC_SIGNATURE_PREFIX, - chunks, "", DIGEST_SHA256); - ed25519_signature_t ed_sig; - char buf[ED25519_SIG_BASE64_LEN+1]; - if (ed25519_sign(&ed_sig, (const uint8_t*)sha256_digest, DIGEST256_LEN, - signing_keypair) < 0) + rv = extrainfo_dump_to_string_ed_sig_helper(chunks, signing_keypair); + if (rv < 0) goto err; - ed25519_signature_to_base64(buf, &ed_sig); - - smartlist_add_asprintf(chunks, "%s\n", buf); } smartlist_add_strdup(chunks, "router-signature\n"); @@ -3285,15 +3389,10 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, } } - memset(sig, 0, sizeof(sig)); - if (router_get_extrainfo_hash(s, strlen(s), digest) < 0 || - router_append_dirobj_signature(sig, sizeof(sig), digest, DIGEST_LEN, - ident_key) < 0) { - log_warn(LD_BUG, "Could not append signature to extra-info " - "descriptor."); + rv = extrainfo_dump_to_string_rsa_sig_helper(chunks, ident_key, s); + if (rv < 0) goto err; - } - smartlist_add_strdup(chunks, sig); + tor_free(s); s = smartlist_join_strings(chunks, "", 0, NULL); @@ -3329,7 +3428,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, SMARTLIST_FOREACH(chunks, char *, chunk, tor_free(chunk)); smartlist_free(chunks); tor_free(s_dup); - tor_free(ed_cert_line); extrainfo_free(ei_tmp); return result; -- cgit v1.2.3-54-g00ecf From 5beb32d3d9a9640e515e6369d3a908e93b8895ef Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 24 Jun 2019 21:19:49 +1000 Subject: stats: Stop removing the ed25519 signature if the extra info file is too big If the signature data was removed, but the keyword was kept, this could result in an unparseable extra info file. Fixes bug 30958; bugfix on 0.2.7.2-alpha. --- changes/bug30958 | 5 +++++ src/or/router.c | 12 +++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 changes/bug30958 (limited to 'changes') diff --git a/changes/bug30958 b/changes/bug30958 new file mode 100644 index 0000000000..374c8e46f7 --- /dev/null +++ b/changes/bug30958 @@ -0,0 +1,5 @@ + o Minor bugfixes (statistics): + - Stop removing the ed25519 signature if the extra info file is too big. + If the signature data was removed, but the keyword was kept, this could + result in an unparseable extra info file. Fixes bug 30958; + bugfix on 0.2.7.2-alpha. diff --git a/src/or/router.c b/src/or/router.c index c416474226..3fce45115c 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -3252,11 +3252,13 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, while (strlen(s) > MAX_EXTRAINFO_UPLOAD_SIZE - DIROBJ_MAX_SIG_LEN) { /* So long as there are at least two chunks (one for the initial * extra-info line and one for the router-signature), we can keep removing - * things. */ - if (smartlist_len(chunks) > 2) { - /* We remove the next-to-last element (remember, len-1 is the last - element), since we need to keep the router-signature element. */ - int idx = smartlist_len(chunks) - 2; + * things. If emit_ed_sigs is true, we also keep 2 additional chunks at the + * end for the ed25519 signature. */ + const int required_chunks = emit_ed_sigs ? 4 : 2; + if (smartlist_len(chunks) > required_chunks) { + /* We remove the next-to-last or 4th-last element (remember, len-1 is the + * last element), since we need to keep the router-signature elements. */ + int idx = smartlist_len(chunks) - required_chunks; char *e = smartlist_get(chunks, idx); smartlist_del_keeporder(chunks, idx); log_warn(LD_GENERAL, "We just generated an extra-info descriptor " -- cgit v1.2.3-54-g00ecf From c60a85d22ab87fef5a7de2fee616ad112835177b Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 14 Jun 2019 08:42:24 -0400 Subject: Add a "typed_var" abstraction to implement lvalue access in C. Right now, this has been done at a high level by confparse.c, but it makes more sense to lower it. This API is radically un-typesafe as it stands; we'll be wrapping it in a safer API as we do #30914 and lower the struct manipulation code as well. Closes ticket 30864. --- Makefile.am | 4 +- changes/ticket30864 | 3 + scripts/maint/add_c_file.py | 6 +- src/app/config/confparse.c | 349 ++---------------- src/lib/conf/conftypes.h | 16 + src/lib/confmgt/.may_include | 2 + src/lib/confmgt/include.am | 7 +- src/lib/confmgt/type_defs.c | 727 ++++++++++++++++++++++++++++++++++++++ src/lib/confmgt/type_defs.h | 17 + src/lib/confmgt/typedvar.c | 305 ++++++++++++++++ src/lib/confmgt/typedvar.h | 49 +++ src/lib/confmgt/var_type_def_st.h | 147 ++++++++ src/test/test_confparse.c | 4 +- src/test/test_options.c | 12 +- 14 files changed, 1315 insertions(+), 333 deletions(-) create mode 100644 changes/ticket30864 create mode 100644 src/lib/confmgt/type_defs.c create mode 100644 src/lib/confmgt/type_defs.h create mode 100644 src/lib/confmgt/typedvar.c create mode 100644 src/lib/confmgt/typedvar.h create mode 100644 src/lib/confmgt/var_type_def_st.h (limited to 'changes') diff --git a/Makefile.am b/Makefile.am index 0083608ce9..6445502933 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,6 +41,7 @@ TOR_UTIL_LIBS = \ src/lib/libtor-geoip.a \ src/lib/libtor-process.a \ src/lib/libtor-buf.a \ + src/lib/libtor-confmgt.a \ src/lib/libtor-pubsub.a \ src/lib/libtor-dispatch.a \ src/lib/libtor-time.a \ @@ -54,7 +55,6 @@ TOR_UTIL_LIBS = \ src/lib/libtor-math.a \ src/lib/libtor-meminfo.a \ src/lib/libtor-osinfo.a \ - src/lib/libtor-confmgt.a \ src/lib/libtor-log.a \ src/lib/libtor-lock.a \ src/lib/libtor-fdio.a \ @@ -75,6 +75,7 @@ TOR_UTIL_TESTING_LIBS = \ src/lib/libtor-geoip-testing.a \ src/lib/libtor-process-testing.a \ src/lib/libtor-buf-testing.a \ + src/lib/libtor-confmgt-testing.a \ src/lib/libtor-pubsub-testing.a \ src/lib/libtor-dispatch-testing.a \ src/lib/libtor-time-testing.a \ @@ -89,7 +90,6 @@ TOR_UTIL_TESTING_LIBS = \ src/lib/libtor-meminfo-testing.a \ src/lib/libtor-osinfo-testing.a \ src/lib/libtor-term-testing.a \ - src/lib/libtor-confmgt-testing.a \ src/lib/libtor-log-testing.a \ src/lib/libtor-lock-testing.a \ src/lib/libtor-fdio-testing.a \ diff --git a/changes/ticket30864 b/changes/ticket30864 new file mode 100644 index 0000000000..b8fb571300 --- /dev/null +++ b/changes/ticket30864 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Extract our variable manipulation code from confparse.c to a new + lower-level typedvar.h module. Closes ticket 30864. diff --git a/scripts/maint/add_c_file.py b/scripts/maint/add_c_file.py index 499415974f..adf7ce79bb 100755 --- a/scripts/maint/add_c_file.py +++ b/scripts/maint/add_c_file.py @@ -125,8 +125,8 @@ class AutomakeChunk: Y \ Z """ - self.prespace = "\t" - self.postspace = "\t\t" + prespace = "\t" + postspace = "\t\t" for lineno, line in enumerate(self.lines): m = re.match(r'(\s+)(\S+)(\s+)\\', line) if not m: @@ -135,7 +135,7 @@ class AutomakeChunk: if fname > member: self.insert_before(lineno, member, prespace, postspace) return - self.insert_at_end(member) + self.insert_at_end(member, prespace, postspace) def insert_before(self, lineno, member, prespace, postspace): self.lines.insert(lineno, diff --git a/src/app/config/confparse.c b/src/app/config/confparse.c index 296e7c2a39..bc2ab24e4f 100644 --- a/src/app/config/confparse.c +++ b/src/app/config/confparse.c @@ -30,6 +30,8 @@ #include "lib/container/bitarray.h" #include "lib/encoding/confline.h" +#include "lib/confmgt/typedvar.h" + static void config_reset(const config_format_t *fmt, void *options, const config_var_t *var, int use_defaults); @@ -160,7 +162,6 @@ static int config_assign_value(const config_format_t *fmt, void *options, config_line_t *c, char **msg) { - int i, ok; const config_var_t *var; void *lvalue; @@ -168,144 +169,14 @@ config_assign_value(const config_format_t *fmt, void *options, var = config_find_option(fmt, c->key); tor_assert(var); + tor_assert(!strcmp(c->key, var->name)); lvalue = STRUCT_VAR_P(options, var->var_offset); - switch (var->type) { - - case CONFIG_TYPE_INT: - case CONFIG_TYPE_POSINT: - i = (int)tor_parse_long(c->value, 10, - var->type==CONFIG_TYPE_INT ? INT_MIN : 0, - INT_MAX, - &ok, NULL); - if (!ok) { - tor_asprintf(msg, - "Int keyword '%s %s' is malformed or out of bounds.", - c->key, c->value); - return -1; - } - *(int *)lvalue = i; - break; - - case CONFIG_TYPE_UINT64: { - uint64_t u64 = tor_parse_uint64(c->value, 10, - 0, UINT64_MAX, &ok, NULL); - if (!ok) { - tor_asprintf(msg, - "uint64 keyword '%s %s' is malformed or out of bounds.", - c->key, c->value); - return -1; - } - *(uint64_t *)lvalue = u64; - break; - } + if (var->type == CONFIG_TYPE_ROUTERSET) { + // XXXX make the backend extensible so that we don't have to + // XXXX handle ROUTERSET specially. - case CONFIG_TYPE_CSV_INTERVAL: { - /* We used to have entire smartlists here. But now that all of our - * download schedules use exponential backoff, only the first part - * matters. */ - const char *comma = strchr(c->value, ','); - const char *val = c->value; - char *tmp = NULL; - if (comma) { - tmp = tor_strndup(c->value, comma - c->value); - val = tmp; - } - - i = config_parse_interval(val, &ok); - if (!ok) { - tor_asprintf(msg, - "Interval '%s %s' is malformed or out of bounds.", - c->key, c->value); - tor_free(tmp); - return -1; - } - *(int *)lvalue = i; - tor_free(tmp); - break; - } - - case CONFIG_TYPE_INTERVAL: { - i = config_parse_interval(c->value, &ok); - if (!ok) { - tor_asprintf(msg, - "Interval '%s %s' is malformed or out of bounds.", - c->key, c->value); - return -1; - } - *(int *)lvalue = i; - break; - } - - case CONFIG_TYPE_MSEC_INTERVAL: { - i = config_parse_msec_interval(c->value, &ok); - if (!ok) { - tor_asprintf(msg, - "Msec interval '%s %s' is malformed or out of bounds.", - c->key, c->value); - return -1; - } - *(int *)lvalue = i; - break; - } - - case CONFIG_TYPE_MEMUNIT: { - uint64_t u64 = config_parse_memunit(c->value, &ok); - if (!ok) { - tor_asprintf(msg, - "Value '%s %s' is malformed or out of bounds.", - c->key, c->value); - return -1; - } - *(uint64_t *)lvalue = u64; - break; - } - - case CONFIG_TYPE_BOOL: - i = (int)tor_parse_long(c->value, 10, 0, 1, &ok, NULL); - if (!ok) { - tor_asprintf(msg, - "Boolean '%s %s' expects 0 or 1.", - c->key, c->value); - return -1; - } - *(int *)lvalue = i; - break; - - case CONFIG_TYPE_AUTOBOOL: - if (!strcasecmp(c->value, "auto")) - *(int *)lvalue = -1; - else if (!strcmp(c->value, "0")) - *(int *)lvalue = 0; - else if (!strcmp(c->value, "1")) - *(int *)lvalue = 1; - else { - tor_asprintf(msg, "Boolean '%s %s' expects 0, 1, or 'auto'.", - c->key, c->value); - return -1; - } - break; - - case CONFIG_TYPE_STRING: - case CONFIG_TYPE_FILENAME: - tor_free(*(char **)lvalue); - *(char **)lvalue = tor_strdup(c->value); - break; - - case CONFIG_TYPE_DOUBLE: - *(double *)lvalue = atof(c->value); - break; - - case CONFIG_TYPE_ISOTIME: - if (parse_iso_time(c->value, (time_t *)lvalue)) { - tor_asprintf(msg, - "Invalid time '%s' for keyword '%s'", c->value, c->key); - return -1; - } - break; - - case CONFIG_TYPE_ROUTERSET: if (*(routerset_t**)lvalue) { routerset_free(*(routerset_t**)lvalue); } @@ -315,50 +186,10 @@ config_assign_value(const config_format_t *fmt, void *options, c->value, c->key); return -1; } - break; - - case CONFIG_TYPE_CSV: - if (*(smartlist_t**)lvalue) { - SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp)); - smartlist_clear(*(smartlist_t**)lvalue); - } else { - *(smartlist_t**)lvalue = smartlist_new(); - } - - smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - break; - - case CONFIG_TYPE_LINELIST: - case CONFIG_TYPE_LINELIST_S: - { - config_line_t *lastval = *(config_line_t**)lvalue; - if (lastval && lastval->fragile) { - if (c->command != CONFIG_LINE_APPEND) { - config_free_lines(lastval); - *(config_line_t**)lvalue = NULL; - } else { - lastval->fragile = 0; - } - } - - config_line_append((config_line_t**)lvalue, c->key, c->value); - } - break; - case CONFIG_TYPE_OBSOLETE: - log_warn(LD_CONFIG, "Skipping obsolete configuration option '%s'", c->key); - break; - case CONFIG_TYPE_LINELIST_V: - tor_asprintf(msg, - "You may not provide a value for virtual option '%s'", c->key); - return -1; - // LCOV_EXCL_START - default: - tor_assert_unreached(); - break; - // LCOV_EXCL_STOP + return 0; } - return 0; + + return typed_var_kvassign(lvalue, c, msg, var->type); } /** Mark every linelist in options "fragile", so that fresh assignments @@ -544,100 +375,15 @@ config_get_assigned_option(const config_format_t *fmt, const void *options, } value = STRUCT_VAR_P(options, var->var_offset); - result = tor_malloc_zero(sizeof(config_line_t)); - result->key = tor_strdup(var->name); - switch (var->type) - { - case CONFIG_TYPE_STRING: - case CONFIG_TYPE_FILENAME: - if (*(char**)value) { - result->value = tor_strdup(*(char**)value); - } else { - tor_free(result->key); - tor_free(result); - return NULL; - } - break; - case CONFIG_TYPE_ISOTIME: - if (*(time_t*)value) { - result->value = tor_malloc(ISO_TIME_LEN+1); - format_iso_time(result->value, *(time_t*)value); - } else { - tor_free(result->key); - tor_free(result); - } - escape_val = 0; /* Can't need escape. */ - break; - case CONFIG_TYPE_CSV_INTERVAL: - case CONFIG_TYPE_INTERVAL: - case CONFIG_TYPE_MSEC_INTERVAL: - case CONFIG_TYPE_POSINT: - case CONFIG_TYPE_INT: - /* This means every or_options_t uint or bool element - * needs to be an int. Not, say, a uint16_t or char. */ - tor_asprintf(&result->value, "%d", *(int*)value); - escape_val = 0; /* Can't need escape. */ - break; - case CONFIG_TYPE_UINT64: /* Fall through */ - case CONFIG_TYPE_MEMUNIT: - tor_asprintf(&result->value, "%"PRIu64, - (*(uint64_t*)value)); - escape_val = 0; /* Can't need escape. */ - break; - case CONFIG_TYPE_DOUBLE: - tor_asprintf(&result->value, "%f", *(double*)value); - escape_val = 0; /* Can't need escape. */ - break; - - case CONFIG_TYPE_AUTOBOOL: - if (*(int*)value == -1) { - result->value = tor_strdup("auto"); - escape_val = 0; - break; - } - /* fall through */ - case CONFIG_TYPE_BOOL: - result->value = tor_strdup(*(int*)value ? "1" : "0"); - escape_val = 0; /* Can't need escape. */ - break; - case CONFIG_TYPE_ROUTERSET: - result->value = routerset_to_string(*(routerset_t**)value); - break; - case CONFIG_TYPE_CSV: - if (*(smartlist_t**)value) - result->value = - smartlist_join_strings(*(smartlist_t**)value, ",", 0, NULL); - else - result->value = tor_strdup(""); - break; - case CONFIG_TYPE_OBSOLETE: - log_fn(LOG_INFO, LD_CONFIG, - "You asked me for the value of an obsolete config option '%s'.", - key); - tor_free(result->key); - tor_free(result); - return NULL; - case CONFIG_TYPE_LINELIST_S: - tor_free(result->key); - tor_free(result); - result = config_lines_dup_and_filter(*(const config_line_t **)value, - key); - break; - case CONFIG_TYPE_LINELIST: - case CONFIG_TYPE_LINELIST_V: - tor_free(result->key); - tor_free(result); - result = config_lines_dup(*(const config_line_t**)value); - break; - // LCOV_EXCL_START - default: - tor_free(result->key); - tor_free(result); - log_warn(LD_BUG,"Unknown type %d for known key '%s'", - var->type, key); - return NULL; - // LCOV_EXCL_STOP - } + if (var->type == CONFIG_TYPE_ROUTERSET) { + // XXXX make the backend extensible so that we don't have to + // XXXX handle ROUTERSET specially. + result = tor_malloc_zero(sizeof(config_line_t)); + result->key = tor_strdup(var->name); + result->value = routerset_to_string(*(routerset_t**)value); + } else { + result = typed_var_kvencode(var->name, value, var->type); + } if (escape_val) { config_line_t *line; @@ -765,56 +511,17 @@ config_clear(const config_format_t *fmt, void *options, { void *lvalue = STRUCT_VAR_P(options, var->var_offset); (void)fmt; /* unused */ - switch (var->type) { - case CONFIG_TYPE_STRING: - case CONFIG_TYPE_FILENAME: - tor_free(*(char**)lvalue); - break; - case CONFIG_TYPE_DOUBLE: - *(double*)lvalue = 0.0; - break; - case CONFIG_TYPE_ISOTIME: - *(time_t*)lvalue = 0; - break; - case CONFIG_TYPE_CSV_INTERVAL: - case CONFIG_TYPE_INTERVAL: - case CONFIG_TYPE_MSEC_INTERVAL: - case CONFIG_TYPE_POSINT: - case CONFIG_TYPE_INT: - case CONFIG_TYPE_BOOL: - *(int*)lvalue = 0; - break; - case CONFIG_TYPE_AUTOBOOL: - *(int*)lvalue = -1; - break; - case CONFIG_TYPE_UINT64: - case CONFIG_TYPE_MEMUNIT: - *(uint64_t*)lvalue = 0; - break; - case CONFIG_TYPE_ROUTERSET: - if (*(routerset_t**)lvalue) { - routerset_free(*(routerset_t**)lvalue); - *(routerset_t**)lvalue = NULL; - } - break; - case CONFIG_TYPE_CSV: - if (*(smartlist_t**)lvalue) { - SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp)); - smartlist_free(*(smartlist_t **)lvalue); - *(smartlist_t **)lvalue = NULL; - } - break; - case CONFIG_TYPE_LINELIST: - case CONFIG_TYPE_LINELIST_S: - config_free_lines(*(config_line_t **)lvalue); - *(config_line_t **)lvalue = NULL; - break; - case CONFIG_TYPE_LINELIST_V: - /* handled by linelist_s. */ - break; - case CONFIG_TYPE_OBSOLETE: - break; + if (var->type == CONFIG_TYPE_ROUTERSET) { + // XXXX make the backend extensible so that we don't have to + // XXXX handle ROUTERSET specially. + if (*(routerset_t**)lvalue) { + routerset_free(*(routerset_t**)lvalue); + *(routerset_t**)lvalue = NULL; + } + return; } + + typed_var_free(lvalue, var->type); } /** Clear the option indexed by var in options. Then if diff --git a/src/lib/conf/conftypes.h b/src/lib/conf/conftypes.h index eb4eb1245f..b03234b62c 100644 --- a/src/lib/conf/conftypes.h +++ b/src/lib/conf/conftypes.h @@ -7,6 +7,22 @@ /** * @file conftypes.h * @brief Types used to specify configurable options. + * + * This header defines the types that different modules will use in order to + * declare their configuration and state variables, and tell the configuration + * management code about those variables. From the individual module's point + * of view, its configuration and state are simply data structures. + * + * For defining new variable types, see var_type_def_st.h. + * + * For the code that manipulates variables defined via this module, see + * lib/confmgt/, especially typedvar.h and (later) structvar.h. The + * configuration manager is responsible for encoding, decoding, and + * maintaining the configuration structures used by the various modules. + * + * STATUS NOTE: This is a work in process refactoring. It is not yet possible + * for modules to define their own variables, and much of the configuration + * management code is still in src/app/config/. **/ #ifndef TOR_SRC_LIB_CONF_CONFTYPES_H diff --git a/src/lib/confmgt/.may_include b/src/lib/confmgt/.may_include index 640acf3770..d85dbf6904 100644 --- a/src/lib/confmgt/.may_include +++ b/src/lib/confmgt/.may_include @@ -2,6 +2,8 @@ orconfig.h lib/cc/*.h lib/conf/*.h lib/confmgt/*.h +lib/container/*.h +lib/encoding/*.h lib/log/*.h lib/malloc/*.h lib/string/*.h diff --git a/src/lib/confmgt/include.am b/src/lib/confmgt/include.am index 729e6147ff..a2c7649957 100644 --- a/src/lib/confmgt/include.am +++ b/src/lib/confmgt/include.am @@ -6,6 +6,8 @@ endif # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_confmgt_a_SOURCES = \ + src/lib/confmgt/type_defs.c \ + src/lib/confmgt/typedvar.c \ src/lib/confmgt/unitparse.c src_lib_libtor_confmgt_testing_a_SOURCES = \ @@ -15,4 +17,7 @@ src_lib_libtor_confmgt_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ - src/lib/confmgt/unitparse.h + src/lib/confmgt/type_defs.h \ + src/lib/confmgt/typedvar.h \ + src/lib/confmgt/unitparse.h \ + src/lib/confmgt/var_type_def_st.h diff --git a/src/lib/confmgt/type_defs.c b/src/lib/confmgt/type_defs.c new file mode 100644 index 0000000000..62b4c1019d --- /dev/null +++ b/src/lib/confmgt/type_defs.c @@ -0,0 +1,727 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file type_defs.c + * @brief Definitions for various low-level configuration types. + * + * This module creates a number of var_type_def_t objects, to be used by + * typedvar.c in manipulating variables. + * + * The types here are common types that can be implemented with Tor's + * low-level functionality. To define new types, see var_type_def_st.h. + **/ + +#include "orconfig.h" +#include "lib/conf/conftypes.h" +#include "lib/confmgt/typedvar.h" +#include "lib/confmgt/type_defs.h" +#include "lib/confmgt/unitparse.h" + +#include "lib/cc/compat_compiler.h" +#include "lib/conf/conftypes.h" +#include "lib/container/smartlist.h" +#include "lib/encoding/confline.h" +#include "lib/encoding/time_fmt.h" +#include "lib/log/escape.h" +#include "lib/log/log.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/malloc.h" +#include "lib/string/parse_int.h" +#include "lib/string/printf.h" + +#include "lib/confmgt/var_type_def_st.h" + +#include +#include + +////// +// CONFIG_TYPE_STRING +// CONFIG_TYPE_FILENAME +// +// These two types are the same for now, but they have different names. +////// + +static int +string_parse(void *target, const char *value, char **errmsg, + const void *params) +{ + (void)params; + (void)errmsg; + char **p = (char**)target; + *p = tor_strdup(value); + return 0; +} + +static char * +string_encode(const void *value, const void *params) +{ + (void)params; + const char **p = (const char**)value; + return *p ? tor_strdup(*p) : NULL; +} + +static void +string_clear(void *value, const void *params) +{ + (void)params; + char **p = (char**)value; + tor_free(*p); // sets *p to NULL. +} + +static const var_type_fns_t string_fns = { + .parse = string_parse, + .encode = string_encode, + .clear = string_clear, +}; + +///// +// CONFIG_TYPE_INT +// CONFIG_TYPE_POSINT +// +// These types are implemented as int, possibly with a restricted range. +///// + +typedef struct int_type_params_t { + int minval; + int maxval; +} int_parse_params_t; + +static const int_parse_params_t INT_PARSE_UNRESTRICTED = { + .minval = INT_MIN, + .maxval = INT_MAX, +}; + +static const int_parse_params_t INT_PARSE_POSINT = { + .minval = 0, + .maxval = INT_MAX, +}; + +static int +int_parse(void *target, const char *value, char **errmsg, const void *params) +{ + const int_parse_params_t *pp; + if (params) { + pp = params; + } else { + pp = &INT_PARSE_UNRESTRICTED; + } + int *p = target; + int ok=0; + *p = (int)tor_parse_long(value, 10, pp->minval, pp->maxval, &ok, NULL); + if (!ok) { + tor_asprintf(errmsg, "Integer %s is malformed or out of bounds.", + value); + return -1; + } + return 0; +} + +static char * +int_encode(const void *value, const void *params) +{ + (void)params; + int v = *(int*)value; + char *result; + tor_asprintf(&result, "%d", v); + return result; +} + +static void +int_clear(void *value, const void *params) +{ + (void)params; + *(int*)value = 0; +} + +static bool +int_ok(const void *value, const void *params) +{ + const int_parse_params_t *pp = params; + if (pp) { + int v = *(int*)value; + return pp->minval <= v && v <= pp->maxval; + } else { + return true; + } +} + +static const var_type_fns_t int_fns = { + .parse = int_parse, + .encode = int_encode, + .clear = int_clear, + .ok = int_ok, +}; + +///// +// CONFIG_TYPE_UINT64 +// +// This type is an unrestricted u64. +///// + +static int +uint64_parse(void *target, const char *value, char **errmsg, + const void *params) +{ + (void)params; + (void)errmsg; + uint64_t *p = target; + int ok=0; + *p = tor_parse_uint64(value, 10, 0, UINT64_MAX, &ok, NULL); + if (!ok) { + tor_asprintf(errmsg, "Integer %s is malformed or out of bounds.", + value); + return -1; + } + return 0; +} + +static char * +uint64_encode(const void *value, const void *params) +{ + (void)params; + uint64_t v = *(uint64_t*)value; + char *result; + tor_asprintf(&result, "%"PRIu64, v); + return result; +} + +static void +uint64_clear(void *value, const void *params) +{ + (void)params; + *(uint64_t*)value = 0; +} + +static const var_type_fns_t uint64_fns = { + .parse = uint64_parse, + .encode = uint64_encode, + .clear = uint64_clear, +}; + +///// +// CONFIG_TYPE_INTERVAL +// CONFIG_TYPE_MSEC_INTERVAL +// CONFIG_TYPE_MEMUNIT +// +// These types are implemented using the config_parse_units() function. +// The intervals are stored as ints, whereas memory units are stored as +// uint64_ts. +///// + +static int +units_parse_u64(void *target, const char *value, char **errmsg, + const void *params) +{ + const unit_table_t *table = params; + tor_assert(table); + uint64_t *v = (uint64_t*)target; + int ok=1; + *v = config_parse_units(value, table, &ok); + if (!ok) { + *errmsg = tor_strdup("Provided value is malformed or out of bounds."); + return -1; + } + return 0; +} + +static int +units_parse_int(void *target, const char *value, char **errmsg, + const void *params) +{ + const unit_table_t *table = params; + tor_assert(table); + int *v = (int*)target; + int ok=1; + uint64_t u64 = config_parse_units(value, table, &ok); + if (!ok) { + *errmsg = tor_strdup("Provided value is malformed or out of bounds."); + return -1; + } + if (u64 > INT_MAX) { + tor_asprintf(errmsg, "Provided value %s is too large", value); + return -1; + } + *v = (int) u64; + return 0; +} + +static bool +units_ok_int(const void *value, const void *params) +{ + (void)params; + int v = *(int*)value; + return v >= 0; +} + +static const var_type_fns_t memunit_fns = { + .parse = units_parse_u64, + .encode = uint64_encode, // doesn't use params + .clear = uint64_clear, // doesn't use params +}; + +static const var_type_fns_t interval_fns = { + .parse = units_parse_int, + .encode = int_encode, // doesn't use params + .clear = int_clear, // doesn't use params, + .ok = units_ok_int // can't use int_ok, since that expects int params. +}; + +///// +// CONFIG_TYPE_DOUBLE +// +// This is a nice simple double. +///// + +static int +double_parse(void *target, const char *value, char **errmsg, + const void *params) +{ + (void)params; + (void)errmsg; + double *v = (double*)target; + // XXXX This is the preexisting behavior, but we should detect errors here. + *v = atof(value); + return 0; +} + +static char * +double_encode(const void *value, const void *params) +{ + (void)params; + double v = *(double*)value; + char *result; + tor_asprintf(&result, "%f", v); + return result; +} + +static void +double_clear(void *value, const void *params) +{ + (void)params; + double *v = (double *)value; + *v = 0.0; +} + +static const var_type_fns_t double_fns = { + .parse = double_parse, + .encode = double_encode, + .clear = double_clear, +}; + +///// +// CONFIG_TYPE_BOOL +// CONFIG_TYPE_AUTOBOOL +// +// These types are implemented as a case-insensitive string-to-integer +// mapping. +///// + +typedef struct enumeration_table_t { + const char *name; + int value; +} enumeration_table_t; + +static int +enum_parse(void *target, const char *value, char **errmsg, + const void *params) +{ + const enumeration_table_t *table = params; + int *p = (int *)target; + for (; table->name; ++table) { + if (!strcasecmp(value, table->name)) { + *p = table->value; + return 0; + } + } + tor_asprintf(errmsg, "Unrecognized value %s.", value); + return -1; +} + +static char * +enum_encode(const void *value, const void *params) +{ + int v = *(const int*)value; + const enumeration_table_t *table = params; + for (; table->name; ++table) { + if (v == table->value) + return tor_strdup(table->name); + } + return NULL; // error. +} + +static void +enum_clear(void *value, const void *params) +{ + int *p = (int*)value; + const enumeration_table_t *table = params; + tor_assert(table->name); + *p = table->value; +} + +static bool +enum_ok(const void *value, const void *params) +{ + int v = *(const int*)value; + const enumeration_table_t *table = params; + for (; table->name; ++table) { + if (v == table->value) + return true; + } + return false; +} + +static const enumeration_table_t enum_table_bool[] = { + { "0", 0 }, + { "1", 1 }, + { NULL, 0 }, +}; + +static const enumeration_table_t enum_table_autobool[] = { + { "0", 0 }, + { "1", 1 }, + { "auto", -1 }, + { NULL, 0 }, +}; + +static const var_type_fns_t enum_fns = { + .parse = enum_parse, + .encode = enum_encode, + .clear = enum_clear, + .ok = enum_ok, +}; + +///// +// CONFIG_TYPE_ISOTIME +// +// This is a time_t, encoded in ISO8601 format. +///// + +static int +time_parse(void *target, const char *value, char **errmsg, + const void *params) +{ + (void) params; + time_t *p = target; + if (parse_iso_time(value, p) < 0) { + tor_asprintf(errmsg, "Invalid time %s", escaped(value)); + return -1; + } + return 0; +} + +static char * +time_encode(const void *value, const void *params) +{ + (void)params; + time_t v = *(const time_t *)value; + char *result = tor_malloc(ISO_TIME_LEN+1); + format_iso_time(result, v); + return result; +} + +static void +time_clear(void *value, const void *params) +{ + (void)params; + time_t *t = value; + *t = 0; +} + +static const var_type_fns_t time_fns = { + .parse = time_parse, + .encode = time_encode, + .clear = time_clear, +}; + +///// +// CONFIG_TYPE_CSV +// +// This type is a comma-separated list of strings, stored in a smartlist_t. +// An empty list may be encoded either as an empty smartlist, or as NULL. +///// + +static int +csv_parse(void *target, const char *value, char **errmsg, + const void *params) +{ + (void)params; + (void)errmsg; + smartlist_t **sl = (smartlist_t**)target; + *sl = smartlist_new(); + smartlist_split_string(*sl, value, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + return 0; +} + +static char * +csv_encode(const void *value, const void *params) +{ + (void)params; + const smartlist_t *sl = *(const smartlist_t **)value; + if (! sl) + return tor_strdup(""); + + return smartlist_join_strings(*(smartlist_t**)value, ",", 0, NULL); +} + +static void +csv_clear(void *value, const void *params) +{ + (void)params; + smartlist_t **sl = (smartlist_t**)value; + if (!*sl) + return; + SMARTLIST_FOREACH(*sl, char *, cp, tor_free(cp)); + smartlist_free(*sl); // clears pointer. +} + +static const var_type_fns_t csv_fns = { + .parse = csv_parse, + .encode = csv_encode, + .clear = csv_clear, +}; + +///// +// CONFIG_TYPE_CSV_INTERVAL +// +// This type used to be a list of time intervals, used to determine a download +// schedule. Now, only the first interval counts: everything after the first +// comma is discarded. +///// + +static int +legacy_csv_interval_parse(void *target, const char *value, char **errmsg, + const void *params) +{ + (void)params; + /* We used to have entire smartlists here. But now that all of our + * download schedules use exponential backoff, only the first part + * matters. */ + const char *comma = strchr(value, ','); + const char *val = value; + char *tmp = NULL; + if (comma) { + tmp = tor_strndup(val, comma - val); + val = tmp; + } + + int rv = units_parse_int(target, val, errmsg, &time_units); + tor_free(tmp); + return rv; +} + +static const var_type_fns_t legacy_csv_interval_fns = { + .parse = legacy_csv_interval_parse, + .encode = int_encode, + .clear = int_clear, +}; + +///// +// CONFIG_TYPE_LINELIST +// CONFIG_TYPE_LINELIST_S +// CONFIG_TYPE_LINELIST_V +// +// A linelist is a raw config_line_t list. Order is preserved. +// +// The LINELIST type is used for homogeneous lists, where all the lines +// have the same key. +// +// The LINELIST_S and LINELIST_V types are used for the case where multiple +// lines of different keys are kept in a single list, to preserve their +// relative order. The unified list is stored as a "virtual" variable whose +// type is LINELIST_V; the individual sublists are treated as variables of +// type LINELIST_S. +// +// A linelist may be fragile or non-fragile. Assigning a line to a fragile +// linelist replaces the list with the line. If the line has the "APPEND" +// command set on it, or if the list is non-fragile, the line is appended. +// Either way, the new list is non-fragile. +///// + +static int +linelist_kv_parse(void *target, const struct config_line_t *line, + char **errmsg, const void *params) +{ + (void)params; + (void)errmsg; + config_line_t **lines = target; + + if (*lines && (*lines)->fragile) { + if (line->command == CONFIG_LINE_APPEND) { + (*lines)->fragile = 0; + } else { + config_free_lines(*lines); // sets it to NULL + } + } + + config_line_append(lines, line->key, line->value); + return 0; +} + +static int +linelist_kv_virt_noparse(void *target, const struct config_line_t *line, + char **errmsg, const void *params) +{ + (void)target; + (void)line; + (void)params; + *errmsg = tor_strdup("Cannot assign directly to virtual option."); + return -1; +} + +static struct config_line_t * +linelist_kv_encode(const char *key, const void *value, + const void *params) +{ + (void)key; + (void)params; + config_line_t *lines = *(config_line_t **)value; + return config_lines_dup(lines); +} + +static struct config_line_t * +linelist_s_kv_encode(const char *key, const void *value, + const void *params) +{ + (void)params; + config_line_t *lines = *(config_line_t **)value; + return config_lines_dup_and_filter(lines, key); +} + +static void +linelist_clear(void *target, const void *params) +{ + (void)params; + config_line_t **lines = target; + config_free_lines(*lines); // sets it to NULL +} + +static bool +linelist_eq(const void *a, const void *b, const void *params) +{ + (void)params; + const config_line_t *lines_a = *(const config_line_t **)a; + const config_line_t *lines_b = *(const config_line_t **)b; + return config_lines_eq(lines_a, lines_b); +} + +static int +linelist_copy(void *target, const void *value, const void *params) +{ + (void)params; + config_line_t **ptr = (config_line_t **)target; + const config_line_t *val = *(const config_line_t **)value; + config_free_lines(*ptr); + *ptr = config_lines_dup(val); + return 0; +} + +static const var_type_fns_t linelist_fns = { + .kv_parse = linelist_kv_parse, + .kv_encode = linelist_kv_encode, + .clear = linelist_clear, + .eq = linelist_eq, + .copy = linelist_copy, +}; + +static const var_type_fns_t linelist_v_fns = { + .kv_parse = linelist_kv_virt_noparse, + .kv_encode = linelist_kv_encode, + .clear = linelist_clear, + .eq = linelist_eq, + .copy = linelist_copy, +}; + +static const var_type_fns_t linelist_s_fns = { + .kv_parse = linelist_kv_parse, + .kv_encode = linelist_s_kv_encode, + .clear = linelist_clear, + .eq = linelist_eq, + .copy = linelist_copy, +}; + +///// +// CONFIG_TYPE_ROUTERSET +// +// XXXX This type is not implemented here, since routerset_t is not available +// XXXX to this module. +///// + +///// +// CONFIG_TYPE_OBSOLETE +// +// Used to indicate an obsolete option. +// +// XXXX This is not a type, and should be handled at a higher level of +// XXXX abstraction. +///// + +static int +ignore_parse(void *target, const char *value, char **errmsg, + const void *params) +{ + (void)target; + (void)value; + (void)errmsg; + (void)params; + // XXXX move this to a higher level, once such a level exists. + log_warn(LD_GENERAL, "Skipping obsolete configuration option."); + return 0; +} + +static char * +ignore_encode(const void *value, const void *params) +{ + (void)value; + (void)params; + return NULL; +} + +static const var_type_fns_t ignore_fns = { + .parse = ignore_parse, + .encode = ignore_encode, +}; + +/** + * Table mapping conf_type_t values to var_type_def_t objects. + **/ +static const var_type_def_t type_definitions_table[] = { + [CONFIG_TYPE_STRING] = { "String", &string_fns, NULL }, + [CONFIG_TYPE_FILENAME] = { "Filename", &string_fns, NULL }, + [CONFIG_TYPE_INT] = { "SignedInteger", &int_fns, &INT_PARSE_UNRESTRICTED }, + [CONFIG_TYPE_POSINT] = { "Integer", &int_fns, &INT_PARSE_POSINT }, + [CONFIG_TYPE_UINT64] = { "Integer", &uint64_fns, NULL, }, + [CONFIG_TYPE_MEMUNIT] = { "DataSize", &memunit_fns, &memory_units }, + [CONFIG_TYPE_INTERVAL] = { "TimeInterval", &interval_fns, &time_units }, + [CONFIG_TYPE_MSEC_INTERVAL] = { "TimeMsecInterval", &interval_fns, + &time_msec_units }, + [CONFIG_TYPE_DOUBLE] = { "Float", &double_fns, NULL }, + [CONFIG_TYPE_BOOL] = { "Boolean", &enum_fns, &enum_table_bool }, + [CONFIG_TYPE_AUTOBOOL] = { "Boolean+Auto", &enum_fns, &enum_table_autobool }, + [CONFIG_TYPE_ISOTIME] = { "Time", &time_fns, NULL }, + [CONFIG_TYPE_CSV] = { "CommaList", &csv_fns, NULL }, + [CONFIG_TYPE_CSV_INTERVAL] = { "TimeInterval", &legacy_csv_interval_fns, + NULL }, + [CONFIG_TYPE_LINELIST] = { "LineList", &linelist_fns, NULL }, + [CONFIG_TYPE_LINELIST_S] = { "Dependent", &linelist_s_fns, NULL }, + [CONFIG_TYPE_LINELIST_V] = { "Virtual", &linelist_v_fns, NULL }, + [CONFIG_TYPE_OBSOLETE] = { "Obsolete", &ignore_fns, NULL } +}; + +/** + * Return a pointer to the var_type_def_t object for the given + * config_type_t value, or NULL if no such type definition exists. + **/ +const var_type_def_t * +lookup_type_def(config_type_t type) +{ + int t = type; + tor_assert(t >= 0); + if (t >= (int)ARRAY_LENGTH(type_definitions_table)) + return NULL; + return &type_definitions_table[t]; +} diff --git a/src/lib/confmgt/type_defs.h b/src/lib/confmgt/type_defs.h new file mode 100644 index 0000000000..ecf040529e --- /dev/null +++ b/src/lib/confmgt/type_defs.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file type_defs.h + * @brief Header for lib/confmgt/type_defs.c + **/ + +#ifndef TOR_LIB_CONFMGT_TYPE_DEFS_H +#define TOR_LIB_CONFMGT_TYPE_DEFS_H + +const struct var_type_def_t *lookup_type_def(config_type_t type); + +#endif /* !defined(TOR_LIB_CONFMGT_TYPE_DEFS_H) */ diff --git a/src/lib/confmgt/typedvar.c b/src/lib/confmgt/typedvar.c new file mode 100644 index 0000000000..fc45c44481 --- /dev/null +++ b/src/lib/confmgt/typedvar.c @@ -0,0 +1,305 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file typedvar.c + * @brief Functions for accessing a pointer as an object of a given type. + * + * These functions represent a low-level API for accessing a typed variable. + * They are used in the configuration system to examine and set fields in + * configuration objects used by individual modules. + * + * Almost no code should call these directly. + **/ + +#include "orconfig.h" +#include "lib/conf/conftypes.h" +#include "lib/confmgt/type_defs.h" +#include "lib/confmgt/typedvar.h" +#include "lib/encoding/confline.h" +#include "lib/log/escape.h" +#include "lib/log/log.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/malloc.h" +#include "lib/string/util_string.h" + +#include "lib/confmgt/var_type_def_st.h" + +#include +#include + +/** + * Try to parse a string in value that encodes an object of the type + * defined by def. + * + * On success, adjust the lvalue pointed to by target to hold that + * value, and return 0. On failure, set *errmsg to a newly allocated + * string holding an error message, and return -1. + **/ +int +typed_var_assign_ex(void *target, const char *value, char **errmsg, + const var_type_def_t *def) +{ + if (BUG(!def)) + return -1; + // clear old value if needed. + typed_var_free_ex(target, def); + + tor_assert(def->fns->parse); + return def->fns->parse(target, value, errmsg, def->params); +} + +/** + * Try to parse a single line from the head ofline that encodes an + * object of the type defined in def. On success and failure, behave as + * typed_var_assign_ex(). + * + * All types for which keys are significant should use this function. + * + * Note that although multiple lines may be provided in line, + * only the first one is handled by this function. + **/ +int +typed_var_kvassign_ex(void *target, const config_line_t *line, + char **errmsg, const var_type_def_t *def) +{ + if (BUG(!def)) + return -1; + + if (def->fns->kv_parse) { + // We do _not_ free the old value here, since linelist options + // sometimes have append semantics. + return def->fns->kv_parse(target, line, errmsg, def->params); + } + + return typed_var_assign_ex(target, line->value, errmsg, def); +} + +/** + * Release storage held by a variable in target of type defined by + * def, and set target to a reasonable default. + **/ +void +typed_var_free_ex(void *target, const var_type_def_t *def) +{ + if (BUG(!def)) + return; + if (def->fns->clear) { + def->fns->clear(target, def->params); + } +} + +/** + * Encode a value of type def pointed to by value, and return + * its result in a newly allocated string. The string may need to be escaped. + * + * Returns NULL if this option has a NULL value, or on internal error. + **/ +char * +typed_var_encode_ex(const void *value, const var_type_def_t *def) +{ + if (BUG(!def)) + return NULL; + tor_assert(def->fns->encode); + return def->fns->encode(value, def->params); +} + +/** + * As typed_var_encode_ex(), but returns a newly allocated config_line_t + * object. The provided key is used as the key of the lines, unless + * the type is one (line a linelist) that encodes its own keys. + * + * This function may return a list of multiple lines. + * + * Returns NULL if there are no lines to encode, or on internal error. + */ +config_line_t * +typed_var_kvencode_ex(const char *key, const void *value, + const var_type_def_t *def) +{ + if (BUG(!def)) + return NULL; + if (def->fns->kv_encode) { + return def->fns->kv_encode(key, value, def->params); + } + char *encoded_value = typed_var_encode_ex(value, def); + if (!encoded_value) + return NULL; + + config_line_t *result = tor_malloc_zero(sizeof(config_line_t)); + result->key = tor_strdup(key); + result->value = encoded_value; + return result; +} + +/** + * Set dest to contain the same value as src. Both types + * must be as defined by def. + * + * Return 0 on success, and -1 on failure. + **/ +int +typed_var_copy_ex(void *dest, const void *src, const var_type_def_t *def) +{ + if (BUG(!def)) + return -1; + if (def->fns->copy) { + // If we have been provided a copy fuction, use it. + return def->fns->copy(dest, src, def); + } + + // Otherwise, encode 'src' and parse the result into 'def'. + char *enc = typed_var_encode_ex(src, def); + if (!enc) { + typed_var_free_ex(dest, def); + return 0; + } + char *err = NULL; + int rv = typed_var_assign_ex(dest, enc, &err, def); + if (BUG(rv < 0)) { + log_warn(LD_BUG, "Encoded value %s was not parseable as a %s: %s", + escaped(enc), def->name, err?err:""); + } + tor_free(err); + tor_free(enc); + return rv; +} + +/** + * Return true if a and b are semantically equivalent. + * Both types must be as defined by def. + **/ +bool +typed_var_eq_ex(const void *a, const void *b, const var_type_def_t *def) +{ + if (BUG(!def)) + return false; + + if (def->fns->eq) { + // Use a provided eq function if we got one. + return def->fns->eq(a, b, def->params); + } + + // Otherwise, encode the values and compare them. + char *enc_a = typed_var_encode_ex(a, def); + char *enc_b = typed_var_encode_ex(b, def); + bool eq = !strcmp_opt(enc_a,enc_b); + tor_free(enc_a); + tor_free(enc_b); + return eq; +} + +/** + * Check whether value encodes a valid value according to the + * type definition in def. + */ +bool +typed_var_ok_ex(const void *value, const var_type_def_t *def) +{ + if (BUG(!def)) + return false; + + if (def->fns->ok) + return def->fns->ok(value, def->params); + + return true; +} + +/* ===== + * The functions below take a config_type_t instead of a var_type_def_t. + * I'd like to deprecate them eventually and use var_type_def_t everywhere, + * but for now they make migration easier. + * ===== */ + +/** + * As typed_var_assign_ex(), but look up the definition of the configuration + * type from a provided config_type_t enum. + */ +int +typed_var_assign(void *target, const char *value, char **errmsg, + config_type_t type) +{ + const var_type_def_t *def = lookup_type_def(type); + return typed_var_assign_ex(target, value, errmsg, def); +} + +/** + * As typed_var_kvassign_ex(), but look up the definition of the configuration + * type from a provided config_type_t enum. + */ +int +typed_var_kvassign(void *target, const config_line_t *line, char **errmsg, + config_type_t type) +{ + const var_type_def_t *def = lookup_type_def(type); + return typed_var_kvassign_ex(target, line, errmsg, def); +} + +/** + * As typed_var_free_ex(), but look up the definition of the configuration + * type from a provided config_type_t enum. + */ +void +typed_var_free(void *target, config_type_t type) +{ + const var_type_def_t *def = lookup_type_def(type); + return typed_var_free_ex(target, def); +} + +/** + * As typed_var_encode_ex(), but look up the definition of the configuration + * type from a provided config_type_t enum. + */ +char * +typed_var_encode(const void *value, config_type_t type) +{ + const var_type_def_t *def = lookup_type_def(type); + return typed_var_encode_ex(value, def); +} + +/** + * As typed_var_kvencode_ex(), but look up the definition of the configuration + * type from a provided config_type_t enum. + */ +config_line_t * +typed_var_kvencode(const char *key, const void *value, config_type_t type) +{ + const var_type_def_t *def = lookup_type_def(type); + return typed_var_kvencode_ex(key, value, def); +} + +/** + * As typed_var_copy_ex(), but look up the definition of the configuration type + * from a provided config_type_t enum. + */ +int +typed_var_copy(void *dest, const void *src, config_type_t type) +{ + const var_type_def_t *def = lookup_type_def(type); + return typed_var_copy_ex(dest, src, def); +} + +/** + * As typed_var_eq_ex(), but look up the definition of the configuration type + * from a provided config_type_t enum. + */ +bool +typed_var_eq(const void *a, const void *b, config_type_t type) +{ + const var_type_def_t *def = lookup_type_def(type); + return typed_var_eq_ex(a, b, def); +} + +/** + * As typed_var_ok_ex(), but look up the definition of the configuration type + * from a provided config_type_t enum. + */ +bool +typed_var_ok(const void *value, config_type_t type) +{ + const var_type_def_t *def = lookup_type_def(type); + return typed_var_ok_ex(value, def); +} diff --git a/src/lib/confmgt/typedvar.h b/src/lib/confmgt/typedvar.h new file mode 100644 index 0000000000..720ad54fc6 --- /dev/null +++ b/src/lib/confmgt/typedvar.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file typedvar.h + * @brief Header for lib/confmgt/typedvar.c + **/ + +#ifndef TOR_LIB_CONFMGT_TYPEDVAR_H +#define TOR_LIB_CONFMGT_TYPEDVAR_H + +#include + +enum config_type_t; +struct config_line_t; + +typedef struct var_type_fns_t var_type_fns_t; +typedef struct var_type_def_t var_type_def_t; + +int typed_var_assign(void *target, const char *value, char **errmsg, + enum config_type_t type); +void typed_var_free(void *target, enum config_type_t type); +char *typed_var_encode(const void *value, enum config_type_t type); +int typed_var_copy(void *dest, const void *src, enum config_type_t type); +bool typed_var_eq(const void *a, const void *b, enum config_type_t type); +bool typed_var_ok(const void *value, enum config_type_t type); + +int typed_var_kvassign(void *target, const struct config_line_t *line, + char **errmsg, enum config_type_t type); +struct config_line_t *typed_var_kvencode(const char *key, const void *value, + enum config_type_t type); + +int typed_var_assign_ex(void *target, const char *value, char **errmsg, + const var_type_def_t *def); +void typed_var_free_ex(void *target, const var_type_def_t *def); +char *typed_var_encode_ex(const void *value, const var_type_def_t *def); +int typed_var_copy_ex(void *dest, const void *src, const var_type_def_t *def); +bool typed_var_eq_ex(const void *a, const void *b, const var_type_def_t *def); +bool typed_var_ok_ex(const void *value, const var_type_def_t *def); + +int typed_var_kvassign_ex(void *target, const struct config_line_t *line, + char **errmsg, const var_type_def_t *def); +struct config_line_t *typed_var_kvencode_ex(const char *key, const void *value, + const var_type_def_t *def); + +#endif /* !defined(TOR_LIB_CONFMGT_TYPEDVAR_H) */ diff --git a/src/lib/confmgt/var_type_def_st.h b/src/lib/confmgt/var_type_def_st.h new file mode 100644 index 0000000000..c63ff66eff --- /dev/null +++ b/src/lib/confmgt/var_type_def_st.h @@ -0,0 +1,147 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file typedvar.h + * @brief Structure declarations for typedvar type definitions. + * + * This structure is used for defining new variable types. If you are not + * defining a new variable type for use by the configuration management + * system, you don't need this structure. + * + * For defining new variables, see the types in conftypes.h. + * + * For data-driven access to configuration variables, see the other members of + * lib/confmgt/. + * + * STATUS NOTE: It is not yet possible to actually define new variables + * outside of config.c, and many of the types that will eventually be used + * to do so are not yet moved. This will change as more of #29211 is + * completed. + **/ + +#ifndef TOR_LIB_CONFMGT_VAR_TYPE_DEF_ST_H +#define TOR_LIB_CONFMGT_VAR_TYPE_DEF_ST_H + +#include + +struct config_line_t; + +/** + * A structure full of functions pointers to implement a variable type. + * + * Every type MUST implement parse or kv_parse and encode or kv_encode; + * the other functions pointers MAY be NULL. + * + * All functions here take a params argument, whose value + * is determined by the type definition. Two types may have the + * same functions, but differ only in parameters. + **/ +struct var_type_fns_t { + /** + * Try to parse a string in value that encodes an object of this + * type. On success, adjust the lvalue pointed to by target to hold + * that value, and return 0. On failure, set *errmsg to a newly + * allocated string holding an error message, and return -1. + **/ + int (*parse)(void *target, const char *value, char **errmsg, + const void *params); + /** + * Try to parse a single line from the head ofline that encodes + * an object of this type. On success and failure, behave as in the parse() + * function. + * + * If this function is absent, it is implemented in terms of parse(). + * + * All types for which keys are significant should use this method. For + * example, a "linelist" type records the actual keys that are given + * for each line, and so should use this method. + * + * Note that although multiple lines may be provided in line, + * only the first one should be handled by this function. + **/ + int (*kv_parse)(void *target, const struct config_line_t *line, + char **errmsg, const void *params); + /** + * Encode a value pointed to by value and return its result + * in a newly allocated string. The string may need to be escaped. + * + * If this function is absent, it is implemented in terms of kv_encode(). + * + * Returns NULL if this option has a NULL value, or on internal error. + * + * Requirement: all strings generated by encode() should produce a + * semantically equivalent value when given to parse(). + **/ + char *(*encode)(const void *value, const void *params); + /** + * As encode(), but returns a newly allocated config_line_t object. The + * provided key is used as the key of the lines, unless the type is + * one that encodes its own keys. + * + * Unlike kv_parse(), this function will return a list of multiple lines, + * if value is such that it must be encoded by multiple lines. + * + * Returns NULL if there are no lines to encode, or on internal error. + * + * If this function is absent, it is implemented in terms of encode(). + **/ + struct config_line_t *(*kv_encode)(const char *key, const void *value, + const void *params); + /** + * Free all storage held in arg, and set arg to a default + * value -- usually zero or NULL. + * + * If this function is absent, the default implementation does nothing. + **/ + void (*clear)(void *arg, const void *params); + /** + * Return true if a and b hold the same value, and false + * otherwise. + * + * If this function is absent, it is implemented by encoding both a and + * b and comparing their encoded strings for equality. + **/ + bool (*eq)(const void *a, const void *b, const void *params); + /** + * Try to copy the value from value into target. + * On success return 0; on failure return -1. + * + * If this function is absent, it is implemented by encoding the value + * into a string, and then parsing it into the target. + **/ + int (*copy)(void *target, const void *value, const void *params); + /** + * Check whether value holds a valid value according to the + * rules of this type; return true if it does and false if it doesn't. + * + * The default implementation for this function assumes that all + * values are valid. + **/ + bool (*ok)(const void *value, const void *params); +}; + +/** + * A structure describing a type that can be manipulated with the typedvar_* + * functions. + **/ +struct var_type_def_t { + /** + * The name of this type. Should not include spaces. Used for + * debugging, log messages, and the controller API. */ + const char *name; + /** + * A function table for this type. + */ + const struct var_type_fns_t *fns; + /** + * A pointer to a value that should be passed as the 'params' argument when + * calling the functions in this type's function table. + */ + const void *params; +}; + +#endif /* !defined(TOR_LIB_CONFMGT_VAR_TYPE_DEF_ST_H) */ diff --git a/src/test/test_confparse.c b/src/test/test_confparse.c index 89a6eb5265..fef361ef65 100644 --- a/src/test/test_confparse.c +++ b/src/test/test_confparse.c @@ -469,9 +469,9 @@ static const badval_test_t bv_badcsvi2 = { "csv_interval cl,10\n", "malformed" }; static const badval_test_t bv_nonoption = { "fnord 10\n", "Unknown option" }; static const badval_test_t bv_badmem = { "mem 3 trits\n", "malformed" }; -static const badval_test_t bv_badbool = { "boolean 7\n", "expects 0 or 1" }; +static const badval_test_t bv_badbool = { "boolean 7\n", "Unrecognized value"}; static const badval_test_t bv_badabool = - { "autobool 7\n", "expects 0, 1, or 'auto'" }; + { "autobool 7\n", "Unrecognized value" }; static const badval_test_t bv_badtime = { "time lunchtime\n", "Invalid time" }; static const badval_test_t bv_virt = { "MixedLines 7\n", "virtual option" }; static const badval_test_t bv_rs = { "Routerset 2.2.2.2.2\n", "Invalid" }; diff --git a/src/test/test_options.c b/src/test/test_options.c index d693fe0568..b39cd4f1e4 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -258,13 +258,17 @@ test_options_validate(void *arg) WANT_ERR("BridgeRelay 1\nDirCache 0", "We're a bridge but DirCache is disabled.", PH_VALIDATE); + // XXXX We should replace this with a more full error message once #29211 + // XXXX is done. It is truncated for now because at the current stage + // XXXX of refactoring, we can't give a full error message like before. WANT_ERR_LOG("HeartbeatPeriod 21 snarks", - "Interval 'HeartbeatPeriod 21 snarks' is malformed or" - " out of bounds.", LOG_WARN, "Unknown unit 'snarks'.", + "malformed or out of bounds", LOG_WARN, + "Unknown unit 'snarks'.", PH_ASSIGN); + // XXXX As above. WANT_ERR_LOG("LogTimeGranularity 21 snarks", - "Msec interval 'LogTimeGranularity 21 snarks' is malformed or" - " out of bounds.", LOG_WARN, "Unknown unit 'snarks'.", + "malformed or out of bounds", LOG_WARN, + "Unknown unit 'snarks'.", PH_ASSIGN); OK("HeartbeatPeriod 1 hour", PH_VALIDATE); OK("LogTimeGranularity 100 milliseconds", PH_VALIDATE); -- cgit v1.2.3-54-g00ecf From 3644f4ab5f4c10e95f6ea6db26764054c73ce594 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 25 Jun 2019 11:57:08 -0400 Subject: Remove changes files that appeared in 0.4.1.3-alpha or earlier. --- changes/bug22619 | 3 --- changes/bug29034 | 5 ----- changes/bug30713 | 5 ----- changes/bug30744 | 3 --- changes/bug30781 | 4 ---- changes/bug30956 | 4 ---- changes/doc30630 | 3 --- changes/geoip-2019-06-10 | 4 ---- changes/ticket30686 | 5 ----- 9 files changed, 36 deletions(-) delete mode 100644 changes/bug22619 delete mode 100644 changes/bug29034 delete mode 100644 changes/bug30713 delete mode 100644 changes/bug30744 delete mode 100644 changes/bug30781 delete mode 100644 changes/bug30956 delete mode 100644 changes/doc30630 delete mode 100644 changes/geoip-2019-06-10 delete mode 100644 changes/ticket30686 (limited to 'changes') diff --git a/changes/bug22619 b/changes/bug22619 deleted file mode 100644 index 9c71996f5b..0000000000 --- a/changes/bug22619 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (circuit isolation): - - Fix a logic error that prevented the SessionGroup sub-option from - being accepted. Fixes bug 22619; bugfix on 0.2.7.2-alpha. diff --git a/changes/bug29034 b/changes/bug29034 deleted file mode 100644 index e7aa9af00b..0000000000 --- a/changes/bug29034 +++ /dev/null @@ -1,5 +0,0 @@ - o Major bugfixes (Onion service reachability): - - Properly clean up the introduction point map when circuits change purpose - from onion service circuits to pathbias, measurement, or other circuit types. - This should fix some service-side instances of introduction point failure. - Fixes bug 29034; bugfix on 0.3.2.1-alpha. diff --git a/changes/bug30713 b/changes/bug30713 deleted file mode 100644 index e00b98da65..0000000000 --- a/changes/bug30713 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (testing): - - Skip test_rebind when the TOR_SKIP_TEST_REBIND environmental variable is - set. Fixes bug 30713; bugfix on 0.3.5.1-alpha. - - Skip test_rebind on macOS in Travis, because it is unreliable on - macOS on Travis. Fixes bug 30713; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug30744 b/changes/bug30744 deleted file mode 100644 index 9f07d4855f..0000000000 --- a/changes/bug30744 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (continuous integration): - - Allow the test-stem job to fail in Travis, because it sometimes hangs. - Fixes bug 30744; bugfix on 0.3.5.4-alpha. diff --git a/changes/bug30781 b/changes/bug30781 deleted file mode 100644 index 7c7adf470e..0000000000 --- a/changes/bug30781 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (directory authorities): - - Stop crashing after parsing an unknown descriptor purpose annotation. - We think this bug can only be triggered by modifying a local file. - Fixes bug 30781; bugfix on 0.2.0.8-alpha. diff --git a/changes/bug30956 b/changes/bug30956 deleted file mode 100644 index 8f52a81de3..0000000000 --- a/changes/bug30956 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (pluggable transports): - - Always publish bridge pluggable transport information in the extra info - descriptor, even if ExtraInfoStatistics is 0. This information is - needed by BridgeDB. Fixes bug 30956; bugfix on 0.4.1.1-alpha. diff --git a/changes/doc30630 b/changes/doc30630 deleted file mode 100644 index 0fbd8d4dd4..0000000000 --- a/changes/doc30630 +++ /dev/null @@ -1,3 +0,0 @@ - o Documentation: - - Mention URLs for Travis/Appveyor/Jenkins in ReleasingTor.md. Closes - ticket 30630. diff --git a/changes/geoip-2019-06-10 b/changes/geoip-2019-06-10 deleted file mode 100644 index 2d1e065649..0000000000 --- a/changes/geoip-2019-06-10 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (geoip): - - Update geoip and geoip6 to the June 10 2019 Maxmind GeoLite2 - Country database. Closes ticket 30852. - diff --git a/changes/ticket30686 b/changes/ticket30686 deleted file mode 100644 index 36473c1a02..0000000000 --- a/changes/ticket30686 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (logging): - - Give a more useful assertion failure message if we think we have - minherit() but we fail to make a region non-inheritable. Give a - compile-time warning if our support for minherit() is - incomplete. Closes ticket 30686. -- cgit v1.2.3-54-g00ecf From 5612eccef877455769f495f088f86f6e268dfd2d Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Tue, 25 Jun 2019 11:38:36 -0500 Subject: Changes file for ticket 30889 --- changes/ticket30889 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket30889 (limited to 'changes') diff --git a/changes/ticket30889 b/changes/ticket30889 new file mode 100644 index 0000000000..8582e2bcac --- /dev/null +++ b/changes/ticket30889 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Eliminate some uses of lower-level control reply abstractions, + primarily in the onion_helper functions. Closes ticket 30889. -- cgit v1.2.3-54-g00ecf From e8790971f6120cc3e4fd2acd41f5dd0512f52068 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 19 Jun 2019 16:24:07 -0400 Subject: changes file for ticket 30914 --- changes/ticket30914 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket30914 (limited to 'changes') diff --git a/changes/ticket30914 b/changes/ticket30914 new file mode 100644 index 0000000000..c8c008b3d1 --- /dev/null +++ b/changes/ticket30914 @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Lower another layer of object management from confparse.c to + a more general tool. Now typed structure members are accessible + via an abstract type. Implements ticket 30914. -- cgit v1.2.3-54-g00ecf From cd1de99468aa4d7b48c9f3bcb7c7d4fb5b3bfe9a Mon Sep 17 00:00:00 2001 From: teor Date: Sun, 2 Jun 2019 17:46:58 +1000 Subject: resolve: consistently parse IP addresses in square brackets When parsing addreses via Tor's internal DNS lookup API: * reject IPv4 addresses in square brackets (with or without a port), * accept IPv6 addresses in square brackets (with or without a port), and * accept IPv6 addresses without square brackets, as long as they have no port. This change completes the work started in 23082, making address parsing consistent between tor's internal DNS lookup and address parsing APIs. Fixes bug 30721; bugfix on 0.2.1.5-alpha. --- changes/bug30721 | 6 +++++ src/lib/net/address.c | 31 +++++++++++++++++---- src/lib/net/resolve.c | 75 ++++++++++++++++++++++++++------------------------- 3 files changed, 70 insertions(+), 42 deletions(-) create mode 100644 changes/bug30721 (limited to 'changes') diff --git a/changes/bug30721 b/changes/bug30721 new file mode 100644 index 0000000000..5e03653005 --- /dev/null +++ b/changes/bug30721 @@ -0,0 +1,6 @@ + o Minor bugfixes (networking): + - When parsing addreses via Tor's internal DNS lookup API, reject IPv4 + addresses in square brackets, and accept IPv6 addresses in square + brackets. This change completes the work started in 23082, making + address parsing consistent between tor's internal DNS lookup and address + parsing APIs. Fixes bug 30721; bugfix on 0.2.1.5-alpha. diff --git a/src/lib/net/address.c b/src/lib/net/address.c index 546af800a9..4989e4ab2b 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -373,7 +373,8 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate) * * If accept_regular is set and the address is in neither recognized * reverse lookup hostname format, try parsing the address as a regular - * IPv4 or IPv6 address too. + * IPv4 or IPv6 address too. This mode will accept IPv6 addresses with or + * without square brackets. */ int tor_addr_parse_PTR_name(tor_addr_t *result, const char *address, @@ -1204,6 +1205,10 @@ tor_addr_parse(tor_addr_t *addr, const char *src) tor_assert(addr && src); + /* Clear the address before starting, to avoid returning uninitialised data. + */ + memset(addr, 0, sizeof(tor_addr_t)); + size_t len = strlen(src); if (len && src[0] == '[' && src[len - 1] == ']') { @@ -1718,6 +1723,11 @@ get_interface_address6_list,(int severity, * form "ip" or "ip:0". Otherwise, accept those forms, and set * *port_out to default_port. * + * This function accepts: + * - IPv6 address and port, when the IPv6 address is in square brackets, + * - IPv6 address with square brackets, + * - IPv6 address without square brackets. + * * Return 0 on success, -1 on failure. */ int tor_addr_port_parse(int severity, const char *addrport, @@ -1755,9 +1765,17 @@ tor_addr_port_parse(int severity, const char *addrport, } /** Given an address of the form "host[:port]", try to divide it into its host - * and port portions, setting *address_out to a newly allocated string - * holding the address portion and *port_out to the port (or 0 if no - * port is given). Return 0 on success, -1 on failure. */ + * and port portions. + * + * Like tor_addr_port_parse(), this function accepts: + * - IPv6 address and port, when the IPv6 address is in square brackets, + * - IPv6 address with square brackets, + * - IPv6 address without square brackets. + * + * Sets *address_out to a newly allocated string holding the address + * portion, and *port_out to the port (or 0 if no port is given). + * + * Return 0 on success, -1 on failure. */ int tor_addr_port_split(int severity, const char *addrport, char **address_out, uint16_t *port_out) @@ -1766,8 +1784,11 @@ tor_addr_port_split(int severity, const char *addrport, tor_assert(addrport); tor_assert(address_out); tor_assert(port_out); + /* We need to check for IPv6 manually because the logic below doesn't - * do a good job on IPv6 addresses that lack a port. */ + * do a good job on IPv6 addresses that lack a port. + * If an IPv6 address without square brackets is ambiguous, it gets parsed + * here as an address, rather than address:port. */ if (tor_addr_parse(&a_tmp, addrport) == AF_INET6) { *port_out = 0; *address_out = tor_strdup(addrport); diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c index 49c263faa2..71c033fe7a 100644 --- a/src/lib/net/resolve.c +++ b/src/lib/net/resolve.c @@ -35,6 +35,8 @@ * *addr to the proper IP address, in host byte order. Returns 0 * on success, -1 on failure; 1 on transient failure. * + * This function only accepts IPv4 addresses. + * * (This function exists because standard windows gethostbyname * doesn't treat raw IP addresses properly.) */ @@ -62,6 +64,9 @@ tor_lookup_hostname,(const char *name, uint32_t *addr)) * preferred family, though another one may be returned if only one * family is implemented for this address. * + * Like tor_addr_parse(), this function accepts IPv6 addresses with or without + * square brackets. + * * Return 0 on success, -1 on failure; 1 on transient failure. */ MOCK_IMPL(int, @@ -70,26 +75,39 @@ tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr)) /* Perhaps eventually this should be replaced by a tor_getaddrinfo or * something. */ - struct in_addr iaddr; - struct in6_addr iaddr6; + int parsed_family = 0; + tor_assert(name); tor_assert(addr); tor_assert(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC); + + /* Clear address before starting, to avoid returning uninitialised data */ + memset(addr, 0, sizeof(tor_addr_t)); + if (!*name) { /* Empty address is an error. */ return -1; - } else if (tor_inet_pton(AF_INET, name, &iaddr)) { + } + + /* Is it an IP address? */ + parsed_family = tor_addr_parse(addr, name); + + if (parsed_family == AF_INET) { /* It's an IPv4 IP. */ - if (family == AF_INET6) + if (family == AF_INET6) { + memset(addr, 0, sizeof(tor_addr_t)); return -1; - tor_addr_from_in(addr, &iaddr); + } return 0; - } else if (tor_inet_pton(AF_INET6, name, &iaddr6)) { - if (family == AF_INET) + } else if (parsed_family == AF_INET6) { + if (family == AF_INET) { + memset(addr, 0, sizeof(tor_addr_t)); return -1; - tor_addr_from_in6(addr, &iaddr6); + } return 0; } else { + /* Clear the address after a failed tor_addr_parse(). */ + memset(addr, 0, sizeof(tor_addr_t)); #ifdef HAVE_GETADDRINFO int err; struct addrinfo *res=NULL, *res_p; @@ -179,52 +197,35 @@ tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr)) /** Parse an address or address-port combination from s, resolve the * address as needed, and put the result in addr_out and (optionally) - * port_out. Return 0 on success, negative on failure. */ + * port_out. + * + * Like tor_addr_port_parse(), this function accepts: + * - IPv6 address and port, when the IPv6 address is in square brackets, + * - IPv6 address with square brackets, + * - IPv6 address without square brackets. + * + * Return 0 on success, negative on failure. */ int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out) { - const char *port; tor_addr_t addr; uint16_t portval; char *tmp = NULL; + int rv = 0; tor_assert(s); tor_assert(addr_out); s = eat_whitespace(s); - if (*s == '[') { - port = strstr(s, "]"); - if (!port) - goto err; - tmp = tor_strndup(s+1, port-(s+1)); - port = port+1; - if (*port == ':') - port++; - else - port = NULL; - } else { - port = strchr(s, ':'); - if (port) - tmp = tor_strndup(s, port-s); - else - tmp = tor_strdup(s); - if (port) - ++port; - } + rv = tor_addr_port_split(LOG_WARN, s, &tmp, &portval); + if (rv < 0) + goto err; if (tor_addr_lookup(tmp, AF_UNSPEC, &addr) != 0) goto err; tor_free(tmp); - if (port) { - portval = (int) tor_parse_long(port, 10, 1, 65535, NULL, NULL); - if (!portval) - goto err; - } else { - portval = 0; - } - if (port_out) *port_out = portval; tor_addr_copy(addr_out, &addr); -- cgit v1.2.3-54-g00ecf From adb8538e7b6a7a2531233797990f6d11be86a718 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 13 Jun 2019 21:21:19 +1000 Subject: address/resolve: Require square brackets on IPv6 address:ports When parsing addreses via Tor's internal address:port parsing and DNS lookup APIs, require IPv6 addresses with ports to have square brackets. But allow IPv6 addresses without ports, whether or not they have square brackets. Fixes bug 30721; bugfix on 0.2.1.5-alpha. --- changes/bug30721 | 6 +++- src/lib/net/address.c | 77 ++++++++++++++++++++++++++++++++++++--------------- src/lib/net/resolve.c | 40 ++++++++++++++++++++++++-- 3 files changed, 96 insertions(+), 27 deletions(-) (limited to 'changes') diff --git a/changes/bug30721 b/changes/bug30721 index 5e03653005..5ea4a14625 100644 --- a/changes/bug30721 +++ b/changes/bug30721 @@ -1,6 +1,10 @@ - o Minor bugfixes (networking): + o Minor bugfixes (networking, IP addresses): - When parsing addreses via Tor's internal DNS lookup API, reject IPv4 addresses in square brackets, and accept IPv6 addresses in square brackets. This change completes the work started in 23082, making address parsing consistent between tor's internal DNS lookup and address parsing APIs. Fixes bug 30721; bugfix on 0.2.1.5-alpha. + - When parsing addreses via Tor's internal address:port parsing and + DNS lookup APIs, require IPv6 addresses with ports to have square + brackets. But allow IPv6 addresses without ports, whether or not they + have square brackets. Fixes bug 30721; bugfix on 0.2.1.5-alpha. diff --git a/src/lib/net/address.c b/src/lib/net/address.c index 75322ad886..0a2c84caf2 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -1188,27 +1188,28 @@ fmt_addr32(uint32_t addr) } /** Convert the string in src to a tor_addr_t addr. The string - * may be an IPv4 address, an IPv6 address, or an IPv6 address surrounded by - * square brackets. + * may be an IPv4 address, or an IPv6 address surrounded by square brackets. * - * Return an address family on success, or -1 if an invalid address string is - * provided. */ -int -tor_addr_parse(tor_addr_t *addr, const char *src) + * If allow_ipv6_without_brackets is true, also allow IPv6 addresses + * without brackets. + * + * Always rejects IPv4 addresses with brackets. + * + * Returns an address family on success, or -1 if an invalid address string is + * provided. */ +static int +tor_addr_parse_impl(tor_addr_t *addr, const char *src, + bool allow_ipv6_without_brackets) { /* Holds substring of IPv6 address after removing square brackets */ char *tmp = NULL; - int result; + int result = -1; struct in_addr in_tmp; struct in6_addr in6_tmp; int brackets_detected = 0; tor_assert(addr && src); - /* Clear the address before starting, to avoid returning uninitialised data. - */ - memset(addr, 0, sizeof(tor_addr_t)); - size_t len = strlen(src); if (len && src[0] == '[' && src[len - 1] == ']') { @@ -1216,21 +1217,46 @@ tor_addr_parse(tor_addr_t *addr, const char *src) src = tmp = tor_strndup(src+1, strlen(src)-2); } - if (tor_inet_pton(AF_INET6, src, &in6_tmp) > 0) { - result = AF_INET6; - tor_addr_from_in6(addr, &in6_tmp); - } else if (!brackets_detected && - tor_inet_pton(AF_INET, src, &in_tmp) > 0) { - result = AF_INET; - tor_addr_from_in(addr, &in_tmp); - } else { - result = -1; + /* Try to parse an IPv6 address if it has brackets, or if IPv6 addresses + * without brackets are allowed */ + if (brackets_detected || allow_ipv6_without_brackets) { + if (tor_inet_pton(AF_INET6, src, &in6_tmp) > 0) { + result = AF_INET6; + tor_addr_from_in6(addr, &in6_tmp); + } + } + + /* Try to parse an IPv4 address without brackets */ + if (!brackets_detected) { + if (tor_inet_pton(AF_INET, src, &in_tmp) > 0) { + result = AF_INET; + tor_addr_from_in(addr, &in_tmp); + } + } + + /* Clear the address on error, to avoid returning uninitialised or partly + * parsed data. + */ + if (result == -1) { + memset(addr, 0, sizeof(tor_addr_t)); } tor_free(tmp); return result; } +/** Convert the string in src to a tor_addr_t addr. The string + * may be an IPv4 address, an IPv6 address, or an IPv6 address surrounded by + * square brackets. + * + * Returns an address family on success, or -1 if an invalid address string is + * provided. */ +int +tor_addr_parse(tor_addr_t *addr, const char *src) +{ + return tor_addr_parse_impl(addr, src, 1); +} + #ifdef HAVE_IFADDRS_TO_SMARTLIST /* * Convert a linked list consisting of ifaddrs structures @@ -1737,6 +1763,7 @@ tor_addr_port_parse(int severity, const char *addrport, int retval = -1; int r; char *addr_tmp = NULL; + bool has_port; tor_assert(addrport); tor_assert(address_out); @@ -1746,15 +1773,19 @@ tor_addr_port_parse(int severity, const char *addrport, if (r < 0) goto done; - if (!*port_out) { + has_port = !! *port_out; + /* If there's no port, use the default port, or fail if there is no default + */ + if (!has_port) { if (default_port >= 0) *port_out = default_port; else goto done; } - /* make sure that address_out is an IP address */ - if (tor_addr_parse(address_out, addr_tmp) < 0) + /* Make sure that address_out is an IP address. + * If there is no port in addrport, allow IPv6 addresses without brackets. */ + if (tor_addr_parse_impl(address_out, addr_tmp, !has_port) < 0) goto done; retval = 0; diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c index 9555720883..1097e36bd8 100644 --- a/src/lib/net/resolve.c +++ b/src/lib/net/resolve.c @@ -258,32 +258,66 @@ tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out) uint16_t portval = 0; char *tmp = NULL; int rv = 0; + int result; tor_assert(s); tor_assert(addr_out); s = eat_whitespace(s); + /* Try parsing s as an address:port first, so we don't have to duplicate + * the logic that rejects IPv6:Port with no square brackets. */ + rv = tor_addr_port_parse(LOG_WARN, s, &addr, &portval, 0); + /* That was easy, no DNS required. */ + if (rv == 0) + goto success; + + /* Now let's check for malformed IPv6 addresses and ports: + * tor_addr_port_parse() requires squared brackes if there is a port, + * and we want tor_addr_port_lookup() to have the same requirement. + * But we strip the port using tor_addr_port_split(), so tor_addr_lookup() + * only sees the address, and will accept it without square brackets. */ + int family = tor_addr_parse(&addr, s); + /* If tor_addr_parse() succeeds where tor_addr_port_parse() failed, we need + * to reject this address as malformed. */ + if (family >= 0) { + /* Double-check it's an IPv6 address. If not, we have a parsing bug. + */ + tor_assertf_nonfatal(family == AF_INET6, + "Wrong family: %d (should be IPv6: %d) which " + "failed IP:port parsing, but passed IP parsing. " + "input string: '%s'; parsed address: '%s'.", + family, AF_INET6, s, fmt_addr(&addr)); + goto err; + } + + /* Now we have a hostname. Let's split off the port, if any. */ rv = tor_addr_port_split(LOG_WARN, s, &tmp, &portval); if (rv < 0) goto err; + /* And feed the hostname to the lookup function. */ if (tor_addr_lookup(tmp, AF_UNSPEC, &addr) != 0) goto err; - tor_free(tmp); + success: if (port_out) *port_out = portval; tor_addr_copy(addr_out, &addr); + result = 0; + goto done; - return 0; err: /* Clear the address and port on error */ memset(addr_out, 0, sizeof(tor_addr_t)); if (port_out) *port_out = 0; + result = -1; + + /* We have set the result, now it's time to clean up */ + done: tor_free(tmp); - return -1; + return result; } #ifdef USE_SANDBOX_GETADDRINFO -- cgit v1.2.3-54-g00ecf From 362afa8c4e9fc2afeef703950e1f9c715cd1aef4 Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 24 Jun 2019 13:50:26 +1000 Subject: doc: update the man page entries for DirAuthority and FallbackDir Improve the documentation for the DirAuthority and FallbackDir torrc options. Closes ticket 30955. --- changes/ticket30955 | 3 +++ doc/tor.1.txt | 45 +++++++++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 20 deletions(-) create mode 100644 changes/ticket30955 (limited to 'changes') diff --git a/changes/ticket30955 b/changes/ticket30955 new file mode 100644 index 0000000000..7715a07569 --- /dev/null +++ b/changes/ticket30955 @@ -0,0 +1,3 @@ + o Documentation (hard-coded directories): + - Improve the documentation for the DirAuthority and FallbackDir torrc + options. Closes ticket 30955. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 064259b15f..dc261cb9c9 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -447,13 +447,18 @@ GENERAL OPTIONS setting for DataDirectoryGroupReadable when the CacheDirectory is the same as the DataDirectory, and 0 otherwise. (Default: auto) -[[FallbackDir]] **FallbackDir** __ipv4address__:__port__ orport=__port__ id=__fingerprint__ [weight=__num__] [ipv6=**[**__ipv6address__**]**:__orport__]:: - When we're unable to connect to any directory cache for directory info - (usually because we don't know about any yet) we try a directory authority. - Clients also simultaneously try a FallbackDir, to avoid hangs on client - startup if a directory authority is down. Clients retry FallbackDirs more - often than directory authorities, to reduce the load on the directory - authorities. +[[FallbackDir]] **FallbackDir** __ipv4address__:__dirport__ orport=__orport__ id=__fingerprint__ [weight=__num__] [ipv6=**[**__ipv6address__**]**:__orport__]:: + When tor is unable to connect to any directory cache for directory info + (usually because it doesn't know about any yet) it tries a hard-coded + directory. Relays try one directory authority at a time. Clients try + multiple directory authorities and FallbackDirs, to avoid hangs on + startup if a hard-coded directory is down. Clients wait for a few seconds + between each attempt, and retry FallbackDirs more often than directory + authorities, to reduce the load on the directory authorities. + + + + FallbackDirs should be stable relays with stable IP addresses, ports, + and identity keys. They must have a DirPort. + + + By default, the directory authorities are also FallbackDirs. Specifying a FallbackDir replaces Tor's default hard-coded FallbackDirs (if any). (See the **DirAuthority** entry for an explanation of each flag.) @@ -463,30 +468,30 @@ GENERAL OPTIONS FallbackDir line is present, it replaces the hard-coded FallbackDirs, regardless of the value of UseDefaultFallbackDirs.) (Default: 1) -[[DirAuthority]] **DirAuthority** [__nickname__] [**flags**] __ipv4address__:__port__ __fingerprint__:: +[[DirAuthority]] **DirAuthority** [__nickname__] [**flags**] __ipv4address__:__dirport__ __fingerprint__:: Use a nonstandard authoritative directory server at the provided address and port, with the specified key fingerprint. This option can be repeated many times, for multiple authoritative directory servers. Flags are separated by spaces, and determine what kind of an authority this directory is. By default, an authority is not authoritative for any directory style - or version unless an appropriate flag is given. + or version unless an appropriate flag is given. + + + Tor will use this authority as a bridge authoritative directory if the - "bridge" flag is set. If a flag "orport=**port**" is given, Tor will use the - given port when opening encrypted tunnels to the dirserver. If a flag - "weight=**num**" is given, then the directory server is chosen randomly - with probability proportional to that weight (default 1.0). If a + "bridge" flag is set. If a flag "orport=**orport**" is given, Tor will + use the given port when opening encrypted tunnels to the dirserver. If a + flag "weight=**num**" is given, then the directory server is chosen + randomly with probability proportional to that weight (default 1.0). If a flag "v3ident=**fp**" is given, the dirserver is a v3 directory authority whose v3 long-term signing key has the fingerprint **fp**. Lastly, if an "ipv6=**[**__ipv6address__**]**:__orport__" flag is present, then - the directory - authority is listening for IPv6 connections on the indicated IPv6 address - and OR Port. + + the directory authority is listening for IPv6 connections on the + indicated IPv6 address and OR Port. + + Tor will contact the authority at __ipv4address__ to - download directory documents. The provided __port__ value is a dirport; - clients ignore this in favor of the specified "orport=" value. If an - IPv6 ORPort is supplied, Tor will - also download directory documents at the IPv6 ORPort. + + download directory documents. Clients always use the ORPort. Relays + usually use the DirPort, but will use the ORPort in some circumstances. + If an IPv6 ORPort is supplied, clients will also download directory + documents at the IPv6 ORPort, if they are configured to use IPv6. + + If no **DirAuthority** line is given, Tor will use the default directory authorities. NOTE: this option is intended for setting up a private Tor -- cgit v1.2.3-54-g00ecf From f446db59e1fc3f87f1312defbb12894ad006d978 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 27 Jun 2019 14:47:11 -0400 Subject: man: Fix -help typo to --help Signed-off-by: David Goulet --- changes/ticket31008 | 3 +++ doc/tor.1.txt | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/ticket31008 (limited to 'changes') diff --git a/changes/ticket31008 b/changes/ticket31008 new file mode 100644 index 0000000000..c7077de6c6 --- /dev/null +++ b/changes/ticket31008 @@ -0,0 +1,3 @@ + o Documentation (tor.1 man page): + - Fix typo -help to --help in tor.1 man page. Fixes bug 31008; bugfix on + 0.2.2.9-alpha. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 975a198182..3909a829b5 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -37,7 +37,7 @@ Project's website. COMMAND-LINE OPTIONS -------------------- -[[opt-h]] **-h**, **-help**:: +[[opt-h]] **-h**, **--help**:: Display a short help message and exit. [[opt-f]] **-f** __FILE__:: -- cgit v1.2.3-54-g00ecf From 0fa3dc3228a32fd21ff71e24e3c2e456e342e3b8 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 28 Jun 2019 11:27:59 -0400 Subject: begin_cell_parse(): Add an assertion to please coverity. Coverity doesn't understand that if begin_cell_parse() returns 0 and sets is_begindir to 0, its address field will always be set. Fixes bug 30126; bugfix on 0.2.4.7-alpha; Fixes CID 1447296. --- changes/ticket31026 | 5 +++++ scripts/maint/practracker/exceptions.txt | 4 ++-- src/core/or/connection_edge.c | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 changes/ticket31026 (limited to 'changes') diff --git a/changes/ticket31026 b/changes/ticket31026 new file mode 100644 index 0000000000..6f6abcffba --- /dev/null +++ b/changes/ticket31026 @@ -0,0 +1,5 @@ + o Minor bugfixes (coverity compliance): + - Add an assertion when parsing a BEGIN cell so that coverity can be sure + that we are not about to dereference a NULL address. + Fixes bug 31026; bugfix on 0.2.4.7-alpha. This is CID + 1447296. diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index 3ed76a2bfd..e29d3b6076 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -101,7 +101,7 @@ problem function-size /src/core/or/circuituse.c:circuit_get_open_circ_or_launch( problem function-size /src/core/or/circuituse.c:connection_ap_handshake_attach_circuit() 244 problem function-size /src/core/or/command.c:command_process_create_cell() 156 problem function-size /src/core/or/command.c:command_process_relay_cell() 132 -problem file-size /src/core/or/connection_edge.c 4595 +problem file-size /src/core/or/connection_edge.c 4596 problem include-count /src/core/or/connection_edge.c 65 problem function-size /src/core/or/connection_edge.c:connection_ap_expire_beginning() 117 problem function-size /src/core/or/connection_edge.c:connection_ap_handshake_rewrite() 192 @@ -109,7 +109,7 @@ problem function-size /src/core/or/connection_edge.c:connection_ap_handle_onion( problem function-size /src/core/or/connection_edge.c:connection_ap_handshake_rewrite_and_attach() 423 problem function-size /src/core/or/connection_edge.c:connection_ap_handshake_send_begin() 111 problem function-size /src/core/or/connection_edge.c:connection_ap_handshake_socks_resolved() 106 -problem function-size /src/core/or/connection_edge.c:connection_exit_begin_conn() 184 +problem function-size /src/core/or/connection_edge.c:connection_exit_begin_conn() 185 problem function-size /src/core/or/connection_edge.c:connection_exit_connect() 102 problem file-size /src/core/or/connection_or.c 3124 problem include-count /src/core/or/connection_or.c 51 diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c index c08d2a9ff5..091d9c9b09 100644 --- a/src/core/or/connection_edge.c +++ b/src/core/or/connection_edge.c @@ -3833,6 +3833,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) if (! bcell.is_begindir) { /* Steal reference */ + tor_assert(bcell.address); address = bcell.address; port = bcell.port; -- cgit v1.2.3-54-g00ecf From f55598f870b2346ed48a32befc51b9a548b8b5fa Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 28 Jun 2019 11:57:36 -0400 Subject: Coverity: different implementation for csiphash Coverity has had trouble figuring out our csiphash implementation, and has given spurious warnings about its behavior. This patch changes the csiphash implementation when coverity is in use, so that coverity can figure out that we are not about to read beyond the provided input. Closes ticket 31025. --- changes/ticket31025 | 5 +++++ src/ext/csiphash.c | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100644 changes/ticket31025 (limited to 'changes') diff --git a/changes/ticket31025 b/changes/ticket31025 new file mode 100644 index 0000000000..c572288239 --- /dev/null +++ b/changes/ticket31025 @@ -0,0 +1,5 @@ + o Minor bugfixes (coverity): + - In our siphash implementation, when building for coverity, use memcpy + in place of a switch statement, so that coverity can tell we are not + accessing out-of-bounds memory. Fixes bug 31025; bugfix on + 0.2.8.1-alpha. This is tracked as CID 1447293 and 1447295. diff --git a/src/ext/csiphash.c b/src/ext/csiphash.c index af8559a476..faa52ae4e1 100644 --- a/src/ext/csiphash.c +++ b/src/ext/csiphash.c @@ -87,6 +87,13 @@ uint64_t siphash24(const void *src, unsigned long src_sz, const struct sipkey *k v0 ^= mi; } +#ifdef __COVERITY__ + { + uint64_t mi = 0; + memcpy(&mi, m+i, (src_sz-blocks)); + last7 = _le64toh(mi) | (uint64_t)(src_sz & 0xff) << 56; + } +#else switch (src_sz - blocks) { case 7: last7 |= (uint64_t)m[i + 6] << 48; /* Falls through. */ case 6: last7 |= (uint64_t)m[i + 5] << 40; /* Falls through. */ @@ -98,6 +105,7 @@ uint64_t siphash24(const void *src, unsigned long src_sz, const struct sipkey *k case 0: default:; } +#endif v3 ^= last7; DOUBLE_ROUND(v0,v1,v2,v3); v0 ^= last7; -- cgit v1.2.3-54-g00ecf From 75ea7514e1e87124bf250b36a1a1c243b6b0cea0 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 28 Jun 2019 12:36:12 -0400 Subject: Add a changes file for coverity test fixes of 31030. --- changes/ticket31030 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket31030 (limited to 'changes') diff --git a/changes/ticket31030 b/changes/ticket31030 new file mode 100644 index 0000000000..4d99323b4e --- /dev/null +++ b/changes/ticket31030 @@ -0,0 +1,3 @@ + o Minor bugfixes (coverity, tests): + - Fix several coverity warnings from our unit tests. Fixes bug 31030; + bugfix on 0.2.4.1-alpha, 0.3.2.1-alpha, and 0.4.0.1-alpha. -- cgit v1.2.3-54-g00ecf From 59e523f058ee0953deacf1370d546cabd192584d Mon Sep 17 00:00:00 2001 From: rl1987 Date: Tue, 2 Jul 2019 20:06:23 +0300 Subject: Early exit from post-merge git hook script when not merging to master --- changes/bug31040 | 3 +++ scripts/git/post-merge.git-hook | 6 ++++++ 2 files changed, 9 insertions(+) create mode 100644 changes/bug31040 (limited to 'changes') diff --git a/changes/bug31040 b/changes/bug31040 new file mode 100644 index 0000000000..81f6d7e795 --- /dev/null +++ b/changes/bug31040 @@ -0,0 +1,3 @@ + o Minor bugfixes (developer tooling): + - Only log git script changes in post-merge script when merge was to the + master branch. Fixes bug 31040; bugfix on 0.4.1.1-alpha. diff --git a/scripts/git/post-merge.git-hook b/scripts/git/post-merge.git-hook index 176b7c9bbd..eae4f999e7 100755 --- a/scripts/git/post-merge.git-hook +++ b/scripts/git/post-merge.git-hook @@ -35,6 +35,12 @@ check_for_script_update() { fi } +cur_branch=$(git rev-parse --abbrev-ref HEAD) +if [ "$cur_branch" != "master" ]; then + echo "post-merge: Not a master branch. Skipping." + exit 0 +fi + check_for_diffs "pre-push" check_for_diffs "pre-commit" check_for_diffs "post-merge" -- cgit v1.2.3-54-g00ecf From ef2123c7c7bbf0cb6ec2a5528bae082d51ea8962 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 19 Jun 2019 12:02:41 -0400 Subject: hs-v3: Disallow single hop client to post/get a descriptor Closes #24964 Signed-off-by: David Goulet --- changes/ticket24964 | 4 +++ src/feature/dircache/dircache.c | 13 ++++---- src/feature/dircommon/directory.c | 69 +++++++++++++++++++++++++++++++++++++++ src/feature/dircommon/directory.h | 1 + src/test/test_hs_cache.c | 23 +++++++++++-- 5 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 changes/ticket24964 (limited to 'changes') diff --git a/changes/ticket24964 b/changes/ticket24964 new file mode 100644 index 0000000000..171c86eb1d --- /dev/null +++ b/changes/ticket24964 @@ -0,0 +1,4 @@ + o Minor feature (onion service v3): + - Do not allow single hop client to fetch or post an HS descriptor from an + HSDir. Closes ticket 24964; + diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c index 1b36f716f4..7c6af3582b 100644 --- a/src/feature/dircache/dircache.c +++ b/src/feature/dircache/dircache.c @@ -1390,8 +1390,9 @@ handle_get_hs_descriptor_v3(dir_connection_t *conn, const char *pubkey_str = NULL; const char *url = args->url; - /* Reject unencrypted dir connections */ - if (!connection_dir_is_encrypted(conn)) { + /* Reject non anonymous dir connections (which also tests if encrypted). We + * do not allow single hop clients to query an HSDir. */ + if (!connection_dir_is_anonymous(conn)) { write_short_http_response(conn, 404, "Not found"); goto done; } @@ -1632,10 +1633,10 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers, goto done; } - /* Handle HS descriptor publish request. */ - /* XXX: This should be disabled with a consensus param until we want to - * the prop224 be deployed and thus use. */ - if (connection_dir_is_encrypted(conn) && !strcmpstart(url, "/tor/hs/")) { + /* Handle HS descriptor publish request. We force an anonymous connection + * (which also tests for encrypted). We do not allow single-hop client to + * post a descriptor onto an HSDir. */ + if (connection_dir_is_anonymous(conn) && !strcmpstart(url, "/tor/hs/")) { const char *msg = "HS descriptor stored successfully."; /* We most probably have a publish request for an HS descriptor. */ diff --git a/src/feature/dircommon/directory.c b/src/feature/dircommon/directory.c index 9e6f72e9ac..b3db0aa108 100644 --- a/src/feature/dircommon/directory.c +++ b/src/feature/dircommon/directory.c @@ -7,6 +7,10 @@ #include "app/config/config.h" #include "core/mainloop/connection.h" +#include "core/or/circuitlist.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "core/or/channeltls.h" #include "feature/dircache/dircache.h" #include "feature/dircache/dirserv.h" #include "feature/dirclient/dirclient.h" @@ -15,6 +19,10 @@ #include "feature/stats/geoip_stats.h" #include "lib/compress/compress.h" +#include "core/or/circuit_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/edge_connection_st.h" +#include "core/or/or_connection_st.h" #include "feature/dircommon/dir_connection_st.h" #include "feature/nodelist/routerinfo_st.h" @@ -167,6 +175,67 @@ connection_dir_is_encrypted(const dir_connection_t *conn) return TO_CONN(conn)->linked; } +/** Return true iff the given directory connection dir_conn is + * anonymous, that is, it is on a circuit via a public relay and not directly + * from a client or bridge. + * + * For client circuits via relays: true for 2-hop+ paths. + * For client circuits via bridges: true for 3-hop+ paths. + * + * This first test if the connection is encrypted since it is a strong + * requirement for anonymity. */ +bool +connection_dir_is_anonymous(const dir_connection_t *dir_conn) +{ + const connection_t *conn, *linked_conn; + const edge_connection_t *edge_conn; + const circuit_t *circ; + + tor_assert(dir_conn); + + if (!connection_dir_is_encrypted(dir_conn)) { + return false; + } + + /* + * Buckle up, we'll do a deep dive into the connection in order to get the + * final connection channel of that connection in order to figure out if + * this is a client or relay link. + * + * We go: dir_conn -> linked_conn -> edge_conn -> on_circuit -> p_chan. + */ + + conn = TO_CONN(dir_conn); + linked_conn = conn->linked_conn; + + /* The dir connection should be connected to an edge connection. It can not + * be closed or marked for close. */ + if (linked_conn == NULL || linked_conn->magic != EDGE_CONNECTION_MAGIC || + conn->linked_conn_is_closed || conn->linked_conn->marked_for_close) { + log_info(LD_DIR, "Rejected HSDir request: not linked to edge"); + return false; + } + + edge_conn = TO_EDGE_CONN((connection_t *) linked_conn); + circ = edge_conn->on_circuit; + + /* Can't be a circuit we initiated and without a circuit, no channel. */ + if (circ == NULL || CIRCUIT_IS_ORIGIN(circ)) { + log_info(LD_DIR, "Rejected HSDir request: not on OR circuit"); + return false; + } + + /* Get the previous channel to learn if it is a client or relay link. */ + if (BUG(CONST_TO_OR_CIRCUIT(circ)->p_chan == NULL)) { + log_info(LD_DIR, "Rejected HSDir request: no p_chan"); + return false; + } + + /* Will be true if the channel is an unauthenticated peer which is only true + * for clients and bridges. */ + return !channel_is_client(CONST_TO_OR_CIRCUIT(circ)->p_chan); +} + /** Parse an HTTP request line at the start of a headers string. On failure, * return -1. On success, set *command_out to a copy of the HTTP * command ("get", "post", etc), set *url_out to a copy of the URL, and diff --git a/src/feature/dircommon/directory.h b/src/feature/dircommon/directory.h index ba3f8c1b0e..4fc743ad3d 100644 --- a/src/feature/dircommon/directory.h +++ b/src/feature/dircommon/directory.h @@ -94,6 +94,7 @@ int parse_http_command(const char *headers, char *http_get_header(const char *headers, const char *which); int connection_dir_is_encrypted(const dir_connection_t *conn); +bool connection_dir_is_anonymous(const dir_connection_t *conn); int connection_dir_reached_eof(dir_connection_t *conn); int connection_dir_process_inbuf(dir_connection_t *conn); int connection_dir_finished_flushing(dir_connection_t *conn); diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c index d71f8b6b18..86ac7e7fb1 100644 --- a/src/test/test_hs_cache.c +++ b/src/test/test_hs_cache.c @@ -10,6 +10,7 @@ #define DIRCACHE_PRIVATE #define DIRCLIENT_PRIVATE #define HS_CACHE_PRIVATE +#define TOR_CHANNEL_INTERNAL_ #include "trunnel/ed25519_cert.h" #include "feature/hs/hs_cache.h" @@ -20,7 +21,12 @@ #include "core/mainloop/connection.h" #include "core/proto/proto_http.h" #include "lib/crypt_ops/crypto_format.h" +#include "core/or/circuitlist.h" +#include "core/or/channel.h" +#include "core/or/edge_connection_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/or_connection_st.h" #include "feature/dircommon/dir_connection_st.h" #include "feature/nodelist/networkstatus_st.h" @@ -232,6 +238,8 @@ helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key) /* The dir conn we are going to simulate */ dir_connection_t *conn = NULL; + edge_connection_t *edge_conn = NULL; + or_circuit_t *or_circ = NULL; /* First extract the blinded public key that we are going to use in our query, and then build the actual query string. */ @@ -245,8 +253,16 @@ helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key) /* Simulate an HTTP GET request to the HSDir */ conn = dir_connection_new(AF_INET); tt_assert(conn); + TO_CONN(conn)->linked = 1; /* Signal that it is encrypted. */ tor_addr_from_ipv4h(&conn->base_.addr, 0x7f000001); - TO_CONN(conn)->linked = 1;/* Pretend the conn is encrypted :) */ + + /* Pretend this conn is anonymous. */ + edge_conn = edge_connection_new(CONN_TYPE_EXIT, AF_INET); + TO_CONN(conn)->linked_conn = TO_CONN(edge_conn); + or_circ = or_circuit_new(0, NULL); + or_circ->p_chan = tor_malloc_zero(sizeof(channel_t)); + edge_conn->on_circuit = TO_CIRCUIT(or_circ); + retval = directory_handle_command_get(conn, hsdir_query_str, NULL, 0); tt_int_op(retval, OP_EQ, 0); @@ -263,8 +279,11 @@ helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key) done: tor_free(hsdir_query_str); - if (conn) + if (conn) { + tor_free(or_circ->p_chan); + connection_free_minimal(TO_CONN(conn)->linked_conn); connection_free_minimal(TO_CONN(conn)); + } return received_desc; } -- cgit v1.2.3-54-g00ecf From 09c692e72b56e08668ae5f42416741ebd6edc404 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 8 Jul 2019 13:32:45 -0400 Subject: Use a 64-bit mask for log domains, and fix a conflict When we added LD_MESG, we created a conflict with the LD_NO_MOCK flag. We now need 64 bits for log domains in order to fix this issue. Fixes bug 31080; bugfix on 0.4.1.1-alpha. --- changes/bug31080_041 | 4 +++ src/lib/err/backtrace.c | 4 +-- src/lib/err/backtrace.h | 5 ++-- src/lib/log/log.h | 68 ++++++++++++++++++++++++------------------------- 4 files changed, 43 insertions(+), 38 deletions(-) create mode 100644 changes/bug31080_041 (limited to 'changes') diff --git a/changes/bug31080_041 b/changes/bug31080_041 new file mode 100644 index 0000000000..1fe9ec508d --- /dev/null +++ b/changes/bug31080_041 @@ -0,0 +1,4 @@ + o Minor bugfixes (logging): + - Fix a conflict between the flag used for messaging-domain + log messages, and the LD_NO_MOCK testing flag. Fixes bug 31080; + bugfix on 0.4.1.1-alpha. diff --git a/src/lib/err/backtrace.c b/src/lib/err/backtrace.c index 1d1b3bcfa3..f5fa7ec299 100644 --- a/src/lib/err/backtrace.c +++ b/src/lib/err/backtrace.c @@ -115,7 +115,7 @@ clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx) * that with a backtrace log. Send messages via the tor_log function at * logger". */ void -log_backtrace_impl(int severity, int domain, const char *msg, +log_backtrace_impl(int severity, uint64_t domain, const char *msg, tor_log_fn logger) { size_t depth; @@ -240,7 +240,7 @@ remove_bt_handler(void) #ifdef NO_BACKTRACE_IMPL void -log_backtrace_impl(int severity, int domain, const char *msg, +log_backtrace_impl(int severity, uint64_t domain, const char *msg, tor_log_fn logger) { logger(severity, domain, "%s. (Stack trace not available)", msg); diff --git a/src/lib/err/backtrace.h b/src/lib/err/backtrace.h index 9b313261e6..ba3049ed15 100644 --- a/src/lib/err/backtrace.h +++ b/src/lib/err/backtrace.h @@ -12,11 +12,12 @@ #include "orconfig.h" #include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" -typedef void (*tor_log_fn)(int, unsigned, const char *fmt, ...) +typedef void (*tor_log_fn)(int, uint64_t, const char *fmt, ...) CHECK_PRINTF(3,4); -void log_backtrace_impl(int severity, int domain, const char *msg, +void log_backtrace_impl(int severity, uint64_t domain, const char *msg, tor_log_fn logger); int configure_backtrace_handler(const char *tor_version); void clean_up_backtrace_handler(void); diff --git a/src/lib/log/log.h b/src/lib/log/log.h index bd606ce900..801bafa968 100644 --- a/src/lib/log/log.h +++ b/src/lib/log/log.h @@ -56,82 +56,82 @@ /* Logging domains */ /** Catch-all for miscellaneous events and fatal errors. */ -#define LD_GENERAL (1u<<0) +#define LD_GENERAL (UINT64_C(1)<<0) /** The cryptography subsystem. */ -#define LD_CRYPTO (1u<<1) +#define LD_CRYPTO (UINT64_C(1)<<1) /** Networking. */ -#define LD_NET (1u<<2) +#define LD_NET (UINT64_C(1)<<2) /** Parsing and acting on our configuration. */ -#define LD_CONFIG (1u<<3) +#define LD_CONFIG (UINT64_C(1)<<3) /** Reading and writing from the filesystem. */ -#define LD_FS (1u<<4) +#define LD_FS (UINT64_C(1)<<4) /** Other servers' (non)compliance with the Tor protocol. */ -#define LD_PROTOCOL (1u<<5) +#define LD_PROTOCOL (UINT64_C(1)<<5) /** Memory management. */ -#define LD_MM (1u<<6) +#define LD_MM (UINT64_C(1)<<6) /** HTTP implementation. */ -#define LD_HTTP (1u<<7) +#define LD_HTTP (UINT64_C(1)<<7) /** Application (socks) requests. */ -#define LD_APP (1u<<8) +#define LD_APP (UINT64_C(1)<<8) /** Communication via the controller protocol. */ -#define LD_CONTROL (1u<<9) +#define LD_CONTROL (UINT64_C(1)<<9) /** Building, using, and managing circuits. */ -#define LD_CIRC (1u<<10) +#define LD_CIRC (UINT64_C(1)<<10) /** Hidden services. */ -#define LD_REND (1u<<11) +#define LD_REND (UINT64_C(1)<<11) /** Internal errors in this Tor process. */ -#define LD_BUG (1u<<12) +#define LD_BUG (UINT64_C(1)<<12) /** Learning and using information about Tor servers. */ -#define LD_DIR (1u<<13) +#define LD_DIR (UINT64_C(1)<<13) /** Learning and using information about Tor servers. */ -#define LD_DIRSERV (1u<<14) +#define LD_DIRSERV (UINT64_C(1)<<14) /** Onion routing protocol. */ -#define LD_OR (1u<<15) +#define LD_OR (UINT64_C(1)<<15) /** Generic edge-connection functionality. */ -#define LD_EDGE (1u<<16) +#define LD_EDGE (UINT64_C(1)<<16) #define LD_EXIT LD_EDGE /** Bandwidth accounting. */ -#define LD_ACCT (1u<<17) +#define LD_ACCT (UINT64_C(1)<<17) /** Router history */ -#define LD_HIST (1u<<18) +#define LD_HIST (UINT64_C(1)<<18) /** OR handshaking */ -#define LD_HANDSHAKE (1u<<19) +#define LD_HANDSHAKE (UINT64_C(1)<<19) /** Heartbeat messages */ -#define LD_HEARTBEAT (1u<<20) +#define LD_HEARTBEAT (UINT64_C(1)<<20) /** Abstract channel_t code */ -#define LD_CHANNEL (1u<<21) +#define LD_CHANNEL (UINT64_C(1)<<21) /** Scheduler */ -#define LD_SCHED (1u<<22) +#define LD_SCHED (UINT64_C(1)<<22) /** Guard nodes */ -#define LD_GUARD (1u<<23) +#define LD_GUARD (UINT64_C(1)<<23) /** Generation and application of consensus diffs. */ -#define LD_CONSDIFF (1u<<24) +#define LD_CONSDIFF (UINT64_C(1)<<24) /** Denial of Service mitigation. */ -#define LD_DOS (1u<<25) +#define LD_DOS (UINT64_C(1)<<25) /** Processes */ -#define LD_PROCESS (1u<<26) +#define LD_PROCESS (UINT64_C(1)<<26) /** Pluggable Transports. */ -#define LD_PT (1u<<27) +#define LD_PT (UINT64_C(1)<<27) /** Bootstrap tracker. */ -#define LD_BTRACK (1u<<28) +#define LD_BTRACK (UINT64_C(1)<<28) /** Message-passing backend. */ -#define LD_MESG (1u<<29) +#define LD_MESG (UINT64_C(1)<<29) #define N_LOGGING_DOMAINS 30 #ifdef TOR_UNIT_TESTS /** This log message should not be intercepted by mock_saving_logv */ -#define LD_NO_MOCK (1u<<29) +#define LD_NO_MOCK (UINT64_C(1)<<61) #endif /** This log message is not safe to send to a callback-based logger * immediately. Used as a flag, not a log domain. */ -#define LD_NOCB (1u<<31) +#define LD_NOCB (UINT64_C(1)<<62) /** This log message should not include a function name, even if it otherwise * would. Used as a flag, not a log domain. */ -#define LD_NOFUNCNAME (1u<<30) +#define LD_NOFUNCNAME (UINT64_C(1)<<63) /** Mask of zero or more log domains, OR'd together. */ -typedef uint32_t log_domain_mask_t; +typedef uint64_t log_domain_mask_t; /** Configures which severities are logged for each logging domain for a given * log target. */ -- cgit v1.2.3-54-g00ecf From ffce19a9ec71a6753673f84535f16003f38eb214 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Wed, 10 Jul 2019 11:36:26 +0300 Subject: Make tor-print-ed-signing-cert output RFC1123 and unix timestamps as well --- changes/ticket31012 | 4 ++++ doc/tor-print-ed-signing-cert.1.txt | 6 ++++++ src/tools/tor-print-ed-signing-cert.c | 7 +++++++ 3 files changed, 17 insertions(+) create mode 100644 changes/ticket31012 (limited to 'changes') diff --git a/changes/ticket31012 b/changes/ticket31012 new file mode 100644 index 0000000000..61ea30d8da --- /dev/null +++ b/changes/ticket31012 @@ -0,0 +1,4 @@ + o Minor bugfixes (operator tools): + - Make tor-print-ed-signing-cert(1) print certificate expiration date in + RFC 1123 and UNIX timestamp formats, to make output machine readable. + Fixes bug 31012; bugfix on 0.3.5.1-alpha. diff --git a/doc/tor-print-ed-signing-cert.1.txt b/doc/tor-print-ed-signing-cert.1.txt index 1a3109df95..48a3f095d5 100644 --- a/doc/tor-print-ed-signing-cert.1.txt +++ b/doc/tor-print-ed-signing-cert.1.txt @@ -21,6 +21,12 @@ DESCRIPTION **tor-print-ed-signing-cert** is utility program for Tor relay operators to check expiration date of ed25519 signing certificate. +Expiration date is printed in three formats: + +* Human-readable timestamp, localized to current timezone. +* RFC 1123 timestamp (at GMT timezone). +* Unix time value. + SEE ALSO -------- **tor**(1) + diff --git a/src/tools/tor-print-ed-signing-cert.c b/src/tools/tor-print-ed-signing-cert.c index 1f1a01ab5c..43a1d7bcbd 100644 --- a/src/tools/tor-print-ed-signing-cert.c +++ b/src/tools/tor-print-ed-signing-cert.c @@ -10,11 +10,13 @@ #include "lib/cc/torint.h" /* TOR_PRIdSZ */ #include "lib/crypt_ops/crypto_format.h" #include "lib/malloc/malloc.h" +#include "lib/encoding/time_fmt.h" int main(int argc, char **argv) { ed25519_cert_t *cert = NULL; + char rfc1123_buf[RFC1123_TIME_LEN+1] = ""; if (argc != 2) { fprintf(stderr, "Usage:\n"); @@ -59,6 +61,11 @@ main(int argc, char **argv) printf("Expires at: %s", ctime(&expires_at)); + format_rfc1123_time(rfc1123_buf, expires_at); + printf("RFC 1123 timestamp: %s\n", rfc1123_buf); + + printf("UNIX timestamp: %ld\n", (long int)expires_at); + ed25519_cert_free(cert); return 0; -- cgit v1.2.3-54-g00ecf From 78768aafe1068bd76419944bea1ed3453d85edfe Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 18 Jul 2019 09:27:49 -0400 Subject: Changes file for 29746. --- changes/ticket29746 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket29746 (limited to 'changes') diff --git a/changes/ticket29746 b/changes/ticket29746 new file mode 100644 index 0000000000..63b9edb391 --- /dev/null +++ b/changes/ticket29746 @@ -0,0 +1,4 @@ + o Minor bugfixes (best practices tracker): + - Fix a few issues in the best-practices script, including tests, tab + tolerance, error reporting, and directory-exclusion logic. Fixes bug + 29746; bugfix on 0.4.1.1-alpha. -- cgit v1.2.3-54-g00ecf From 3efe5cc57af040f8adb9a9e24a6ad1e77998a7a1 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 18 Jul 2019 09:27:58 -0400 Subject: changes file for 30752 --- changes/ticket30752 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/ticket30752 (limited to 'changes') diff --git a/changes/ticket30752 b/changes/ticket30752 new file mode 100644 index 0000000000..754a9003d1 --- /dev/null +++ b/changes/ticket30752 @@ -0,0 +1,6 @@ + o Minor features (best practices tracker): + - Give a warning rather than an error when a practracker exception is + violated by a small amount; add a --list-overstrict option to + practracker that lists exceptions that are stricter than they need to + be, and provide an environment variable for disabling + practracker. Closes ticekt 30752. -- cgit v1.2.3-54-g00ecf From 8bbec36b3b2dadbd23c7b3ffe2bccb7291aee1f0 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 19 Jul 2019 09:21:08 -0400 Subject: Changes file for bug 31001 --- changes/ticket31001 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/ticket31001 (limited to 'changes') diff --git a/changes/ticket31001 b/changes/ticket31001 new file mode 100644 index 0000000000..2ce1cbdf34 --- /dev/null +++ b/changes/ticket31001 @@ -0,0 +1,6 @@ + o Minor bugfixes (compatibility, standards compliance): + - Fix a bug that would invoke undefined behavior on certain operating + systems when trying to asprintf() a string exactly INT_MAX bytes + long. We don't believe this is exploitable, but it's better + to fix it anyway. Fixes bug 31001; bugfix on 0.2.2.11-alpha. + Found and fixed by Tobias Stoeckmann. -- cgit v1.2.3-54-g00ecf From aed82bf4109126a3088752d7bec45bab4f5e1537 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 23 Jul 2019 11:46:07 +0300 Subject: Add changes file for #31112 and #31098. --- changes/bug31112 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/bug31112 (limited to 'changes') diff --git a/changes/bug31112 b/changes/bug31112 new file mode 100644 index 0000000000..882efaad59 --- /dev/null +++ b/changes/bug31112 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Various simplifications and minor improvements to the circuit padding + machines. Patch by Tobias Pulls. Closes tickets 31112 and 31098. -- cgit v1.2.3-54-g00ecf From ec38b662f2bfbaa197f78b75493b4e8734610e26 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Thu, 30 May 2019 15:18:16 -0700 Subject: Bug 30649: Changes file. --- changes/bug30649 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/bug30649 (limited to 'changes') diff --git a/changes/bug30649 b/changes/bug30649 new file mode 100644 index 0000000000..3f5768bcb4 --- /dev/null +++ b/changes/bug30649 @@ -0,0 +1,4 @@ + o Minor bugfixes (circuit padding): + - On relays, properly check that a padding machine is absent before + logging a warn about it being absent. Fixes bug 30649; + bugfix on 0.4.1.1-alpha. -- cgit v1.2.3-54-g00ecf From fdfee3d06f05973f54cd7550450096ef2f8b5f55 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 23 Jul 2019 12:40:33 +0300 Subject: Changes file for #31113. --- changes/bug31113 | 3 +++ scripts/maint/practracker/exceptions.txt | 1 + 2 files changed, 4 insertions(+) create mode 100644 changes/bug31113 (limited to 'changes') diff --git a/changes/bug31113 b/changes/bug31113 new file mode 100644 index 0000000000..f48328f0fe --- /dev/null +++ b/changes/bug31113 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Improve documentation in circuit padding subsystem. Patch by Tobias + Pulls. Closes ticket 31113. diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index f28392537b..66e9f7a0c2 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -87,6 +87,7 @@ problem function-size /src/core/or/circuitlist.c:circuit_about_to_free() 120 problem function-size /src/core/or/circuitlist.c:circuits_handle_oom() 117 problem function-size /src/core/or/circuitmux.c:circuitmux_set_policy() 110 problem function-size /src/core/or/circuitmux.c:circuitmux_attach_circuit() 114 +problem file-size /src/core/or/circuitpadding.c 3001 problem function-size /src/core/or/circuitpadding.c:circpad_machine_schedule_padding() 107 problem function-size /src/core/or/circuitpadding_machines.c:circpad_machine_relay_hide_intro_circuits() 104 problem function-size /src/core/or/circuitpadding_machines.c:circpad_machine_client_hide_rend_circuits() 112 -- cgit v1.2.3-54-g00ecf From bd1ac408d854758cc40bde88cc5f71b46661b51c Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sat, 29 Jun 2019 19:38:14 +0300 Subject: Remove dead code from circpad_machine_remove_token(). --- changes/bug31027 | 3 +++ src/core/or/circuitpadding.c | 9 ++++----- 2 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 changes/bug31027 (limited to 'changes') diff --git a/changes/bug31027 b/changes/bug31027 new file mode 100644 index 0000000000..dd3ce20b60 --- /dev/null +++ b/changes/bug31027 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Remove some dead code from circpad_machine_remove_token() to fix some + Coverity warnings (CID 1447298). Fixes bug 31027; bugfix on 0.4.1.1-alpha. \ No newline at end of file diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c index 0214cc4219..626787da7b 100644 --- a/src/core/or/circuitpadding.c +++ b/src/core/or/circuitpadding.c @@ -1083,8 +1083,11 @@ circpad_machine_remove_token(circpad_machine_runtime_t *mi) state = circpad_machine_current_state(mi); + /* If we are not in a padding state (like start or end), we're done */ + if (!state) + return; /* Don't remove any tokens if we're not doing token removal */ - if (!state || state->token_removal == CIRCPAD_TOKEN_REMOVAL_NONE) + if (state->token_removal == CIRCPAD_TOKEN_REMOVAL_NONE) return; current_time = monotime_absolute_usec(); @@ -1103,10 +1106,6 @@ circpad_machine_remove_token(circpad_machine_runtime_t *mi) timer_disable(mi->padding_timer); } - /* If we are not in a padding state (like start or end), we're done */ - if (!state) - return; - /* Perform the specified token removal strategy */ switch (state->token_removal) { case CIRCPAD_TOKEN_REMOVAL_CLOSEST_USEC: -- cgit v1.2.3-54-g00ecf From af26cd61015a2c127dbcf7e3db91da91adb415f9 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sat, 29 Jun 2019 19:46:43 +0300 Subject: Always check the retval of circpad_machine_current_state(). --- changes/bug31024 | 4 ++++ src/core/or/circuitpadding.c | 6 ++++++ 2 files changed, 10 insertions(+) create mode 100644 changes/bug31024 (limited to 'changes') diff --git a/changes/bug31024 b/changes/bug31024 new file mode 100644 index 0000000000..888fb2a26b --- /dev/null +++ b/changes/bug31024 @@ -0,0 +1,4 @@ + o Minor bugfixes (circuitpadding): + - Add two NULL checks in unreachable places to silence Coverity (CID 144729 + and 1447291) and better future proof ourselves. Fixes bug 31024; bugfix + on 0.4.1.1-alpha. \ No newline at end of file diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c index 626787da7b..c4670bbc2f 100644 --- a/src/core/or/circuitpadding.c +++ b/src/core/or/circuitpadding.c @@ -450,6 +450,9 @@ circpad_is_token_removal_supported(circpad_machine_runtime_t *mi) /* Machines that do want token removal are less sensitive to performance. * Let's spend some time to check that our state is consistent and sane */ const circpad_state_t *state = circpad_machine_current_state(mi); + if (BUG(!state)) { + return 1; + } tor_assert_nonfatal(state->token_removal != CIRCPAD_TOKEN_REMOVAL_NONE); tor_assert_nonfatal(state->histogram_len == mi->histogram_len); tor_assert_nonfatal(mi->histogram_len != 0); @@ -1667,6 +1670,9 @@ circpad_estimate_circ_rtt_on_received(circuit_t *circ, } } else { const circpad_state_t *state = circpad_machine_current_state(mi); + if (BUG(!state)) { + return; + } /* Since monotime is unpredictably expensive, only update this field * if rtt estimates are needed. Otherwise, stop the rtt update. */ -- cgit v1.2.3-54-g00ecf From 19536fd18d02a52031f7914d5930645bb53b9dba Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 1 Aug 2019 09:35:33 -0400 Subject: practracker: replaces "overstrict" with "overbroad" I had the logic reversed here. --- changes/ticket30752 | 2 +- scripts/maint/practracker/practracker.py | 8 ++++---- scripts/maint/practracker/problem.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'changes') diff --git a/changes/ticket30752 b/changes/ticket30752 index 754a9003d1..044c7c7d93 100644 --- a/changes/ticket30752 +++ b/changes/ticket30752 @@ -1,6 +1,6 @@ o Minor features (best practices tracker): - Give a warning rather than an error when a practracker exception is - violated by a small amount; add a --list-overstrict option to + violated by a small amount; add a --list-overbroad option to practracker that lists exceptions that are stricter than they need to be, and provide an environment variable for disabling practracker. Closes ticekt 30752. diff --git a/scripts/maint/practracker/practracker.py b/scripts/maint/practracker/practracker.py index 245d01d36d..a4e951ac7c 100755 --- a/scripts/maint/practracker/practracker.py +++ b/scripts/maint/practracker/practracker.py @@ -153,7 +153,7 @@ def main(argv): parser = argparse.ArgumentParser(prog=progname) parser.add_argument("--regen", action="store_true", help="Regenerate the exceptions file") - parser.add_argument("--list-overstrict", action="store_true", + parser.add_argument("--list-overbroad", action="store_true", help="List over-strict exceptions") parser.add_argument("--exceptions", help="Override the location for the exceptions file") @@ -200,7 +200,7 @@ def main(argv): # 2.1) Adjust the exceptions so that we warn only about small problems, # and produce errors on big ones. - if not (args.regen or args.list_overstrict or args.strict): + if not (args.regen or args.list_overbroad or args.strict): ProblemVault.set_tolerances(TOLERANCE_FNS) # 3) Go through all the files and report problems if they are not exceptions @@ -234,10 +234,10 @@ variable. """.format(found_new_issues, exceptions_file) print(new_issues_str) - if args.list_overstrict: + if args.list_overbroad: def k_fn(tup): return tup[0].key() - for (ex,p) in sorted(ProblemVault.list_overstrict_exceptions(), key=k_fn): + for (ex,p) in sorted(ProblemVault.list_overbroad_exceptions(), key=k_fn): if p is None: print(ex, "->", 0) else: diff --git a/scripts/maint/practracker/problem.py b/scripts/maint/practracker/problem.py index d09e941518..73519d446f 100644 --- a/scripts/maint/practracker/problem.py +++ b/scripts/maint/practracker/problem.py @@ -82,7 +82,7 @@ class ProblemVault(object): return status - def list_overstrict_exceptions(self): + def list_overbroad_exceptions(self): """Return an iterator of tuples containing (ex,prob) where ex is an exceptions in this vault that are stricter than it needs to be, and prob is the worst problem (if any) that it covered. -- cgit v1.2.3-54-g00ecf From 223afc2d8f4fd48445c3dc30168a753075ba4959 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 1 Aug 2019 12:57:26 -0400 Subject: practracker: add envvar TOR_PRACTRACKER_OPTIONS We have Makefile.am use this to decide how to invoke practracker on the Tor source. --- Makefile.am | 2 +- changes/ticket31309 | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 changes/ticket31309 (limited to 'changes') diff --git a/Makefile.am b/Makefile.am index 8eeba5edb7..7ada42f9d0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -371,7 +371,7 @@ endif check-best-practices: if USEPYTHON - @$(PYTHON) $(top_srcdir)/scripts/maint/practracker/practracker.py $(top_srcdir) + @$(PYTHON) $(top_srcdir)/scripts/maint/practracker/practracker.py $(top_srcdir) $(TOR_PRACTRACKER_OPTIONS) endif practracker-regen: diff --git a/changes/ticket31309 b/changes/ticket31309 new file mode 100644 index 0000000000..8e1c9f27ea --- /dev/null +++ b/changes/ticket31309 @@ -0,0 +1,4 @@ + o Minor features (best practices tracker): + - Add a TOR_PRACTRACKER_OPTIONS variable for passing arguments + to practracker from the environment. We may want this for + continuous integration. Closes ticket 31309. -- cgit v1.2.3-54-g00ecf From 394528241947800a0ac881b8890e5af387e0e9d7 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 1 Aug 2019 13:45:45 -0400 Subject: make dist: only include files from practracker dir intentionally. Previously, we included temporary files and whatnot, which is not good. Fixes bug 31311; bugfix on 0.4.1.1-alpha. --- Makefile.am | 9 ++++++--- changes/ticket31311 | 3 +++ 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 changes/ticket31311 (limited to 'changes') diff --git a/Makefile.am b/Makefile.am index 3f3de34ceb..10bd4b45c2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -165,9 +165,12 @@ EXTRA_DIST+= \ README \ ReleaseNotes \ scripts/maint/checkIncludes.py \ - scripts/maint/checkSpace.pl \ - scripts/maint/practracker - + scripts/maint/checkSpace.pl \ + scripts/maint/practracker/exceptions.txt \ + scripts/maint/practracker/metrics.py \ + scripts/maint/practracker/practracker.py \ + scripts/maint/practracker/problem.py \ + scripts/maint/practracker/util.py ## This tells etags how to find mockable function definitions. AM_ETAGSFLAGS=--regex='{c}/MOCK_IMPL([^,]+,\W*\([a-zA-Z0-9_]+\)\W*,/\1/s' diff --git a/changes/ticket31311 b/changes/ticket31311 new file mode 100644 index 0000000000..88dfb85736 --- /dev/null +++ b/changes/ticket31311 @@ -0,0 +1,3 @@ + o Minor bugfixes (distribution): + - Do not ship any temporary files found in the scripts/maint/practracker + directory. Fixes bug 31311; bugfix on 0.4.1.1-alpha. -- cgit v1.2.3-54-g00ecf From fa60fee8d56af01f6fefca17f945bdd00d195571 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 1 Aug 2019 14:01:43 -0400 Subject: practracker: Add unit tests to test script, and test script to makefile This makes all of the practracker tests get run by make check, and hence by our CI. Closes ticket 31304. --- changes/ticket31304 | 3 +++ scripts/maint/practracker/test_practracker.sh | 4 ++++ src/test/include.am | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 changes/ticket31304 (limited to 'changes') diff --git a/changes/ticket31304 b/changes/ticket31304 new file mode 100644 index 0000000000..ca60148b0c --- /dev/null +++ b/changes/ticket31304 @@ -0,0 +1,3 @@ + o Minor features (tests): + - The practracker tests are now run as part of the Tor test suite. + Closes ticket 31304. diff --git a/scripts/maint/practracker/test_practracker.sh b/scripts/maint/practracker/test_practracker.sh index 590525660b..c7be227702 100755 --- a/scripts/maint/practracker/test_practracker.sh +++ b/scripts/maint/practracker/test_practracker.sh @@ -29,6 +29,10 @@ run_practracker() { "${DATA}/" "$@"; } +echo "unit tests:" + +"${PYTHON:-python}" "${PRACTRACKER_DIR}/practracker_tests.py" || exit 1 + echo "ex0:" run_practracker --exceptions "${DATA}/ex0.txt" > "${TMPDIR}/ex0-received.txt" diff --git a/src/test/include.am b/src/test/include.am index 0ec4d96ad4..7cd1ecae36 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -31,7 +31,11 @@ TESTSCRIPTS += \ endif if USEPYTHON -TESTSCRIPTS += src/test/test_ntor.sh src/test/test_hs_ntor.sh src/test/test_bt.sh +TESTSCRIPTS += \ + src/test/test_ntor.sh \ + src/test/test_hs_ntor.sh \ + src/test/test_bt.sh \ + scripts/maint/practracker/test_practracker.sh if COVERAGE_ENABLED # ... -- cgit v1.2.3-54-g00ecf From 74c059596527af67f5df38847e86179852bc7005 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 5 Aug 2019 13:47:07 +0300 Subject: Ignore regular cells in padding circuits. Padding circuits were regular cells that got closed before their padding machine could finish. This means that they can still receive regular cells from their past life, but they have no way or reason to answer them anymore. Hence let's ignore them before they even get to the proper subsystems. --- changes/bug30942 | 4 ++++ src/core/or/relay.c | 11 +++++++++++ 2 files changed, 15 insertions(+) create mode 100644 changes/bug30942 (limited to 'changes') diff --git a/changes/bug30942 b/changes/bug30942 new file mode 100644 index 0000000000..bd6b2ff581 --- /dev/null +++ b/changes/bug30942 @@ -0,0 +1,4 @@ + o Minor bugfixes (circuit padding): + - Ignore non-padding cells on padding circuits. This addresses various + warning messages from subsystems that were not expecting padding + circuits. Fixes bug 30942; bugfix on 0.4.1.1-alpha. \ No newline at end of file diff --git a/src/core/or/relay.c b/src/core/or/relay.c index 9f90a09699..9e691a02b5 100644 --- a/src/core/or/relay.c +++ b/src/core/or/relay.c @@ -1663,6 +1663,17 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, if (circpad_handle_padding_negotiated(circ, cell, layer_hint) == 0) circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length); return 0; + } + + /* If this is a padding circuit we don't need to parse any other commands + * than the padding ones. Just drop them to the floor. */ + if (circ->purpose == CIRCUIT_PURPOSE_C_CIRCUIT_PADDING) { + log_info(domain, "Ignored cell (%d) that arrived in padding circuit.", + rh.command); + return 0; + } + + switch (rh.command) { case RELAY_COMMAND_BEGIN: case RELAY_COMMAND_BEGIN_DIR: if (layer_hint && -- cgit v1.2.3-54-g00ecf From 9a1e9b1d6c66e05049a6441e27f8388ad21c16a1 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 5 Aug 2019 10:31:02 -0400 Subject: Teach practracker about .h files I'm using 500 as a file size limit, and 15 as an include limit. This affects comparatively few files, but I think they are the worst ones. Closes ticket 31175. --- changes/ticket31175 | 3 +++ scripts/maint/practracker/metrics.py | 4 +++- scripts/maint/practracker/practracker.py | 18 ++++++++++++++---- scripts/maint/practracker/problem.py | 11 +++++++++-- scripts/maint/practracker/util.py | 10 +++++++--- 5 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 changes/ticket31175 (limited to 'changes') diff --git a/changes/ticket31175 b/changes/ticket31175 new file mode 100644 index 0000000000..cff13761a4 --- /dev/null +++ b/changes/ticket31175 @@ -0,0 +1,3 @@ + o Minor features (development tools): + - Our best-practices tracker now looks at headers as well as + C files. Closes ticket 31175. diff --git a/scripts/maint/practracker/metrics.py b/scripts/maint/practracker/metrics.py index 82f1cd64e9..9f69b2ac1f 100644 --- a/scripts/maint/practracker/metrics.py +++ b/scripts/maint/practracker/metrics.py @@ -27,7 +27,9 @@ def get_function_lines(f): # Skip lines that look like they are defining functions with these # names: they aren't real function definitions. - REGEXP_CONFUSE_TERMS = {"MOCK_IMPL", "ENABLE_GCC_WARNINGS", "ENABLE_GCC_WARNING", "DUMMY_TYPECHECK_INSTANCE", + REGEXP_CONFUSE_TERMS = {"MOCK_IMPL", "MOCK_DECL", "HANDLE_DECL", + "ENABLE_GCC_WARNINGS", "ENABLE_GCC_WARNING", + "DUMMY_TYPECHECK_INSTANCE", "DISABLE_GCC_WARNING", "DISABLE_GCC_WARNINGS"} in_function = False diff --git a/scripts/maint/practracker/practracker.py b/scripts/maint/practracker/practracker.py index 7e51edb48f..0fdfd4a40a 100755 --- a/scripts/maint/practracker/practracker.py +++ b/scripts/maint/practracker/practracker.py @@ -35,6 +35,10 @@ MAX_FILE_SIZE = 3000 # lines MAX_FUNCTION_SIZE = 100 # lines # Recommended number of #includes MAX_INCLUDE_COUNT = 50 +# Recommended file size for headers +MAX_H_FILE_SIZE = 500 +# Recommended include count for headers +MAX_H_INCLUDE_COUNT = 15 # Map from problem type to functions that adjust for tolerance TOLERANCE_FNS = { @@ -161,8 +165,12 @@ def main(argv): help="Make all warnings into errors") parser.add_argument("--terse", action="store_true", help="Do not emit helpful instructions.") + parser.add_argument("--max-h-file-size", default=MAX_H_FILE_SIZE, + help="Maximum lines per .H file") + parser.add_argument("--max-h-include-count", default=MAX_H_INCLUDE_COUNT, + help="Maximum includes per .H file") parser.add_argument("--max-file-size", default=MAX_FILE_SIZE, - help="Maximum lines per C file size") + help="Maximum lines per C file") parser.add_argument("--max-include-count", default=MAX_INCLUDE_COUNT, help="Maximum includes per C file") parser.add_argument("--max-function-size", default=MAX_FUNCTION_SIZE, @@ -180,9 +188,11 @@ def main(argv): # 0) Configure our thresholds of "what is a problem actually" filt = problem.ProblemFilter() - filt.addThreshold(problem.FileSizeItem("*", int(args.max_file_size))) - filt.addThreshold(problem.IncludeCountItem("*", int(args.max_include_count))) - filt.addThreshold(problem.FunctionSizeItem("*", int(args.max_function_size))) + filt.addThreshold(problem.FileSizeItem("*.c", int(args.max_file_size))) + filt.addThreshold(problem.IncludeCountItem("*.c", int(args.max_include_count))) + filt.addThreshold(problem.FileSizeItem("*.h", int(args.max_h_file_size))) + filt.addThreshold(problem.IncludeCountItem("*.h", int(args.max_h_include_count))) + filt.addThreshold(problem.FunctionSizeItem("*.c", int(args.max_function_size))) # 1) Get all the .c files we care about files_list = util.get_tor_c_files(TOR_TOPDIR) diff --git a/scripts/maint/practracker/problem.py b/scripts/maint/practracker/problem.py index 73519d446f..13c8e55143 100644 --- a/scripts/maint/practracker/problem.py +++ b/scripts/maint/practracker/problem.py @@ -108,10 +108,11 @@ class ProblemFilter(object): self.thresholds = dict() def addThreshold(self, item): - self.thresholds[item.get_type()] = item + self.thresholds[(item.get_type(),item.get_file_type())] = item def matches(self, item): - filt = self.thresholds.get(item.get_type(), None) + key = (item.get_type(), item.get_file_type()) + filt = self.thresholds.get(key, None) if filt is None: return False return item.is_worse_than(filt) @@ -158,6 +159,12 @@ class Item(object): def get_type(self): return self.problem_type + def get_file_type(self): + if self.problem_location.endswith(".h"): + return "*.h" + else: + return "*.c" + class FileSizeItem(Item): """ Denotes a problem with the size of a .c file. diff --git a/scripts/maint/practracker/util.py b/scripts/maint/practracker/util.py index 5a8876a0f6..695668f561 100644 --- a/scripts/maint/practracker/util.py +++ b/scripts/maint/practracker/util.py @@ -5,12 +5,14 @@ import os EXCLUDE_SOURCE_DIRS = {"src/test/", "src/trunnel/", "src/rust/", "src/ext/", ".git/"} +EXCLUDE_FILES = {"orconfig.h"} + def _norm(p): return os.path.normcase(os.path.normpath(p)) def get_tor_c_files(tor_topdir): """ - Return a list with the .c filenames we want to get metrics of. + Return a list with the .c and .h filenames we want to get metrics of. """ files_list = [] exclude_dirs = { _norm(os.path.join(tor_topdir, p)) for p in EXCLUDE_SOURCE_DIRS } @@ -23,8 +25,10 @@ def get_tor_c_files(tor_topdir): directories.sort() filenames.sort() for filename in filenames: - # We only care about .c files - if not filename.endswith(".c"): + # We only care about .c and .h files + if not (filename.endswith(".c") or filename.endswith(".h")): + continue + if filename in EXCLUDE_FILES: continue full_path = os.path.join(root,filename) -- cgit v1.2.3-54-g00ecf From d515b0f4ba5797ab763c43b5ded0a7a5712eae20 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 5 Aug 2019 17:43:53 -0400 Subject: changes file for ticket 31176 --- changes/ticket31176 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/ticket31176 (limited to 'changes') diff --git a/changes/ticket31176 b/changes/ticket31176 new file mode 100644 index 0000000000..5fcdeab3af --- /dev/null +++ b/changes/ticket31176 @@ -0,0 +1,5 @@ + o Major features (developer tools): + - Our best-practices tracker now integrates with our include-checker tool + to keep track of the layering violations that we have not yet fixed. + We hope to reduce this number over time to improve Tor's modularity. + Closes ticket 31176. -- cgit v1.2.3-54-g00ecf From 25c97b18f1814eadee7c60a9f1d96fdb781bb419 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 6 Aug 2019 13:13:36 -0400 Subject: changes file for ticket 31320 --- changes/ticket31320 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket31320 (limited to 'changes') diff --git a/changes/ticket31320 b/changes/ticket31320 new file mode 100644 index 0000000000..07847e5624 --- /dev/null +++ b/changes/ticket31320 @@ -0,0 +1,3 @@ + o Documentation: + - Include an example usage for IPv6 ORPort in our sample torrc. + Closes ticket 31320; patch from Ali Raheem. -- cgit v1.2.3-54-g00ecf From d6202d3128db259c1051eeef3e304459bcee8b53 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 8 Aug 2019 12:33:42 +1000 Subject: scripts/git: add TOR_PUSH_DELAY to git-push-all.sh Add a TOR_PUSH_DELAY variable to git-push-all.sh, which makes the script push master and maint branches with a delay between each branch. These delays trigger the CI jobs in a set order, which should show the most likely failures first. Also: * make pushes atomic by default, and * make the script pass any command-line arguments to git push. Closes ticket 29879. --- changes/ticket29879 | 7 +++++++ scripts/git/git-push-all.sh | 51 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 changes/ticket29879 (limited to 'changes') diff --git a/changes/ticket29879 b/changes/ticket29879 new file mode 100644 index 0000000000..c37bdd3f62 --- /dev/null +++ b/changes/ticket29879 @@ -0,0 +1,7 @@ + o Minor features (git scripts): + - Add a TOR_PUSH_DELAY variable to git-push-all.sh, which makes the script + push master and maint branches with a delay between each branch. These + delays trigger the CI jobs in a set order, which should show the most + likely failures first. Also make pushes atomic by default, and make + the script pass any command-line arguments to git push. + Closes ticket 29879. diff --git a/scripts/git/git-push-all.sh b/scripts/git/git-push-all.sh index 2030a600ff..1ae310eca4 100755 --- a/scripts/git/git-push-all.sh +++ b/scripts/git/git-push-all.sh @@ -1,11 +1,44 @@ #!/usr/bin/env bash -# The remote upstream branch on which git.torproject.org/tor.git points to. -UPSTREAM_BRANCH=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"} - -git push "$UPSTREAM_BRANCH" \ - master \ - {release,maint}-0.4.1 \ - {release,maint}-0.4.0 \ - {release,maint}-0.3.5 \ - {release,maint}-0.2.9 +# Usage: git-push-all.sh +# env vars: TOR_UPSTREAM_REMOTE_NAME=upstream TOR_PUSH_DELAY=0 +# options: --no-atomic --dry-run (any other git push option) +# +# TOR_PUSH_DELAY pushes the master and maint branches separately, so that CI +# runs in a sensible order. +# push --atomic is the default when TOR_PUSH_DELAY=0, and for release branches. + +set -e + +# The upstream remote which git.torproject.org/tor.git points to. +UPSTREAM_REMOTE=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"} +# Add a delay between pushes, so CI runs on the most important branches first +PUSH_DELAY=${TOR_PUSH_DELAY:-0} + +PUSH_BRANCHES=`echo \ + master \ + {release,maint}-0.4.1 \ + {release,maint}-0.4.0 \ + {release,maint}-0.3.5 \ + {release,maint}-0.2.9 \ + ` + +if [ "$PUSH_DELAY" -le 0 ]; then + echo "Pushing $PUSH_BRANCHES" + git push --atomic "$@" "$UPSTREAM_REMOTE" $PUSH_BRANCHES +else + PUSH_BRANCHES=`echo "$PUSH_BRANCHES" | tr " " "\n" | sort -V` + MASTER_BRANCH=`echo "$PUSH_BRANCHES" | tr " " "\n" | grep master` + MAINT_BRANCHES=`echo "$PUSH_BRANCHES" | tr " " "\n" | grep maint` + RELEASE_BRANCHES=`echo "$PUSH_BRANCHES" | tr " " "\n" | grep release | \ + tr "\n" " "` + printf "Pushing with %ss delays, so CI runs in this order:\n%s\n%s\n%s\n" \ + "$PUSH_DELAY" "$MASTER_BRANCH" "$MAINT_BRANCHES" "$RELEASE_BRANCHES" + git push "$@" "$UPSTREAM_REMOTE" $MASTER_BRANCH + sleep "$PUSH_DELAY" + for b in $MAINT_BRANCHES; do + git push "$@" "$UPSTREAM_REMOTE" $b + sleep "$PUSH_DELAY" + done + git push --atomic "$@" "$UPSTREAM_REMOTE" $RELEASE_BRANCHES +fi -- cgit v1.2.3-54-g00ecf From 71e5af0221568b36d128be88c958a7de018ebcb3 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 8 Aug 2019 11:32:11 -0400 Subject: pre-push hook: Only run practracker when a special file is present Closes ticket 30979. --- changes/ticket30979 | 5 +++++ scripts/git/pre-push.git-hook | 13 ++++++++----- scripts/maint/practracker/.enable_practracker_in_hooks | 1 + 3 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 changes/ticket30979 create mode 100644 scripts/maint/practracker/.enable_practracker_in_hooks (limited to 'changes') diff --git a/changes/ticket30979 b/changes/ticket30979 new file mode 100644 index 0000000000..8ae9b3c418 --- /dev/null +++ b/changes/ticket30979 @@ -0,0 +1,5 @@ + o Minor features (git hooks): + - Our pre-push git hook now checks for a special file + before running practracker, so that it only runs on branches + that are based on master. + Closes ticket 30979. diff --git a/scripts/git/pre-push.git-hook b/scripts/git/pre-push.git-hook index 71abc9aa2b..40a3bffa79 100755 --- a/scripts/git/pre-push.git-hook +++ b/scripts/git/pre-push.git-hook @@ -28,10 +28,14 @@ if [ -x "$workdir/.git/hooks/pre-commit" ]; then fi fi -if [ -e scripts/maint/practracker/practracker.py ]; then - if ! python3 ./scripts/maint/practracker/practracker.py "$workdir"; then - exit 1 - fi +PT_DIR=scripts/maint/practracker + +if [ -e "${PT_DIR}/practracker.py" ]; then + if [ -e "${PT_DIR}/.enable_practracker_in_hooks" ]; then + if ! python3 "${PT_DIR}/practracker.py" "$workdir"; then + exit 1 + fi + fi fi remote="$1" @@ -104,4 +108,3 @@ do done exit 0 - diff --git a/scripts/maint/practracker/.enable_practracker_in_hooks b/scripts/maint/practracker/.enable_practracker_in_hooks new file mode 100644 index 0000000000..a9e707f5da --- /dev/null +++ b/scripts/maint/practracker/.enable_practracker_in_hooks @@ -0,0 +1 @@ +This file is present to tell our git hooks to run practracker on this branch. -- cgit v1.2.3-54-g00ecf From 02c89c955d60d1135aa231ce8ebc431af732f560 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Thu, 8 Aug 2019 13:59:49 -0500 Subject: Bug 31356: Add changes file. Also document the other log changes in this branch. --- changes/bug31356_and_logs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 changes/bug31356_and_logs (limited to 'changes') diff --git a/changes/bug31356_and_logs b/changes/bug31356_and_logs new file mode 100644 index 0000000000..fb5307cb69 --- /dev/null +++ b/changes/bug31356_and_logs @@ -0,0 +1,11 @@ + o Minor bugfixes (circuit padding negotiation): + - Bump circuit padding protover to explicitly signify that the hs setup + machine support is finalized in 0.4.1.x-stable. This also means that + 0.4.1.x-alpha clients will not negotiate padding with 0.4.1.x-stable + relays, and 0.4.1.x-stable clients will not negotiate padding with + 0.4.1.x-alpha relays (or 0.4.0.x relays). Fixes bug 31356; + bugfix on 0.4.1.1-alpha. + o Minor features (circuit padding logging): + - Demote noisy client-side warn log to a protocol warning. Add additional + log messages and circuit id fields to help with fixing bug 30992 and any + other future issues. -- cgit v1.2.3-54-g00ecf From 87a3c5b1109a65fdf9b436f1035126044d77e552 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 19 Aug 2019 13:59:57 -0400 Subject: Fix 64-bit return issue in parse_log_domain() If unsigned int is 32-bits long, then our old code would give a wrong result with any log domain whose mask was >= (1<<32). Fortunately, there are no such log domains right now: the domain mask is only 64 bits long to accommodate some flags. Found by coverity as CID 1452041. Fixes bug 31451; bugfix on 0.4.1.4-rc. --- changes/ticket31451 | 4 ++++ src/lib/log/log.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 changes/ticket31451 (limited to 'changes') diff --git a/changes/ticket31451 b/changes/ticket31451 new file mode 100644 index 0000000000..773d665957 --- /dev/null +++ b/changes/ticket31451 @@ -0,0 +1,4 @@ + o Minor bugfixes (logging): + - Fix a code issue that would have broken our parsing of log + domains as soon as we had 33 of them. Fortunately, we still + only have 29. Fixes bug 31451; bugfix on 0.4.1.4-rc. diff --git a/src/lib/log/log.c b/src/lib/log/log.c index d95bf1ff6e..56f016eae4 100644 --- a/src/lib/log/log.c +++ b/src/lib/log/log.c @@ -1285,7 +1285,7 @@ parse_log_domain(const char *domain) int i; for (i=0; domain_list[i]; ++i) { if (!strcasecmp(domain, domain_list[i])) - return (1u< Date: Tue, 20 Aug 2019 12:21:02 +1000 Subject: scripts/git: Remove a duplicate practracker call from the pre-push hook The pre-push hook already calls the pre-commit hook, which calls practracker. Also update the script comments to avoid similar issues in future. Fixes bug 31462; bugfix on 0.4.1.1-alpha. --- changes/bug31462 | 4 ++++ changes/ticket30979 | 8 +++++--- scripts/git/pre-commit.git-hook | 16 +++++++++++++--- scripts/git/pre-push.git-hook | 18 +++++++----------- 4 files changed, 29 insertions(+), 17 deletions(-) create mode 100644 changes/bug31462 (limited to 'changes') diff --git a/changes/bug31462 b/changes/bug31462 new file mode 100644 index 0000000000..54ab990bb8 --- /dev/null +++ b/changes/bug31462 @@ -0,0 +1,4 @@ + o Minor bugfixes (git hooks): + - Remove a duplicate call to practracker from the pre-push hook. + The pre-push hook already calls the pre-commit hook, which calls + practracker. Fixes bug 31462; bugfix on 0.4.1.1-alpha. diff --git a/changes/ticket30979 b/changes/ticket30979 index 8ae9b3c418..ffe1bfb4ab 100644 --- a/changes/ticket30979 +++ b/changes/ticket30979 @@ -1,5 +1,7 @@ o Minor features (git hooks): - - Our pre-push git hook now checks for a special file - before running practracker, so that it only runs on branches - that are based on master. + - Our pre-commit git hook now checks for a special file + before running practracker, so that practracker only runs on branches + that are based on master. Since the pre-push hook calls the pre-commit + hook, practracker will also only run before pushes of branches based + on master. Closes ticket 30979. diff --git a/scripts/git/pre-commit.git-hook b/scripts/git/pre-commit.git-hook index 2a29837198..37060fdbe8 100755 --- a/scripts/git/pre-commit.git-hook +++ b/scripts/git/pre-commit.git-hook @@ -4,7 +4,8 @@ # tor git repo and make sure it has permission to execute. # # This is pre-commit git hook script that prevents commiting your changeset if -# it fails our code formatting or changelog entry formatting checkers. +# it fails our code formatting, changelog entry formatting, module include +# rules, or best practices tracker. workdir=$(git rev-parse --show-toplevel) @@ -40,6 +41,15 @@ if test -e scripts/maint/checkIncludes.py; then python scripts/maint/checkIncludes.py fi -if [ -e scripts/maint/practracker/practracker.py ]; then - python3 ./scripts/maint/practracker/practracker.py "$workdir" +# Only call practracker if ${PT_DIR}/.enable_practracker_in_hooks exists +# We do this check so that we can enable practracker in hooks in master, and +# disable it on maint branches +PT_DIR=scripts/maint/practracker + +if [ -e "${PT_DIR}/practracker.py" ]; then + if [ -e "${PT_DIR}/.enable_practracker_in_hooks" ]; then + if ! python3 "${PT_DIR}/practracker.py" "$workdir"; then + exit 1 + fi + fi fi diff --git a/scripts/git/pre-push.git-hook b/scripts/git/pre-push.git-hook index 40a3bffa79..f4504c4215 100755 --- a/scripts/git/pre-push.git-hook +++ b/scripts/git/pre-push.git-hook @@ -1,10 +1,11 @@ #!/usr/bin/env bash # git pre-push hook script to: +# 0) Call the pre-commit hook, if it is available # 1) prevent "fixup!" and "squash!" commit from ending up in master, release-* # or maint-* # 2) Disallow pushing branches other than master, release-* -# and maint-* to origin (e.g. gitweb.torproject.org). +# and maint-* to origin (e.g. gitweb.torproject.org) # # To install this script, copy it into .git/hooks/pre-push path in your # local copy of git repository. Make sure it has permission to execute. @@ -21,6 +22,11 @@ z40=0000000000000000000000000000000000000000 upstream_name=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"} +# Are you adding a new check to the git hooks? +# - Common checks belong in the pre-commit hook +# - Push-only checks belong in the pre-push hook +# +# Call the pre-commit hook for the common checks, if it is executable. workdir=$(git rev-parse --show-toplevel) if [ -x "$workdir/.git/hooks/pre-commit" ]; then if ! "$workdir"/.git/hooks/pre-commit; then @@ -28,16 +34,6 @@ if [ -x "$workdir/.git/hooks/pre-commit" ]; then fi fi -PT_DIR=scripts/maint/practracker - -if [ -e "${PT_DIR}/practracker.py" ]; then - if [ -e "${PT_DIR}/.enable_practracker_in_hooks" ]; then - if ! python3 "${PT_DIR}/practracker.py" "$workdir"; then - exit 1 - fi - fi -fi - remote="$1" remote_name=$(git remote --verbose | grep "$2" | awk '{print $1}' | head -n 1) -- cgit v1.2.3-54-g00ecf From 360a29e282a546c47ad1346bb035ffb01fe11c0d Mon Sep 17 00:00:00 2001 From: Sebastian Hahn Date: Sun, 18 Aug 2019 21:31:09 +0200 Subject: Rust: Update version requirements and CI The #[global_allocator] attribute is not available in versions prior to 1.28.0, the default-linker-libraries feature requires rust 1.31.0. Adapt the CI to prevent accidental increases in Rust version by testing against 1.31.0, beta and nightly. --- .travis.yml | 10 ++++++---- changes/bug31442 | 3 +++ configure.ac | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 changes/bug31442 (limited to 'changes') diff --git a/.travis.yml b/.travis.yml index 36fb3a1b76..8ba33f1bc1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,8 @@ env: - HARDENING_OPTIONS="--enable-expensive-hardening" ## We turn off asciidoc by default, because it's slow - ASCIIDOC_OPTIONS="--disable-asciidoc" + ## Our default rust version is the minimum supported version + - RUST_VERSION="1.31.0" matrix: ## We want to use each build option at least once ## @@ -55,9 +57,9 @@ matrix: # We clone our stem repo and run `make test-stem` - env: TEST_STEM="yes" SKIP_MAKE_CHECK="yes" ## Check rust online with distcheck, to make sure we remove rust products - - env: DISTCHECK="yes" RUST_OPTIONS="--enable-rust --enable-cargo-online-mode" + - env: DISTCHECK="yes" RUST_VERSION="beta" RUST_OPTIONS="--enable-rust --enable-cargo-online-mode" ## Check disable module dirauth with and without rust - - env: MODULES_OPTIONS="--disable-module-dirauth" RUST_OPTIONS="--enable-rust" TOR_RUST_DEPENDENCIES=true + - env: MODULES_OPTIONS="--disable-module-dirauth" RUST_VERSION="nightly" RUST_OPTIONS="--enable-rust" TOR_RUST_DEPENDENCIES=true - env: MODULES_OPTIONS="--disable-module-dirauth" ## Check NSS - env: NSS_OPTIONS="--enable-nss" @@ -173,8 +175,8 @@ install: - if [[ "$ASCIIDOC_OPTIONS" == "" ]] && [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export XML_CATALOG_FILES="/usr/local/etc/xml/catalog"; fi ## If we're using Rust, download rustup - if [[ "$RUST_OPTIONS" != "" ]]; then curl -Ssf -o rustup.sh https://sh.rustup.rs; fi - ## Install the nightly channels of rustc and cargo and setup our toolchain environment - - if [[ "$RUST_OPTIONS" != "" ]]; then sh rustup.sh -y --default-toolchain nightly; fi + ## Install the stable channels of rustc and cargo and setup our toolchain environment + - if [[ "$RUST_OPTIONS" != "" ]]; then sh rustup.sh -y --default-toolchain $RUST_VERSION; fi - if [[ "$RUST_OPTIONS" != "" ]]; then source $HOME/.cargo/env; fi ## If we're testing rust builds in offline-mode, then set up our vendored dependencies - if [[ "$TOR_RUST_DEPENDENCIES" == "true" ]]; then export TOR_RUST_DEPENDENCIES=$PWD/src/ext/rust/crates; fi diff --git a/changes/bug31442 b/changes/bug31442 new file mode 100644 index 0000000000..4df9fc6dfb --- /dev/null +++ b/changes/bug31442 @@ -0,0 +1,3 @@ + o Minor bugfixes (rust): + - Raise the minimum rustc version to 1.31.0, as checked by configure + and CI. Fixes bug 31442; bugfix on 0.3.5.4-alpha. diff --git a/configure.ac b/configure.ac index 9ec123f51e..f90a0c09b1 100644 --- a/configure.ac +++ b/configure.ac @@ -558,8 +558,8 @@ if test "x$enable_rust" = "xyes"; then if test "x$RUSTC_VERSION_MAJOR" = "x" -o "x$RUSTC_VERSION_MINOR" = "x"; then AC_MSG_ERROR([rustc version couldn't be identified]) fi - if test "$RUSTC_VERSION_MAJOR" -lt 2 -a "$RUSTC_VERSION_MINOR" -lt 14; then - AC_MSG_ERROR([rustc must be at least version 1.14]) + if test "$RUSTC_VERSION_MAJOR" -lt 2 -a "$RUSTC_VERSION_MINOR" -lt 31; then + AC_MSG_ERROR([rustc must be at least version 1.31.0]) fi AC_MSG_RESULT([$RUSTC_VERSION]) fi -- cgit v1.2.3-54-g00ecf From 4b1e0dd5b53528996a3a0f92717e5ccbb8819a4b Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 20 Aug 2019 11:16:45 -0400 Subject: remove changes files already contained in 0.4.1.5 --- changes/bug30649 | 4 ---- changes/bug30894 | 4 ---- changes/bug30942 | 4 ---- changes/bug31003 | 4 ---- changes/bug31024 | 4 ---- changes/bug31027 | 3 --- changes/bug31080_041 | 4 ---- changes/bug31343 | 9 --------- changes/bug31356_and_logs | 11 ----------- changes/chutney_ci | 3 --- changes/ticket28795 | 5 ----- changes/ticket30591 | 3 --- changes/ticket30694 | 3 --- changes/ticket31001 | 6 ------ changes/ticket31311 | 3 --- changes/ticket31374 | 4 ---- changes/ticket31406 | 3 --- 17 files changed, 77 deletions(-) delete mode 100644 changes/bug30649 delete mode 100644 changes/bug30894 delete mode 100644 changes/bug30942 delete mode 100644 changes/bug31003 delete mode 100644 changes/bug31024 delete mode 100644 changes/bug31027 delete mode 100644 changes/bug31080_041 delete mode 100644 changes/bug31343 delete mode 100644 changes/bug31356_and_logs delete mode 100644 changes/chutney_ci delete mode 100644 changes/ticket28795 delete mode 100644 changes/ticket30591 delete mode 100644 changes/ticket30694 delete mode 100644 changes/ticket31001 delete mode 100644 changes/ticket31311 delete mode 100644 changes/ticket31374 delete mode 100644 changes/ticket31406 (limited to 'changes') diff --git a/changes/bug30649 b/changes/bug30649 deleted file mode 100644 index 3f5768bcb4..0000000000 --- a/changes/bug30649 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (circuit padding): - - On relays, properly check that a padding machine is absent before - logging a warn about it being absent. Fixes bug 30649; - bugfix on 0.4.1.1-alpha. diff --git a/changes/bug30894 b/changes/bug30894 deleted file mode 100644 index 64c14c4e6d..0000000000 --- a/changes/bug30894 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (memory leaks): - - Fix a trivial memory leak when parsing an invalid value - from a download schedule in the configuration. Fixes bug - 30894; bugfix on 0.3.4.1-alpha. diff --git a/changes/bug30942 b/changes/bug30942 deleted file mode 100644 index bd6b2ff581..0000000000 --- a/changes/bug30942 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (circuit padding): - - Ignore non-padding cells on padding circuits. This addresses various - warning messages from subsystems that were not expecting padding - circuits. Fixes bug 30942; bugfix on 0.4.1.1-alpha. \ No newline at end of file diff --git a/changes/bug31003 b/changes/bug31003 deleted file mode 100644 index 6c75163380..0000000000 --- a/changes/bug31003 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (crash on exit): - - Avoid a set of possible code paths that could use try to use freed memory - in routerlist_free() while Tor was exiting. Fixes bug 31003; bugfix on - 0.1.2.2-alpha. diff --git a/changes/bug31024 b/changes/bug31024 deleted file mode 100644 index 888fb2a26b..0000000000 --- a/changes/bug31024 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (circuitpadding): - - Add two NULL checks in unreachable places to silence Coverity (CID 144729 - and 1447291) and better future proof ourselves. Fixes bug 31024; bugfix - on 0.4.1.1-alpha. \ No newline at end of file diff --git a/changes/bug31027 b/changes/bug31027 deleted file mode 100644 index dd3ce20b60..0000000000 --- a/changes/bug31027 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Remove some dead code from circpad_machine_remove_token() to fix some - Coverity warnings (CID 1447298). Fixes bug 31027; bugfix on 0.4.1.1-alpha. \ No newline at end of file diff --git a/changes/bug31080_041 b/changes/bug31080_041 deleted file mode 100644 index 1fe9ec508d..0000000000 --- a/changes/bug31080_041 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (logging): - - Fix a conflict between the flag used for messaging-domain - log messages, and the LD_NO_MOCK testing flag. Fixes bug 31080; - bugfix on 0.4.1.1-alpha. diff --git a/changes/bug31343 b/changes/bug31343 deleted file mode 100644 index 17a8057ead..0000000000 --- a/changes/bug31343 +++ /dev/null @@ -1,9 +0,0 @@ - o Minor bugfixes (compilation): - - Avoid using labs() on time_t, which can cause compilation warnings - on 64-bit Windows builds. Fixes bug 31343; bugfix on 0.2.4.4-alpha. - - o Minor bugfixes (clock skew detection): - - Don't believe clock skew results from NETINFO cells that appear to - arrive before the VERSIONS cells they are responding to were sent. - Previously, we would accept them up to 3 minutes "in the past". - Fixes bug 31343; bugfix on 0.2.4.4-alpha. diff --git a/changes/bug31356_and_logs b/changes/bug31356_and_logs deleted file mode 100644 index fb5307cb69..0000000000 --- a/changes/bug31356_and_logs +++ /dev/null @@ -1,11 +0,0 @@ - o Minor bugfixes (circuit padding negotiation): - - Bump circuit padding protover to explicitly signify that the hs setup - machine support is finalized in 0.4.1.x-stable. This also means that - 0.4.1.x-alpha clients will not negotiate padding with 0.4.1.x-stable - relays, and 0.4.1.x-stable clients will not negotiate padding with - 0.4.1.x-alpha relays (or 0.4.0.x relays). Fixes bug 31356; - bugfix on 0.4.1.1-alpha. - o Minor features (circuit padding logging): - - Demote noisy client-side warn log to a protocol warning. Add additional - log messages and circuit id fields to help with fixing bug 30992 and any - other future issues. diff --git a/changes/chutney_ci b/changes/chutney_ci deleted file mode 100644 index b17d587329..0000000000 --- a/changes/chutney_ci +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (continuous integration): - - Our Travis configuration now uses Chutney to run some network - integration tests automatically. Closes ticket 29280. diff --git a/changes/ticket28795 b/changes/ticket28795 deleted file mode 100644 index 6ae72562bf..0000000000 --- a/changes/ticket28795 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (fallback directory list): - - Replace the 157 fallbacks originally introduced in Tor 0.3.5.6-rc - in December 2018 (of which ~122 were still functional), with a - list of 148 fallbacks (70 new, 78 existing, 79 removed) generated - in June 2019. Closes ticket 28795. diff --git a/changes/ticket30591 b/changes/ticket30591 deleted file mode 100644 index f97c024009..0000000000 --- a/changes/ticket30591 +++ /dev/null @@ -1,3 +0,0 @@ - o Testing (continuous integration): - - In Travis, make stem log a controller trace to the console. And tail - stem's tor log after failure. Closes ticket 30591. diff --git a/changes/ticket30694 b/changes/ticket30694 deleted file mode 100644 index 70dbf6481a..0000000000 --- a/changes/ticket30694 +++ /dev/null @@ -1,3 +0,0 @@ - o Testing (continuous integration): - - In Travis, only run the stem tests that use a tor binary. - Closes ticket 30694. diff --git a/changes/ticket31001 b/changes/ticket31001 deleted file mode 100644 index 2ce1cbdf34..0000000000 --- a/changes/ticket31001 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (compatibility, standards compliance): - - Fix a bug that would invoke undefined behavior on certain operating - systems when trying to asprintf() a string exactly INT_MAX bytes - long. We don't believe this is exploitable, but it's better - to fix it anyway. Fixes bug 31001; bugfix on 0.2.2.11-alpha. - Found and fixed by Tobias Stoeckmann. diff --git a/changes/ticket31311 b/changes/ticket31311 deleted file mode 100644 index 88dfb85736..0000000000 --- a/changes/ticket31311 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (distribution): - - Do not ship any temporary files found in the scripts/maint/practracker - directory. Fixes bug 31311; bugfix on 0.4.1.1-alpha. diff --git a/changes/ticket31374 b/changes/ticket31374 deleted file mode 100644 index e8eef9cd49..0000000000 --- a/changes/ticket31374 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (compilation warning): - - Fix a compilation warning on Windows about casting a function - pointer for GetTickCount64(). Fixes bug 31374; bugfix on - 0.2.9.1-alpha. diff --git a/changes/ticket31406 b/changes/ticket31406 deleted file mode 100644 index 0ebe6f6c47..0000000000 --- a/changes/ticket31406 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (directory authority): - - A new IP address the directory authority "dizum" has been changed. Closes - ticket 31406; -- cgit v1.2.3-54-g00ecf From 5794523f800a2693f0b4a192821f5ac6dfbeb27c Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 23 Aug 2019 00:06:55 +1000 Subject: changes: file for 21003 Log IPv6 addresses as well as IPv4 addresses, when describing routerinfos, routerstatuses, and nodes. Closes ticket 21003. --- changes/ticket21003 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket21003 (limited to 'changes') diff --git a/changes/ticket21003 b/changes/ticket21003 new file mode 100644 index 0000000000..896d7493eb --- /dev/null +++ b/changes/ticket21003 @@ -0,0 +1,3 @@ + o Minor features (IPv6, logging): + - Log IPv6 addresses as well as IPv4 addresses, when describing + routerinfos, routerstatuses, and nodes. Closes ticket 21003. -- cgit v1.2.3-54-g00ecf From 14654d5c97663d5f2552b9f27620c8d829dd8d52 Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Fri, 23 Aug 2019 14:04:05 -0400 Subject: Remove the unused circuit_type field from hs_ident_circuit_t and hs_ident_circuit_new() --- changes/bug31490 | 6 ++++++ src/core/or/circuituse.c | 3 +-- src/feature/hs/hs_circuit.c | 6 ++---- src/feature/hs/hs_ident.c | 6 +----- src/feature/hs/hs_ident.h | 10 +--------- src/test/test_hs_client.c | 9 +++------ src/test/test_hs_service.c | 9 +++------ 7 files changed, 17 insertions(+), 32 deletions(-) create mode 100644 changes/bug31490 (limited to 'changes') diff --git a/changes/bug31490 b/changes/bug31490 new file mode 100644 index 0000000000..24782be3ec --- /dev/null +++ b/changes/bug31490 @@ -0,0 +1,6 @@ + o Minor bugfixes (onion services): + - In the hs_ident_circuit_t data structure, remove the unused field + circuit_type and the respective argument in hs_ident_circuit_new(). + This field is set by clients (for introduction) and services (for + introduction and rendezvous) but is never used afterwards. Fixes + bug 31490; bugfix on 0.3.2.1-alpha. Patch by Neel Chauhan. diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c index 18b419e99d..606c5e2dd2 100644 --- a/src/core/or/circuituse.c +++ b/src/core/or/circuituse.c @@ -2533,8 +2533,7 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn, circ->rend_data = rend_data_dup(edge_conn->rend_data); } else if (edge_conn->hs_ident) { circ->hs_ident = - hs_ident_circuit_new(&edge_conn->hs_ident->identity_pk, - HS_IDENT_CIRCUIT_INTRO); + hs_ident_circuit_new(&edge_conn->hs_ident->identity_pk); } if (circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND && circ->base_.state == CIRCUIT_STATE_OPEN) diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c index a6e86c5ab3..259ffb1441 100644 --- a/src/feature/hs/hs_circuit.c +++ b/src/feature/hs/hs_circuit.c @@ -259,8 +259,7 @@ create_rp_circuit_identifier(const hs_service_t *service, tor_assert(server_pk); tor_assert(keys); - ident = hs_ident_circuit_new(&service->keys.identity_pk, - HS_IDENT_CIRCUIT_RENDEZVOUS); + ident = hs_ident_circuit_new(&service->keys.identity_pk); /* Copy the RENDEZVOUS_COOKIE which is the unique identifier. */ memcpy(ident->rendezvous_cookie, rendezvous_cookie, sizeof(ident->rendezvous_cookie)); @@ -294,8 +293,7 @@ create_intro_circuit_identifier(const hs_service_t *service, tor_assert(service); tor_assert(ip); - ident = hs_ident_circuit_new(&service->keys.identity_pk, - HS_IDENT_CIRCUIT_INTRO); + ident = hs_ident_circuit_new(&service->keys.identity_pk); ed25519_pubkey_copy(&ident->intro_auth_pk, &ip->auth_key_kp.pubkey); return ident; diff --git a/src/feature/hs/hs_ident.c b/src/feature/hs/hs_ident.c index 8fd0013941..a00e55ec23 100644 --- a/src/feature/hs/hs_ident.c +++ b/src/feature/hs/hs_ident.c @@ -13,14 +13,10 @@ /* Return a newly allocated circuit identifier. The given public key is copied * identity_pk into the identifier. */ hs_ident_circuit_t * -hs_ident_circuit_new(const ed25519_public_key_t *identity_pk, - hs_ident_circuit_type_t circuit_type) +hs_ident_circuit_new(const ed25519_public_key_t *identity_pk) { - tor_assert(circuit_type == HS_IDENT_CIRCUIT_INTRO || - circuit_type == HS_IDENT_CIRCUIT_RENDEZVOUS); hs_ident_circuit_t *ident = tor_malloc_zero(sizeof(*ident)); ed25519_pubkey_copy(&ident->identity_pk, identity_pk); - ident->circuit_type = circuit_type; return ident; } diff --git a/src/feature/hs/hs_ident.h b/src/feature/hs/hs_ident.h index 8c46936a1e..82ca50f6b5 100644 --- a/src/feature/hs/hs_ident.h +++ b/src/feature/hs/hs_ident.h @@ -44,13 +44,6 @@ typedef struct hs_ident_circuit_t { * the one found in the onion address. */ ed25519_public_key_t identity_pk; - /* (All circuit) The type of circuit this identifier is attached to. - * Accessors of the fields in this object assert non fatal on this circuit - * type. In other words, if a rendezvous field is being accessed, the - * circuit type MUST BE of type HS_IDENT_CIRCUIT_RENDEZVOUS. This value is - * set when an object is initialized in its constructor. */ - hs_ident_circuit_type_t circuit_type; - /* (All circuit) Introduction point authentication key. It's also needed on * the rendezvous circuit for the ntor handshake. It's used as the unique key * of the introduction point so it should not be shared between multiple @@ -120,8 +113,7 @@ typedef struct hs_ident_edge_conn_t { /* Circuit identifier API. */ hs_ident_circuit_t *hs_ident_circuit_new( - const ed25519_public_key_t *identity_pk, - hs_ident_circuit_type_t circuit_type); + const ed25519_public_key_t *identity_pk); void hs_ident_circuit_free_(hs_ident_circuit_t *ident); #define hs_ident_circuit_free(id) \ FREE_AND_NULL(hs_ident_circuit_t, hs_ident_circuit_free_, (id)) diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c index fb497d52a1..b777dafdfb 100644 --- a/src/test/test_hs_client.c +++ b/src/test/test_hs_client.c @@ -160,8 +160,7 @@ helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out, or_circ->rend_data = rend_data_dup(conn_rend_data); } else { /* prop224: Setup hs ident on the circuit */ - or_circ->hs_ident = hs_ident_circuit_new(&service_pk, - HS_IDENT_CIRCUIT_RENDEZVOUS); + or_circ->hs_ident = hs_ident_circuit_new(&service_pk); } TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN; @@ -964,8 +963,7 @@ test_close_intro_circuits_new_desc(void *arg) const hs_desc_intro_point_t *ip = smartlist_get(desc1->encrypted_data.intro_points, 0); tt_assert(ip); - ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey, - HS_IDENT_CIRCUIT_INTRO); + ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey); ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &ip->auth_key_cert->signed_key); } @@ -1066,8 +1064,7 @@ test_close_intro_circuits_cache_clean(void *arg) const hs_desc_intro_point_t *ip = smartlist_get(desc1->encrypted_data.intro_points, 0); tt_assert(ip); - ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey, - HS_IDENT_CIRCUIT_INTRO); + ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey); ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &ip->auth_key_cert->signed_key); } diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c index 2e4be4e295..c0803a5a59 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -171,8 +171,7 @@ test_e2e_rend_circuit_setup(void *arg) tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sk, 0)); tt_int_op(0, OP_EQ, ed25519_public_key_generate(&service_pk, &sk)); - or_circ->hs_ident = hs_ident_circuit_new(&service_pk, - HS_IDENT_CIRCUIT_RENDEZVOUS); + or_circ->hs_ident = hs_ident_circuit_new(&service_pk); TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN; } @@ -1105,8 +1104,7 @@ test_closing_intro_circs(void *arg) /* Initialize intro circuit */ intro_circ = origin_circuit_init(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, flags); - intro_circ->hs_ident = hs_ident_circuit_new(&service->keys.identity_pk, - HS_IDENT_CIRCUIT_INTRO); + intro_circ->hs_ident = hs_ident_circuit_new(&service->keys.identity_pk); /* Register circuit in the circuitmap . */ hs_circuitmap_register_intro_circ_v3_service_side(intro_circ, &ip->auth_key_kp.pubkey); @@ -1132,8 +1130,7 @@ test_closing_intro_circs(void *arg) /* Now pretend that a new intro point circ was launched and opened. Check * that the intro point will be established correctly. */ intro_circ = origin_circuit_init(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, flags); - intro_circ->hs_ident = hs_ident_circuit_new(&service->keys.identity_pk, - HS_IDENT_CIRCUIT_INTRO); + intro_circ->hs_ident = hs_ident_circuit_new(&service->keys.identity_pk); ed25519_pubkey_copy(&intro_circ->hs_ident->intro_auth_pk, &ip->auth_key_kp.pubkey); /* Register circuit in the circuitmap . */ -- cgit v1.2.3-54-g00ecf From f95b5d07c1a0407a60ca6335c032ec7a01b28968 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 14 Aug 2019 11:15:39 -0400 Subject: hs-v3: Add changes file for prop305 implementation Signed-off-by: David Goulet --- changes/ticket30924 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/ticket30924 (limited to 'changes') diff --git a/changes/ticket30924 b/changes/ticket30924 new file mode 100644 index 0000000000..832c377972 --- /dev/null +++ b/changes/ticket30924 @@ -0,0 +1,6 @@ + o Major features (onion service v3, denial of service): + - Add onion service introduction denial of service defenses. They consist of + rate limiting client introduction at the intro point using parameters that + can be sent by the service within the ESTABLISH_INTRO cell. If the cell + extension for this is not used, the intro point will honor the consensus + parameters. Closes ticket 30924. -- cgit v1.2.3-54-g00ecf From 38c4e1426c2964f4c27d2486b81867bff6d55b8a Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 26 Aug 2019 09:33:29 -0400 Subject: changes file for ticket30935 --- changes/ticket30935 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/ticket30935 (limited to 'changes') diff --git a/changes/ticket30935 b/changes/ticket30935 new file mode 100644 index 0000000000..5a7e918895 --- /dev/null +++ b/changes/ticket30935 @@ -0,0 +1,6 @@ + o Code simplification and refactoring: + - Numerous simplifications in configuration-handling logic: + remove duplicated macro definitions, replace magical names + with flags, and refactor "TestingTorNetwork" to use the + same default-option logic as the rest of Tor. + Closes ticket 30935. -- cgit v1.2.3-54-g00ecf From cc5af6dbd5d27cc80fba9df65eea1fff5833a08d Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Fri, 19 Jul 2019 13:11:45 -0400 Subject: Add changes file for Bug #31088 --- changes/bug31088 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/bug31088 (limited to 'changes') diff --git a/changes/bug31088 b/changes/bug31088 new file mode 100644 index 0000000000..c258d1bada --- /dev/null +++ b/changes/bug31088 @@ -0,0 +1,5 @@ + o Minor bugfixes (ipv6): + - We check for private IPv6 address alongside their IPv4 equivalents when + authorities check descriptors. Previously, we only checked for private + IPv4 addresses. Fixes bug 31088; bugfix on 0.2.3.21-rc. Patch by Neel + Chauhan. -- cgit v1.2.3-54-g00ecf From ec6fbf1ca613c11dc783182a11bc1d04f6a3fb63 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 29 Aug 2019 12:39:44 +1000 Subject: nodelist: Use safe string functions in describe.c Rewrite format_node_description() and router_get_verbose_nickname() to use strlcpy() and strlcat(). The previous implementation used memcpy() and pointer arithmetic, which was error-prone. Closes ticket 31545. This is CID 1452819. --- changes/ticket31545 | 5 ++ src/feature/nodelist/describe.c | 101 +++++++++++++++++++++++++++++++--------- 2 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 changes/ticket31545 (limited to 'changes') diff --git a/changes/ticket31545 b/changes/ticket31545 new file mode 100644 index 0000000000..58921c2ad8 --- /dev/null +++ b/changes/ticket31545 @@ -0,0 +1,5 @@ + o Code simplification and refactoring: + - Rewrite format_node_description() and router_get_verbose_nickname() to + use strlcpy() and strlcat(). The previous implementation used memcpy() + and pointer arithmetic, which was error-prone. + Closes ticket 31545. This is CID 1452819. diff --git a/src/feature/nodelist/describe.c b/src/feature/nodelist/describe.c index 7ec18438c1..1e46837685 100644 --- a/src/feature/nodelist/describe.c +++ b/src/feature/nodelist/describe.c @@ -29,7 +29,8 @@ * NULL or the null address. The addr32h field is optional and may be * set to 0. * - * Return a pointer to the front of buf, or a string constant on error. + * Return a pointer to the front of buf. + * If buf is NULL, return a string constant describing the error. */ STATIC const char * format_node_description(char *buf, @@ -38,7 +39,7 @@ format_node_description(char *buf, const tor_addr_t *addr, uint32_t addr32h) { - char *cp; + size_t rv = 0; bool has_addr = addr && !tor_addr_is_null(addr); if (!buf) @@ -47,34 +48,67 @@ format_node_description(char *buf, memset(buf, 0, NODE_DESC_BUF_LEN); if (!id_digest) { - memcpy(buf, "", 17); + /* strlcpy() returns the length of the source string it attempted to copy, + * ignoring any required truncation due to the buffer length. */ + rv = strlcpy(buf, "", NODE_DESC_BUF_LEN); + tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); return buf; } - buf[0] = '$'; - base16_encode(buf+1, HEX_DIGEST_LEN+1, id_digest, DIGEST_LEN); - cp = buf+1+HEX_DIGEST_LEN; + /* strlcat() returns the length of the concatenated string it attempted to + * create, ignoring any required truncation due to the buffer length. */ + rv = strlcat(buf, "$", NODE_DESC_BUF_LEN); + tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); + + { + char hex_digest[HEX_DIGEST_LEN+1]; + memset(hex_digest, 0, sizeof(hex_digest)); + + base16_encode(hex_digest, sizeof(hex_digest), + id_digest, DIGEST_LEN); + rv = strlcat(buf, hex_digest, NODE_DESC_BUF_LEN); + tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); + } + if (nickname) { - buf[1+HEX_DIGEST_LEN] = '~'; - strlcpy(buf+1+HEX_DIGEST_LEN+1, nickname, MAX_NICKNAME_LEN+1); - cp += strlen(cp); + rv = strlcat(buf, "~", NODE_DESC_BUF_LEN); + tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); + rv = strlcat(buf, nickname, NODE_DESC_BUF_LEN); + tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); } if (addr32h || has_addr) { - memcpy(cp, " at ", 4); - cp += 4; + rv = strlcat(buf, " at ", NODE_DESC_BUF_LEN); + tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); } if (addr32h) { + int ntoa_rv = 0; + char ipv4_addr_str[INET_NTOA_BUF_LEN]; + memset(ipv4_addr_str, 0, sizeof(ipv4_addr_str)); struct in_addr in; + memset(&in, 0, sizeof(in)); + in.s_addr = htonl(addr32h); - tor_inet_ntoa(&in, cp, INET_NTOA_BUF_LEN); - cp += strlen(cp); + ntoa_rv = tor_inet_ntoa(&in, ipv4_addr_str, sizeof(ipv4_addr_str)); + tor_assert_nonfatal(ntoa_rv >= 0); + + rv = strlcat(buf, ipv4_addr_str, NODE_DESC_BUF_LEN); + tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); } + /* Both addresses are valid */ if (addr32h && has_addr) { - memcpy(cp, " and ", 5); - cp += 5; + rv = strlcat(buf, " and ", NODE_DESC_BUF_LEN); + tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); } if (has_addr) { - tor_addr_to_str(cp, addr, TOR_ADDR_BUF_LEN, 1); + const char *str_rv = NULL; + char addr_str[TOR_ADDR_BUF_LEN]; + memset(addr_str, 0, sizeof(addr_str)); + + str_rv = tor_addr_to_str(addr_str, addr, sizeof(addr_str), 1); + tor_assert_nonfatal(str_rv == addr_str); + + rv = strlcat(buf, addr_str, NODE_DESC_BUF_LEN); + tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN); } return buf; @@ -92,6 +126,7 @@ router_describe(const routerinfo_t *ri) if (!ri) return ""; + return format_node_description(buf, ri->cache_info.identity_digest, ri->nickname, @@ -152,6 +187,7 @@ routerstatus_describe(const routerstatus_t *rs) if (!rs) return ""; + return format_node_description(buf, rs->identity_digest, rs->nickname, @@ -171,6 +207,7 @@ extend_info_describe(const extend_info_t *ei) if (!ei) return ""; + return format_node_description(buf, ei->identity_digest, ei->nickname, @@ -188,19 +225,39 @@ extend_info_describe(const extend_info_t *ei) void router_get_verbose_nickname(char *buf, const routerinfo_t *router) { + size_t rv = 0; + if (!buf) return; memset(buf, 0, MAX_VERBOSE_NICKNAME_LEN+1); if (!router) { - memcpy(buf, "", 7); + /* strlcpy() returns the length of the source string it attempted to copy, + * ignoring any required truncation due to the buffer length. */ + rv = strlcpy(buf, "", MAX_VERBOSE_NICKNAME_LEN+1); + tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1); return; } - buf[0] = '$'; - base16_encode(buf+1, HEX_DIGEST_LEN+1, router->cache_info.identity_digest, - DIGEST_LEN); - buf[1+HEX_DIGEST_LEN] = '~'; - strlcpy(buf+1+HEX_DIGEST_LEN+1, router->nickname, MAX_NICKNAME_LEN+1); + /* strlcat() returns the length of the concatenated string it attempted to + * create, ignoring any required truncation due to the buffer length. */ + rv = strlcat(buf, "$", MAX_VERBOSE_NICKNAME_LEN+1); + tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1); + + { + char hex_digest[HEX_DIGEST_LEN+1]; + memset(hex_digest, 0, sizeof(hex_digest)); + + base16_encode(hex_digest, sizeof(hex_digest), + router->cache_info.identity_digest, DIGEST_LEN); + rv = strlcat(buf, hex_digest, MAX_VERBOSE_NICKNAME_LEN+1); + tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1); + } + + rv = strlcat(buf, "~", MAX_VERBOSE_NICKNAME_LEN+1); + tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1); + + rv = strlcat(buf, router->nickname, MAX_VERBOSE_NICKNAME_LEN+1); + tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1); } -- cgit v1.2.3-54-g00ecf From 667311ebbd6fe6c43da8eb5abc1e34e30fb5b911 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 9 Aug 2019 00:18:56 +1000 Subject: scripts/git: Add test branch support to the git scripts Add a -t argument to git-merge-forward.sh and git-push-all.sh, which makes these scripts create, merge forward, and push test branches. Add a -r argument to git-push-all.sh, so the script can push test branches to a personal remote. Closes ticket 31314. --- changes/ticket31314 | 6 ++ scripts/git/git-merge-forward.sh | 150 +++++++++++++++++++++++++++++++++------ scripts/git/git-push-all.sh | 94 +++++++++++++++++++++--- 3 files changed, 218 insertions(+), 32 deletions(-) create mode 100644 changes/ticket31314 (limited to 'changes') diff --git a/changes/ticket31314 b/changes/ticket31314 new file mode 100644 index 0000000000..e1d9fb767b --- /dev/null +++ b/changes/ticket31314 @@ -0,0 +1,6 @@ + o Minor features (git scripts): + - Add a -t argument to git-merge-forward.sh and + git-push-all.sh, which makes these scripts create, merge forward, and + push test branches. Closes ticket 31314. + - Add a -r argument to git-push-all.sh, so the script can + push test branches to a personal remote. Closes ticket 31314. diff --git a/scripts/git/git-merge-forward.sh b/scripts/git/git-merge-forward.sh index e2b5bde49c..1f4ddb85e7 100755 --- a/scripts/git/git-merge-forward.sh +++ b/scripts/git/git-merge-forward.sh @@ -33,20 +33,45 @@ TOR_WKT_NAME=${TOR_WKT_NAME:-"tor-wkt"} # Configuration of the branches that needs merging. The values are in order: # (0) current maint/release branch name # (1) previous maint/release name to merge into (0) +# (only used in merge forward mode) # (2) Full path of the git worktree +# (3) current branch suffix +# (maint branches only, only used in test branch mode) +# (4) previous test branch suffix to merge into (3) +# (maint branches only, only used in test branch mode) # -# As an example: +# Merge forward example: # $ cd (2) # $ git checkout maint-0.3.5 (0) # $ git pull # $ git merge maint-0.3.4 (1) # +# Test branch example: +# $ cd (2) +# $ git checkout -b ticket99999_035 (3) +# $ git checkout maint-0.3.5 (0) +# $ git pull +# $ git checkout ticket99999_035 +# $ git merge maint-0.3.5 +# $ git merge ticket99999_034 (4) +# # First set of arrays are the maint-* branch and then the release-* branch. # New arrays need to be in the WORKTREE= array else they aren't considered. -MAINT_035=( "maint-0.3.5" "maint-0.2.9" "$GIT_PATH/$TOR_WKT_NAME/maint-0.3.5" ) -MAINT_040=( "maint-0.4.0" "maint-0.3.5" "$GIT_PATH/$TOR_WKT_NAME/maint-0.4.0" ) -MAINT_041=( "maint-0.4.1" "maint-0.4.0" "$GIT_PATH/$TOR_WKT_NAME/maint-0.4.1" ) -MAINT_MASTER=( "master" "maint-0.4.1" "$GIT_PATH/$TOR_MASTER_NAME" ) +# +# Only used in test branch mode +# There is no previous branch to merge forward, so the second and fifth items +# must be blank ("") +MAINT_029_TB=( "maint-0.2.9" "" "$GIT_PATH/$TOR_WKT_NAME/maint-0.2.9" \ + "_029" "") +# Used in maint/release merge and test branch modes +MAINT_035=( "maint-0.3.5" "maint-0.2.9" "$GIT_PATH/$TOR_WKT_NAME/maint-0.3.5" \ + "_035" "_029") +MAINT_040=( "maint-0.4.0" "maint-0.3.5" "$GIT_PATH/$TOR_WKT_NAME/maint-0.4.0" \ + "_040" "_035") +MAINT_041=( "maint-0.4.1" "maint-0.4.0" "$GIT_PATH/$TOR_WKT_NAME/maint-0.4.1" \ + "_041" "_040") +MAINT_MASTER=( "master" "maint-0.4.1" "$GIT_PATH/$TOR_MASTER_NAME" \ + "_master" "_041") RELEASE_029=( "release-0.2.9" "maint-0.2.9" "$GIT_PATH/$TOR_WKT_NAME/release-0.2.9" ) RELEASE_035=( "release-0.3.5" "maint-0.3.5" "$GIT_PATH/$TOR_WKT_NAME/release-0.3.5" ) @@ -60,6 +85,7 @@ ORIGIN_PATH="$GIT_PATH/$TOR_MASTER_NAME" # SC2034 -- shellcheck thinks that these are unused. We know better. ACTUALLY_THESE_ARE_USED=< option. The test branch base +# name option makes git-merge-forward.sh create new test branches: +# _029, _035, ... , _master, and merge forward. +TEST_BRANCH_PREFIX= + +while getopts "nt:" opt; do case "$opt" in n) DRY_RUN=1 echo " *** DRY RUN MODE ***" ;; + t) TEST_BRANCH_PREFIX="$OPTARG" + echo " *** CREATING TEST BRANCHES: ${TEST_BRANCH_PREFIX}_nnn ***" + ;; *) exit 1 ;; @@ -93,22 +127,44 @@ done # Git worktrees to manage # ########################### -# List of all worktrees to work on. All defined above. Ordering is important. -# Always the maint-* branch BEFORE then the release-*. -WORKTREE=( - RELEASE_029[@] +if [ -z "$TEST_BRANCH_PREFIX" ]; then + + # maint/release merge mode + # + # List of all worktrees to work on. All defined above. Ordering is important. + # Always the maint-* branch BEFORE then the release-*. + WORKTREE=( + RELEASE_029[@] + + MAINT_035[@] + RELEASE_035[@] + + MAINT_040[@] + RELEASE_040[@] + + MAINT_041[@] + RELEASE_041[@] + + MAINT_MASTER[@] + ) + +else + + # Test branch mode: merge to maint only, and create a new branch for 0.2.9 + WORKTREE=( + MAINT_029_TB[@] + + MAINT_035[@] - MAINT_035[@] - RELEASE_035[@] + MAINT_040[@] - MAINT_040[@] - RELEASE_040[@] + MAINT_041[@] - MAINT_041[@] - RELEASE_041[@] + MAINT_MASTER[@] + ) + +fi - MAINT_MASTER[@] -) COUNT=${#WORKTREE[@]} ############# @@ -161,6 +217,19 @@ function switch_branch fi } +# Checkout a new branch with the given branch name. +function new_branch +{ + local cmd="git checkout -b $1" + printf " %s Creating new branch %s..." "$MARKER" "$1" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + # Pull the given branch name. function pull_branch { @@ -236,16 +305,51 @@ for ((i=0; i +# Usage: git-push-all.sh -t -r # env vars: TOR_UPSTREAM_REMOTE_NAME=upstream TOR_PUSH_DELAY=0 # git-opts: --no-atomic --dry-run (any other git push option) # @@ -17,10 +17,49 @@ set -e # Don't change this configuration - set the env vars in your .profile # # The upstream remote which git.torproject.org/tor.git points to. +# In test branch mode, override this setting with -r UPSTREAM_REMOTE=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"} # Add a delay between pushes, so CI runs on the most important branches first PUSH_DELAY=${TOR_PUSH_DELAY:-0} +####################### +# Argument processing # +####################### + +# Controlled by the -t option. The test branch base +# name option makes git-merge-forward.sh create new test branches: +# _029, _035, ... , _master, and merge forward. +TEST_BRANCH_PREFIX= + +while getopts ":r:t:" opt; do + case "$opt" in + r) UPSTREAM_REMOTE="$OPTARG" + echo " *** PUSHING TO REMOTE: ${UPSTREAM_REMOTE} ***" + shift + shift + OPTIND=$[$OPTIND - 2] + ;; + t) TEST_BRANCH_PREFIX="$OPTARG" + echo " *** PUSHING TEST BRANCHES: ${TEST_BRANCH_PREFIX}_nnn ***" + shift + shift + OPTIND=$[$OPTIND - 2] + ;; + *) + # Assume git push will handle the option + ;; + esac +done + +if [ "$TEST_BRANCH_PREFIX" ]; then + if [ "$UPSTREAM_REMOTE" = ${TOR_UPSTREAM_REMOTE_NAME:-"upstream"} ]; then + echo "Pushing test branches ${TEST_BRANCH_PREFIX}_nnn to " \ + "$UPSTREAM_REMOTE is not allowed." + echo "Usage: $0 -r -t " + exit 1 + fi +fi + ######################## # Git branches to push # ######################## @@ -33,6 +72,32 @@ PUSH_BRANCHES=$(echo \ {release,maint}-0.2.9 \ ) +if [ -z "$TEST_BRANCH_PREFIX" ]; then + + # maint/release push mode + # + # List of branches to push. Ordering is not important. + PUSH_BRANCHES=$(echo \ + master \ + {release,maint}-0.4.1 \ + {release,maint}-0.4.0 \ + {release,maint}-0.3.5 \ + {release,maint}-0.2.9 \ + ) +else + + # Test branch mode: merge to maint only, and create a new branch for 0.2.9 + # + # List of branches to push. Ordering is not important. + PUSH_BRANCHES=$(echo \ + ${TEST_BRANCH_PREFIX}_master \ + ${TEST_BRANCH_PREFIX}_041 \ + ${TEST_BRANCH_PREFIX}_040 \ + ${TEST_BRANCH_PREFIX}_035 \ + ${TEST_BRANCH_PREFIX}_029 \ + ) +fi + ############### # Entry point # ############### @@ -48,18 +113,29 @@ if [ "$PUSH_DELAY" -le 0 ]; then else PUSH_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\n" | sort -V) MASTER_BRANCH=$(echo "$PUSH_BRANCHES" | tr " " "\n" | grep master) - MAINT_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\n" | grep maint) - RELEASE_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\n" | grep release | \ - tr "\n" " ") - printf "Pushing with %ss delays, so CI runs in this order:\n%s\n%s\n%s\n" \ - "$PUSH_DELAY" "$MASTER_BRANCH" "$MAINT_BRANCHES" "$RELEASE_BRANCHES" + if [ -z "$TEST_BRANCH_PREFIX" ]; then + MAINT_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\n" | grep maint) + RELEASE_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\n" | grep release | \ + tr "\n" " ") + printf "Pushing with %ss delays, so CI runs in this order:\n%s\n%s\n%s\n" \ + "$PUSH_DELAY" "$MASTER_BRANCH" "$MAINT_BRANCHES" "$RELEASE_BRANCHES" + else + # Actually test branches based on maint branches + MAINT_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\n" | grep -v master) + printf "Pushing with %ss delays, so CI runs in this order:\n%s\n%s\n" \ + "$PUSH_DELAY" "$MASTER_BRANCH" "$MAINT_BRANCHES" + # No release branches + RELEASE_BRANCHES= + fi git push "$@" "$UPSTREAM_REMOTE" "$MASTER_BRANCH" sleep "$PUSH_DELAY" # shellcheck disable=SC2086 for b in $MAINT_BRANCHES; do - git push "$@" "$UPSTREAM_REMOTE" $b + git push "$@" "$UPSTREAM_REMOTE" "$b" sleep "$PUSH_DELAY" done - # shellcheck disable=SC2086 - git push --atomic "$@" "$UPSTREAM_REMOTE" $RELEASE_BRANCHES + if [ "$RELEASE_BRANCHES" ]; then + # shellcheck disable=SC2086 + git push --atomic "$@" "$UPSTREAM_REMOTE" $RELEASE_BRANCHES + fi fi -- cgit v1.2.3-54-g00ecf From 15782758c7c9e170fccc138a0c4897a602217641 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 9 Aug 2019 14:37:38 +1000 Subject: scripts/git: Allow git-merge-forward.sh to re-use existing test branches Add a -u argument to git-merge-forward.sh, so that the script can re-use existing test branches after a merge failure and fix. Part of 31314. --- changes/ticket31314 | 3 +++ scripts/git/git-merge-forward.sh | 46 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 3 deletions(-) (limited to 'changes') diff --git a/changes/ticket31314 b/changes/ticket31314 index e1d9fb767b..2932231171 100644 --- a/changes/ticket31314 +++ b/changes/ticket31314 @@ -4,3 +4,6 @@ push test branches. Closes ticket 31314. - Add a -r argument to git-push-all.sh, so the script can push test branches to a personal remote. Closes ticket 31314. + - Add a -u argument to git-merge-forward.sh, so that the script can re-use + existing test branches after a merge failure and fix. + Closes ticket 31314. diff --git a/scripts/git/git-merge-forward.sh b/scripts/git/git-merge-forward.sh index 1f4ddb85e7..a7e797eaf0 100755 --- a/scripts/git/git-merge-forward.sh +++ b/scripts/git/git-merge-forward.sh @@ -109,7 +109,12 @@ DRY_RUN=0 # _029, _035, ... , _master, and merge forward. TEST_BRANCH_PREFIX= -while getopts "nt:" opt; do +# Controlled by the -u option. The use existing option checks for existing +# branches with the , and checks them out, rather than +# creating a new branch. +USE_EXISTING=0 + +while getopts "nt:u" opt; do case "$opt" in n) DRY_RUN=1 echo " *** DRY RUN MODE ***" @@ -117,6 +122,9 @@ while getopts "nt:" opt; do t) TEST_BRANCH_PREFIX="$OPTARG" echo " *** CREATING TEST BRANCHES: ${TEST_BRANCH_PREFIX}_nnn ***" ;; + u) USE_EXISTING=1 + echo " *** USE EXISTING TEST BRANCHES MODE ***" + ;; *) exit 1 ;; @@ -230,6 +238,32 @@ function new_branch fi } +# Switch to an existing branch, or checkout a new branch with the given +# branch name. +function switch_or_new_branch +{ + local cmd="git rev-parse --verify $1" + if [ $DRY_RUN -eq 0 ]; then + # Call switch_branch if there is a branch, or new_branch if there is not + msg=$( eval "$cmd" 2>&1 ) + RET=$? + if [ $RET -eq 0 ]; then + # Branch: (commit id) + switch_branch "$1" + elif [ $RET -eq 128 ]; then + # Not a branch: "fatal: Needed a single revision" + new_branch "$1" + else + # Unexpected return value + validate_ret $RET "$msg" + fi + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}, then depending on the result:" + switch_branch "$1" + new_branch "$1" + fi +} + # Pull the given branch name. function pull_branch { @@ -328,8 +362,14 @@ for ((i=0; i Date: Mon, 12 Aug 2019 11:10:12 +1000 Subject: scripts/git: Make the git push command and args configurable TOR_GIT_PUSH provides the git push command and default arguments. Also fix handling of git-push-all.sh script arguments and arguments that are passed through to $TOR_GIT_PUSH, using a "--" argument as a separator. Fix on 29879. --- changes/ticket31314 | 5 +++++ scripts/git/git-push-all.sh | 27 +++++++++++++++++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) (limited to 'changes') diff --git a/changes/ticket31314 b/changes/ticket31314 index 2932231171..8b5f5da8f9 100644 --- a/changes/ticket31314 +++ b/changes/ticket31314 @@ -7,3 +7,8 @@ - Add a -u argument to git-merge-forward.sh, so that the script can re-use existing test branches after a merge failure and fix. Closes ticket 31314. + - Add a TOR_GIT_PUSH env var, which sets the default git push command and + arguments for git-push-all.sh. Closes ticket 31314. + - Add a "--" command-line argument, to + separate git-push-all.sh script arguments from arguments that are passed + through to git push. Closes ticket 31314. diff --git a/scripts/git/git-push-all.sh b/scripts/git/git-push-all.sh index f3bbe8b778..2d6e77a8c1 100755 --- a/scripts/git/git-push-all.sh +++ b/scripts/git/git-push-all.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash -# Usage: git-push-all.sh -t -r +# Usage: git-push-all.sh -t -r +# -- # env vars: TOR_UPSTREAM_REMOTE_NAME=upstream TOR_PUSH_DELAY=0 # git-opts: --no-atomic --dry-run (any other git push option) # @@ -16,6 +17,8 @@ set -e # Don't change this configuration - set the env vars in your .profile # +# git push command and default arguments +GIT_PUSH=${TOR_GIT_PUSH:-"git push --atomic"} # The upstream remote which git.torproject.org/tor.git points to. # In test branch mode, override this setting with -r UPSTREAM_REMOTE=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"} @@ -46,11 +49,21 @@ while getopts ":r:t:" opt; do OPTIND=$[$OPTIND - 2] ;; *) - # Assume git push will handle the option + # Assume we're done with script arguments, + # and git push will handle the option + break ;; esac done +# getopts doesn't allow "-" as an option character, +# so we have to handle -- manually +if [ "$1" = "--" ]; then + shift +fi + +echo "Calling git push --atomic $@ " + if [ "$TEST_BRANCH_PREFIX" ]; then if [ "$UPSTREAM_REMOTE" = ${TOR_UPSTREAM_REMOTE_NAME:-"upstream"} ]; then echo "Pushing test branches ${TEST_BRANCH_PREFIX}_nnn to " \ @@ -108,9 +121,11 @@ if [ "$PUSH_DELAY" -le 0 ]; then # it is safe to use it unquoted. (This also applies to the other shellcheck # exceptions below.) # + # Push all the branches at the same time # shellcheck disable=SC2086 - git push --atomic "$@" "$UPSTREAM_REMOTE" $PUSH_BRANCHES + $GIT_PUSH "$@" "$UPSTREAM_REMOTE" $PUSH_BRANCHES else + # Push the branches in optimal CI order, with a delay between each push PUSH_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\n" | sort -V) MASTER_BRANCH=$(echo "$PUSH_BRANCHES" | tr " " "\n" | grep master) if [ -z "$TEST_BRANCH_PREFIX" ]; then @@ -127,15 +142,15 @@ else # No release branches RELEASE_BRANCHES= fi - git push "$@" "$UPSTREAM_REMOTE" "$MASTER_BRANCH" + $GIT_PUSH "$@" "$UPSTREAM_REMOTE" "$MASTER_BRANCH" sleep "$PUSH_DELAY" # shellcheck disable=SC2086 for b in $MAINT_BRANCHES; do - git push "$@" "$UPSTREAM_REMOTE" "$b" + $GIT_PUSH "$@" "$UPSTREAM_REMOTE" "$b" sleep "$PUSH_DELAY" done if [ "$RELEASE_BRANCHES" ]; then # shellcheck disable=SC2086 - git push --atomic "$@" "$UPSTREAM_REMOTE" $RELEASE_BRANCHES + $GIT_PUSH "$@" "$UPSTREAM_REMOTE" $RELEASE_BRANCHES fi fi -- cgit v1.2.3-54-g00ecf From b47b71ad2fc095b43437317011d127424188eb4f Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 12 Aug 2019 11:12:41 +1000 Subject: scripts/git: Let git-push-all.sh skip unchanged test branches Skip test branches that are the same as remote maint/release/master branches. Add a TOR_PUSH_SAME and -s argument to git-push-all.sh to change this default. Part of 31314. --- changes/ticket31314 | 4 +++ scripts/git/git-push-all.sh | 73 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 4 deletions(-) (limited to 'changes') diff --git a/changes/ticket31314 b/changes/ticket31314 index 8b5f5da8f9..7ce96e96cf 100644 --- a/changes/ticket31314 +++ b/changes/ticket31314 @@ -12,3 +12,7 @@ - Add a "--" command-line argument, to separate git-push-all.sh script arguments from arguments that are passed through to git push. Closes ticket 31314. + - Skip pushing test branches that are the same as a remote + maint/release/master branch in git-push-all.sh by default. Add a -s + argument, so git-push-all.sh can push all test branches. + Closes ticket 31314. diff --git a/scripts/git/git-push-all.sh b/scripts/git/git-push-all.sh index 2d6e77a8c1..8a8ef1f2db 100755 --- a/scripts/git/git-push-all.sh +++ b/scripts/git/git-push-all.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Usage: git-push-all.sh -t -r +# Usage: git-push-all.sh -t -r -s # -- # env vars: TOR_UPSTREAM_REMOTE_NAME=upstream TOR_PUSH_DELAY=0 # git-opts: --no-atomic --dry-run (any other git push option) @@ -20,10 +20,17 @@ set -e # git push command and default arguments GIT_PUSH=${TOR_GIT_PUSH:-"git push --atomic"} # The upstream remote which git.torproject.org/tor.git points to. -# In test branch mode, override this setting with -r -UPSTREAM_REMOTE=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"} +DEFAULT_UPSTREAM_REMOTE=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"} +# Push to a different upstream remote using -r +UPSTREAM_REMOTE=${DEFAULT_UPSTREAM_REMOTE} # Add a delay between pushes, so CI runs on the most important branches first PUSH_DELAY=${TOR_PUSH_DELAY:-0} +# Push (1) or skip (0) test branches that are the same as an upstream +# maint/master branch. Push if you are testing that the CI environment still +# works on old code, skip if you are testing new code in the branch. +# Default: skip unchanged branches. +# Inverted by the -s option. +PUSH_SAME=${TOR_PUSH_SAME:-0} ####################### # Argument processing # @@ -34,7 +41,7 @@ PUSH_DELAY=${TOR_PUSH_DELAY:-0} # _029, _035, ... , _master, and merge forward. TEST_BRANCH_PREFIX= -while getopts ":r:t:" opt; do +while getopts ":r:st:" opt; do case "$opt" in r) UPSTREAM_REMOTE="$OPTARG" echo " *** PUSHING TO REMOTE: ${UPSTREAM_REMOTE} ***" @@ -42,6 +49,15 @@ while getopts ":r:t:" opt; do shift OPTIND=$[$OPTIND - 2] ;; + s) PUSH_SAME=$[! "$PUSH_SAME" ] + if [ "$PUSH_SAME" -eq 0 ]; then + echo " *** SKIPPING UNCHANGED TEST BRANCHES ***" + else + echo " *** PUSHING UNCHANGED TEST BRANCHES ***" + fi + shift + OPTIND=$[$OPTIND - 1] + ;; t) TEST_BRANCH_PREFIX="$OPTARG" echo " *** PUSHING TEST BRANCHES: ${TEST_BRANCH_PREFIX}_nnn ***" shift @@ -73,6 +89,29 @@ if [ "$TEST_BRANCH_PREFIX" ]; then fi fi +################################ +# Git upstream remote branches # +################################ + +DEFAULT_UPSTREAM_BRANCHES= +if [ "$DEFAULT_UPSTREAM_REMOTE" != "$UPSTREAM_REMOTE" ]; then + DEFAULT_UPSTREAM_BRANCHES=`echo \ + ${DEFAULT_UPSTREAM_REMOTE}/master \ + ${DEFAULT_UPSTREAM_REMOTE}/{release,maint}-0.4.1 \ + ${DEFAULT_UPSTREAM_REMOTE}/{release,maint}-0.4.0 \ + ${DEFAULT_UPSTREAM_REMOTE}/{release,maint}-0.3.5 \ + ${DEFAULT_UPSTREAM_REMOTE}/{release,maint}-0.2.9 \ + ` +fi + +UPSTREAM_BRANCHES=`echo \ + ${UPSTREAM_REMOTE}/master \ + ${UPSTREAM_REMOTE}/{release,maint}-0.4.1 \ + ${UPSTREAM_REMOTE}/{release,maint}-0.4.0 \ + ${UPSTREAM_REMOTE}/{release,maint}-0.3.5 \ + ${UPSTREAM_REMOTE}/{release,maint}-0.2.9 \ + ` + ######################## # Git branches to push # ######################## @@ -115,6 +154,32 @@ fi # Entry point # ############### +# Skip the test branches that are the same as the upstream branches +if [ "$PUSH_SAME" -eq 0 -a "$TEST_BRANCH_PREFIX" ]; then + NEW_PUSH_BRANCHES= + for b in $PUSH_BRANCHES; do + PUSH_COMMIT=`git rev-parse $b` + SKIP_UPSTREAM= + for u in $DEFAULT_UPSTREAM_BRANCHES $UPSTREAM_BRANCHES; do + UPSTREAM_COMMIT=`git rev-parse "$u"` + if [ "$PUSH_COMMIT" = "$UPSTREAM_COMMIT" ]; then + SKIP_UPSTREAM="$u" + fi + done + if [ "$SKIP_UPSTREAM" ]; then + printf "Skipping unchanged: %s remote: %s\n" \ + "$b" "$SKIP_UPSTREAM" + else + if [ "$NEW_PUSH_BRANCHES" ]; then + NEW_PUSH_BRANCHES="${NEW_PUSH_BRANCHES} ${b}" + else + NEW_PUSH_BRANCHES="${b}" + fi + fi + done + PUSH_BRANCHES=${NEW_PUSH_BRANCHES} +fi + if [ "$PUSH_DELAY" -le 0 ]; then echo "Pushing $PUSH_BRANCHES" # We know that there are no spaces in any branch within $PUSH_BRANCHES, so -- cgit v1.2.3-54-g00ecf From 4256ee0d379daf35098c396757ce92b97b025c6e Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 29 Aug 2019 09:50:38 -0400 Subject: Stub out some more functions in dirvote/*.h, fix compilation. This fixes LTO compilation for Android and -O0 compilation in general, when --disable-module-dirauth is provided. Fixes bug 31552; bugfix on 0.4.1.1-alpha. --- changes/bug31552 | 5 +++++ src/feature/dirauth/process_descs.h | 26 +++++++++++++++++++++++--- src/feature/dirauth/reachability.h | 16 ++++++++++++++-- 3 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 changes/bug31552 (limited to 'changes') diff --git a/changes/bug31552 b/changes/bug31552 new file mode 100644 index 0000000000..fb33e14429 --- /dev/null +++ b/changes/bug31552 @@ -0,0 +1,5 @@ + o Minor bugfixes (compilation): + - Add more stub functions to fix compilation on Android with LTO, when + --disable-module-dirauth is used. Previously, these compilation + settings would make the compiler look for functions that didn't exist. + Fixes bug 31552; bugfix on 0.4.1.1-alpha. diff --git a/src/feature/dirauth/process_descs.h b/src/feature/dirauth/process_descs.h index 001c866eba..0da47c96c3 100644 --- a/src/feature/dirauth/process_descs.h +++ b/src/feature/dirauth/process_descs.h @@ -25,15 +25,35 @@ enum was_router_added_t dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source); -int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, - int complain, - int *valid_out); uint32_t dirserv_router_get_status(const routerinfo_t *router, const char **msg, int severity); void dirserv_set_node_flags_from_authoritative_status(node_t *node, uint32_t authstatus); +#ifdef HAVE_MODULE_DIRAUTH int dirserv_would_reject_router(const routerstatus_t *rs); +int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, + int complain, + int *valid_out); +#else +static inline int +dirserv_would_reject_router(const routerstatus_t *rs) +{ + (void)rs; + return 0; +} +static inline int +authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, + int complain, + int *valid_out) +{ + (void)ri; + (void)msg; + (void)complain; + (void)valid_out; + return 0; +} +#endif #endif /* !defined(TOR_RECV_UPLOADS_H) */ diff --git a/src/feature/dirauth/reachability.h b/src/feature/dirauth/reachability.h index 873a3f9a23..0018c7f638 100644 --- a/src/feature/dirauth/reachability.h +++ b/src/feature/dirauth/reachability.h @@ -28,9 +28,21 @@ void dirserv_orconn_tls_done(const tor_addr_t *addr, uint16_t or_port, const char *digest_rcvd, const struct ed25519_public_key_t *ed_id_rcvd); -int dirserv_should_launch_reachability_test(const routerinfo_t *ri, - const routerinfo_t *ri_old); void dirserv_single_reachability_test(time_t now, routerinfo_t *router); void dirserv_test_reachability(time_t now); +#ifdef HAVE_MODULE_DIRAUTH +int dirserv_should_launch_reachability_test(const routerinfo_t *ri, + const routerinfo_t *ri_old); +#else +static inline int +dirserv_should_launch_reachability_test(const routerinfo_t *ri, + const routerinfo_t *ri_old) +{ + (void)ri; + (void)ri_old; + return 0; +} +#endif + #endif /* !defined(TOR_REACHABILITY_H) */ -- cgit v1.2.3-54-g00ecf From 52342327c7e566a25bf69dc6df651de45959e6d6 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 2 Sep 2019 14:49:53 -0400 Subject: madvise: tolerate EINVAL and ENOSYS These errors can occur if we are built on a system with support for madvise(MADV_NOFORK) but then we are run on a system whose kernel does not support that flag. If the error is something that we don't tolerate at all, we now log it before crashing. Fixes bug 31570. I am calling this a bugfix on 0.4.1.1-alpha, where we actually started using the map_anon code. --- changes/bug31570 | 5 +++++ src/lib/malloc/map_anon.c | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 changes/bug31570 (limited to 'changes') diff --git a/changes/bug31570 b/changes/bug31570 new file mode 100644 index 0000000000..f70b577b4c --- /dev/null +++ b/changes/bug31570 @@ -0,0 +1,5 @@ + o Major bugfixes (crash, android): + - Tolerate systems (including some Android installations) where madvise + and MADV_DONTDUMP are available at build-time, but not at run time. + Previously, these systems would notice a failed syscall and abort. + Fixes bug 31570; bugfix on 0.4.1.1-alpha. diff --git a/src/lib/malloc/map_anon.c b/src/lib/malloc/map_anon.c index 0f6a4150c7..79bbb99f72 100644 --- a/src/lib/malloc/map_anon.c +++ b/src/lib/malloc/map_anon.c @@ -27,6 +27,9 @@ #include #endif +#include +#include + /** * Macro to get the high bytes of a size_t, if there are high bytes. * Windows needs this; other operating systems define a size_t that does @@ -108,7 +111,17 @@ static int nodump_mem(void *mem, size_t sz) { #if defined(MADV_DONTDUMP) - return madvise(mem, sz, MADV_DONTDUMP); + int rv = madvise(mem, sz, MADV_DONTDUMP); + if (rv == 0) { + return 0; + } else if (errno == ENOSYS || errno == EINVAL) { + return 0; // syscall not supported, or flag not supported. + } else { + tor_log_err_sigsafe("Unexpected error from madvise: ", + strerror(errno), + NULL); + return -1; + } #else (void) mem; (void) sz; -- cgit v1.2.3-54-g00ecf From 651bbe8a0d5fbff261a98314b56f57314ea394cd Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 2 Sep 2019 15:31:31 -0400 Subject: Practracker: only consider files under "src/" --- changes/ticket31578 | 6 ++++++ scripts/maint/practracker/practracker.py | 5 ++++- scripts/maint/practracker/test_practracker.sh | 1 + scripts/maint/practracker/util.py | 12 +++++++++--- 4 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 changes/ticket31578 (limited to 'changes') diff --git a/changes/ticket31578 b/changes/ticket31578 new file mode 100644 index 0000000000..220efffa63 --- /dev/null +++ b/changes/ticket31578 @@ -0,0 +1,6 @@ + o Minor bugfixes (practracker): + - When running check-best-practices, only consider files in the + src subdirectory. Previously we had recursively considered + all subdirectories, which made us get confused by the + temporary directories made by "make distcheck". Fixes bug + 31578; bugfix on 0.4.1.1-alpha. diff --git a/scripts/maint/practracker/practracker.py b/scripts/maint/practracker/practracker.py index 6483b88da1..537f755c8b 100755 --- a/scripts/maint/practracker/practracker.py +++ b/scripts/maint/practracker/practracker.py @@ -195,6 +195,9 @@ def main(argv): help="Maximum lines per function") parser.add_argument("--max-dependency-violations", default=MAX_DEP_VIOLATIONS, help="Maximum number of dependency violations to allow") + parser.add_argument("--include-dir", action="append", + default=["src"], + help="A directory (under topdir) to search for source") parser.add_argument("topdir", default=".", nargs="?", help="Top-level directory for the tor source") args = parser.parse_args(argv[1:]) @@ -216,7 +219,7 @@ def main(argv): filt.addThreshold(problem.DependencyViolationItem("*", int(args.max_dependency_violations))) # 1) Get all the .c files we care about - files_list = util.get_tor_c_files(TOR_TOPDIR) + files_list = util.get_tor_c_files(TOR_TOPDIR, args.include_dir) # 2) Initialize problem vault and load an optional exceptions file so that # we don't warn about the past diff --git a/scripts/maint/practracker/test_practracker.sh b/scripts/maint/practracker/test_practracker.sh index c878ca5580..78e96ba471 100755 --- a/scripts/maint/practracker/test_practracker.sh +++ b/scripts/maint/practracker/test_practracker.sh @@ -25,6 +25,7 @@ DATA="${PRACTRACKER_DIR}/testdata" run_practracker() { "${PYTHON:-python}" "${PRACTRACKER_DIR}/practracker.py" \ + --include-dir "" \ --max-include-count=0 --max-file-size=0 --max-function-size=0 --terse \ "${DATA}/" "$@"; } diff --git a/scripts/maint/practracker/util.py b/scripts/maint/practracker/util.py index 695668f561..854d369f74 100644 --- a/scripts/maint/practracker/util.py +++ b/scripts/maint/practracker/util.py @@ -3,22 +3,28 @@ import os # We don't want to run metrics for unittests, automatically-generated C files, # external libraries or git leftovers. EXCLUDE_SOURCE_DIRS = {"src/test/", "src/trunnel/", "src/rust/", - "src/ext/", ".git/"} + "src/ext/" } EXCLUDE_FILES = {"orconfig.h"} def _norm(p): return os.path.normcase(os.path.normpath(p)) -def get_tor_c_files(tor_topdir): +def get_tor_c_files(tor_topdir, include_dirs=None): """ Return a list with the .c and .h filenames we want to get metrics of. """ files_list = [] exclude_dirs = { _norm(os.path.join(tor_topdir, p)) for p in EXCLUDE_SOURCE_DIRS } + if include_dirs is None: + topdirs = [ tor_topdir ] + else: + topdirs = [ os.path.join(tor_topdir, inc) for inc in include_dirs ] - for root, directories, filenames in os.walk(tor_topdir): + # TO THE REVIEWER: I will fix this indentation shortly. -nm + for topdir in topdirs: + for root, directories, filenames in os.walk(topdir): # Remove all the directories that are excluded. directories[:] = [ d for d in directories if _norm(os.path.join(root,d)) not in exclude_dirs ] -- cgit v1.2.3-54-g00ecf From 4bcfa286f6b37a98c510459f9cd1ea78f957ea9f Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 4 Sep 2019 10:31:45 -0400 Subject: changes file for 31240 --- changes/ticket31240 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/ticket31240 (limited to 'changes') diff --git a/changes/ticket31240 b/changes/ticket31240 new file mode 100644 index 0000000000..0fe37ff44b --- /dev/null +++ b/changes/ticket31240 @@ -0,0 +1,5 @@ + o Minor features (configuration): + - The configuration code has been extended to allow splitting + configuration data across multiple objects. Previously, all + configuration data needed to be kept in a single object, which + tended to become bloated. Closes ticket 31240. -- cgit v1.2.3-54-g00ecf From 870874fec8cadf3a3e91f63cd7f25757b1ec8b8a Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 4 Sep 2019 11:28:21 -0400 Subject: config: Make CLEAR with a nonempty value into a nonfatal assertion. When we parse a CLEAR line (e.g., "/OrPort" or /OrPort blah blah"), we always suppress the value, even if one exists. That means that the block of code was meant to handle CLEAR lines didn't actually do anything, since we previously handled them the same way as with other empty values. Closes ticket 31529. --- changes/ticket31529 | 5 +++++ src/app/config/confparse.c | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 changes/ticket31529 (limited to 'changes') diff --git a/changes/ticket31529 b/changes/ticket31529 new file mode 100644 index 0000000000..84f982214c --- /dev/null +++ b/changes/ticket31529 @@ -0,0 +1,5 @@ + o Minor features (debugging): + - Log a nonfatal assertion failure if we encounter a configuration + line whose command is "CLEAR" but which has a nonempty value. + This should be impossible, according to the rules of our + configuration line parsing. Closes ticket 31529. diff --git a/src/app/config/confparse.c b/src/app/config/confparse.c index f20a361ba3..ecc4e86560 100644 --- a/src/app/config/confparse.c +++ b/src/app/config/confparse.c @@ -652,9 +652,14 @@ config_assign_line(const config_mgr_t *mgr, void *options, } return 0; } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) { - // XXXX This is unreachable, since a CLEAR line always has an - // XXXX empty value. - config_reset(mgr, options, mvar, use_defaults); // LCOV_EXCL_LINE + // This block is unreachable, since a CLEAR line always has an + // empty value, and so will trigger be handled by the previous + // "if (!strlen(c->value))" block. + + // LCOV_EXCL_START + tor_assert_nonfatal_unreached(); + config_reset(mgr, options, mvar, use_defaults); + // LCOV_EXCL_STOP } if (options_seen && ! config_var_is_cumulative(cvar)) { -- cgit v1.2.3-54-g00ecf From 106b75aa5398f7a260a4d0f3093c244376258242 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 4 Sep 2019 11:09:01 -0400 Subject: changes file for 31532 --- changes/ticket31532 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket31532 (limited to 'changes') diff --git a/changes/ticket31532 b/changes/ticket31532 new file mode 100644 index 0000000000..95bcbc517c --- /dev/null +++ b/changes/ticket31532 @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Use the ptrdiff_t type consistently for expressing variable offsets and + pointer differences. Previously we incorrectly (but harmlessly) used + int and sometimes off_t for these cases. Closes ticket 31532. -- cgit v1.2.3-54-g00ecf From 4b1d2ba9798b0255d9566a642dffd09467e321df Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 30 Aug 2019 23:03:50 +1000 Subject: changes: file for 30967 --- changes/ticket30967 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/ticket30967 (limited to 'changes') diff --git a/changes/ticket30967 b/changes/ticket30967 new file mode 100644 index 0000000000..5fe9c980b6 --- /dev/null +++ b/changes/ticket30967 @@ -0,0 +1,6 @@ + o Testing: + - When checking shell scripts, ignore any user-created directories. + Closes ticket 30967. + o Minor features (git scripts): + - Call the shellcheck script from the pre-commit hook. + Closes ticket 30967. -- cgit v1.2.3-54-g00ecf From 763fd0ad668cb03c11d9e3e932111152eea22630 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 2 Sep 2019 11:38:05 +0300 Subject: Fix bugfix version in Bug 30649: Changes file. --- changes/bug30649 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'changes') diff --git a/changes/bug30649 b/changes/bug30649 index 3f5768bcb4..4b2c603171 100644 --- a/changes/bug30649 +++ b/changes/bug30649 @@ -1,4 +1,4 @@ o Minor bugfixes (circuit padding): - On relays, properly check that a padding machine is absent before logging a warn about it being absent. Fixes bug 30649; - bugfix on 0.4.1.1-alpha. + bugfix on 0.4.0.1-alpha. -- cgit v1.2.3-54-g00ecf From 61082c059c83ef889eec00e8cddeda9a6367bee9 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 2 Sep 2019 11:38:05 +0300 Subject: Fix bugfix version in Bug 30649: Changes file. --- changes/bug30649 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'changes') diff --git a/changes/bug30649 b/changes/bug30649 index 3f5768bcb4..4b2c603171 100644 --- a/changes/bug30649 +++ b/changes/bug30649 @@ -1,4 +1,4 @@ o Minor bugfixes (circuit padding): - On relays, properly check that a padding machine is absent before logging a warn about it being absent. Fixes bug 30649; - bugfix on 0.4.1.1-alpha. + bugfix on 0.4.0.1-alpha. -- cgit v1.2.3-54-g00ecf From 73890a86ef4b5dc962d647495e7e8c80ca098975 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 2 Sep 2019 11:58:01 +0300 Subject: Merge branch 'bug30649_040' into bug30649_maint_041 --- .gitignore | 4 + .travis.yml | 36 +- ChangeLog | 1083 +++ Makefile.am | 50 +- ReleaseNotes | 785 ++ autogen.sh | 5 +- changes/29241_diagnostic | 4 - changes/bug13221 | 5 - changes/bug22619 | 3 + changes/bug23507 | 5 + changes/bug23818_v2 | 6 + changes/bug23818_v3 | 6 + changes/bug27199 | 3 - changes/bug28525 | 7 - changes/bug28614_better_logging | 6 - changes/bug28656 | 3 - changes/bug28698 | 3 - changes/bug28925 | 4 - changes/bug28979 | 4 - changes/bug28981 | 5 - changes/bug29017 | 4 - changes/bug29029 | 5 - changes/bug29034 | 5 + changes/bug29036 | 5 - changes/bug29040 | 4 - changes/bug29042 | 5 - changes/bug29122 | 3 - changes/bug29135 | 5 - changes/bug29144 | 5 - changes/bug29145 | 3 - changes/bug29150 | 3 - changes/bug29161 | 3 - changes/bug29169 | 3 - changes/bug29175_035 | 4 - changes/bug29204 | 4 - changes/bug29241 | 6 - changes/bug29244 | 4 - changes/bug29298 | 5 - changes/bug29500 | 3 - changes/bug29508 | 3 - changes/bug29527 | 5 - changes/bug29530_035 | 5 - changes/bug29562 | 4 - changes/bug29599 | 3 - changes/bug29601 | 6 - changes/bug29665 | 7 - changes/bug29693 | 3 - changes/bug29703 | 4 - changes/bug29706_minimal | 4 - changes/bug29706_refactor | 4 - changes/bug29874 | 4 - changes/bug29922 | 4 - changes/bug29930 | 4 - changes/bug29959-040 | 3 - changes/bug30001 | 7 - changes/bug30011 | 4 - changes/bug30021 | 8 - changes/bug30040 | 9 - changes/bug30041 | 5 - changes/bug30189 | 4 - changes/bug30263 | 3 - changes/bug30316 | 4 - changes/bug30452 | 3 - changes/bug30475 | 4 - changes/bug30781 | 4 + changes/bug30894 | 4 + changes/bug30942 | 4 + changes/bug30956 | 4 + changes/bug31003 | 4 + changes/bug31024 | 4 + changes/bug31027 | 3 + changes/bug31080_041 | 4 + changes/bug31343 | 9 + changes/bug31356_and_logs | 11 + changes/bug31463 | 3 + changes/chutney_ci | 3 + changes/cid1444119 | 3 - changes/diagnostic_28223_redux | 4 - changes/doc28623 | 3 - changes/doc29121 | 3 - changes/doc30630 | 3 + changes/feature28976 | 4 - changes/geoip-2019-02-05 | 4 - changes/geoip-2019-03-04 | 4 - changes/geoip-2019-04-02 | 4 - changes/geoip-2019-05-13 | 4 - changes/ticket21377 | 4 - changes/ticket26698 | 4 - changes/ticket27761 | 4 - changes/ticket28614 | 8 - changes/ticket28668 | 3 - changes/ticket28816 | 4 - changes/ticket29026 | 4 - changes/ticket29072 | 2 - changes/ticket29160 | 4 - changes/ticket29168 | 5 - changes/ticket29357 | 7 - changes/ticket29435 | 3 - changes/ticket29631 | 4 - changes/ticket29702 | 4 - changes/ticket29806 | 7 - changes/ticket29897 | 3 - changes/ticket29962 | 3 - changes/ticket30117 | 4 - changes/ticket30213 | 3 - changes/ticket30234 | 2 - changes/ticket30454 | 10 - changes/ticket30591 | 3 + changes/ticket30686 | 5 + changes/ticket30694 | 3 + changes/ticket30871 | 6 + changes/ticket31001 | 6 + changes/ticket31311 | 3 + changes/ticket31374 | 4 + changes/ticket31406 | 3 + configure.ac | 37 +- contrib/README | 2 - contrib/client-tools/torify | 2 +- .../dirauth-tools/nagios-check-tor-authority-cert | 10 +- contrib/dist/suse/tor.sh.in | 118 - contrib/dist/tor.sh.in | 123 - contrib/include.am | 3 - contrib/operator-tools/linux-tor-prio.sh | 192 - contrib/win32build/tor-mingw.nsi.in | 2 +- doc/HACKING/CodingStandards.md | 41 +- doc/HACKING/CodingStandardsRust.md | 6 +- doc/HACKING/HelpfulTools.md | 15 + doc/HACKING/ReleasingTor.md | 18 +- doc/asciidoc-helper.sh | 6 +- doc/tor.1.txt | 62 +- scripts/coccinelle/ctrl-reply-cleanup.cocci | 43 + scripts/coccinelle/ctrl-reply.cocci | 87 + scripts/coccinelle/tor-coccinelle.h | 3 + scripts/git/git-merge-forward.sh | 236 + scripts/git/git-pull-all.sh | 224 + scripts/git/git-push-all.sh | 11 + scripts/git/post-merge.git-hook | 45 + scripts/git/pre-commit.git-hook | 45 + scripts/git/pre-push.git-hook | 108 + scripts/maint/add_c_file.py | 251 + scripts/maint/checkIncludes.py | 2 +- scripts/maint/checkSpace.pl | 32 + scripts/maint/practracker/exceptions.txt | 289 + scripts/maint/practracker/metrics.py | 50 + scripts/maint/practracker/practracker.py | 216 + scripts/maint/practracker/practracker_tests.py | 50 + scripts/maint/practracker/problem.py | 158 + scripts/maint/practracker/util.py | 28 + scripts/maint/pre-commit.git-hook | 26 - scripts/maint/pre-push.git-hook | 61 - scripts/maint/rectify_include_paths.py | 15 +- scripts/maint/updateCopyright.pl | 6 +- scripts/test/cov-diff | 3 +- scripts/test/cov-test-determinism.sh | 51 + src/app/config/auth_dirs.inc | 2 +- src/app/config/config.c | 30 +- src/app/config/confparse.c | 1 + src/app/config/or_options_st.h | 13 +- src/app/config/or_state_st.h | 2 +- src/app/config/statefile.c | 2 +- src/app/config/statefile.h | 2 +- src/app/main/main.c | 183 +- src/app/main/main.h | 3 - src/app/main/ntmain.c | 1 + src/app/main/shutdown.c | 169 + src/app/main/shutdown.h | 18 + src/app/main/subsysmgr.c | 52 +- src/app/main/subsysmgr.h | 7 +- src/app/main/subsystem_list.c | 16 +- src/config/mmdb-convert.py | 2 +- src/config/torrc.sample.in | 6 +- src/core/crypto/hs_ntor.c | 14 +- src/core/crypto/onion_crypto.h | 2 +- src/core/crypto/relay_crypto.c | 48 +- src/core/crypto/relay_crypto.h | 11 + src/core/include.am | 70 +- src/core/mainloop/connection.c | 50 +- src/core/mainloop/cpuworker.c | 7 +- src/core/mainloop/mainloop.c | 562 +- src/core/mainloop/mainloop.h | 12 +- src/core/mainloop/mainloop_pubsub.c | 170 + src/core/mainloop/mainloop_pubsub.h | 24 + src/core/mainloop/mainloop_sys.c | 32 + src/core/mainloop/mainloop_sys.h | 12 + src/core/mainloop/netstatus.h | 2 +- src/core/mainloop/periodic.c | 198 +- src/core/mainloop/periodic.h | 13 +- src/core/or/addr_policy_st.h | 2 +- src/core/or/address_set.h | 2 +- src/core/or/cell_queue_st.h | 2 +- src/core/or/cell_st.h | 2 +- src/core/or/channel.c | 11 + src/core/or/channeltls.c | 26 +- src/core/or/circuit_st.h | 46 +- src/core/or/circuitbuild.c | 131 +- src/core/or/circuitbuild.h | 13 +- src/core/or/circuitlist.c | 105 +- src/core/or/circuitlist.h | 31 +- src/core/or/circuitmux.c | 29 +- src/core/or/circuitpadding.c | 1036 ++- src/core/or/circuitpadding.h | 224 +- src/core/or/circuitpadding_machines.c | 458 ++ src/core/or/circuitpadding_machines.h | 35 + src/core/or/circuitstats.c | 4 +- src/core/or/circuituse.c | 34 +- src/core/or/command.c | 2 +- src/core/or/connection_edge.c | 53 +- src/core/or/connection_edge.h | 1 + src/core/or/connection_or.c | 7 +- src/core/or/connection_st.h | 2 +- src/core/or/cpath_build_state_st.h | 2 +- src/core/or/crypt_path.c | 262 + src/core/or/crypt_path.h | 46 + src/core/or/crypt_path_reference_st.h | 2 +- src/core/or/crypt_path_st.h | 25 +- src/core/or/destroy_cell_queue_st.h | 2 +- src/core/or/dos.h | 4 +- src/core/or/edge_connection_st.h | 2 +- src/core/or/entry_connection_st.h | 2 +- src/core/or/entry_port_cfg_st.h | 2 +- src/core/or/extend_info_st.h | 2 +- src/core/or/half_edge_st.h | 2 +- src/core/or/listener_connection_st.h | 2 +- src/core/or/ocirc_event.h | 2 +- src/core/or/ocirc_event_sys.h | 2 +- src/core/or/or.h | 4 +- src/core/or/or_circuit_st.h | 7 +- src/core/or/or_connection_st.h | 2 +- src/core/or/or_handshake_certs_st.h | 2 +- src/core/or/or_handshake_state_st.h | 2 +- src/core/or/or_periodic.c | 65 + src/core/or/or_periodic.h | 17 + src/core/or/or_sys.c | 43 + src/core/or/or_sys.h | 17 + src/core/or/orconn_event.h | 2 +- src/core/or/orconn_event_sys.h | 2 +- src/core/or/origin_circuit_st.h | 2 +- src/core/or/policies.c | 98 +- src/core/or/policies.h | 2 + src/core/or/port_cfg_st.h | 2 +- src/core/or/protover.c | 9 +- src/core/or/protover.h | 3 + src/core/or/relay.c | 474 +- src/core/or/relay.h | 9 +- src/core/or/relay_crypto_st.h | 4 +- src/core/or/sendme.c | 710 ++ src/core/or/sendme.h | 80 + src/core/or/server_port_cfg_st.h | 2 +- src/core/or/socks_request_st.h | 2 +- src/core/or/tor_version_st.h | 2 +- src/core/or/var_cell_st.h | 2 +- src/core/or/versions.c | 5 +- src/core/proto/proto_socks.c | 2 +- src/ext/include.am | 2 + src/ext/timeouts/.may_include | 5 +- src/ext/timeouts/test-timeout.c | 2 +- src/ext/timeouts/timeout.c | 6 +- src/ext/tinytest.c | 6 + src/ext/tinytest.h | 3 + src/feature/api/tor_api.c | 4 +- src/feature/api/tor_api.h | 2 +- src/feature/client/addressmap.c | 2 +- src/feature/client/bridges.c | 2 +- src/feature/client/circpathbias.c | 35 +- src/feature/client/dnsserv.c | 2 +- src/feature/client/entrynodes.c | 9 +- src/feature/client/transports.c | 12 +- src/feature/control/btrack_circuit.h | 2 +- src/feature/control/btrack_orconn.h | 4 +- src/feature/control/btrack_orconn_cevent.c | 2 +- src/feature/control/btrack_orconn_cevent.h | 3 +- src/feature/control/btrack_orconn_maps.h | 3 +- src/feature/control/btrack_sys.h | 2 +- src/feature/control/control.c | 7566 +------------------- src/feature/control/control.h | 388 +- src/feature/control/control_auth.c | 445 ++ src/feature/control/control_auth.h | 32 + src/feature/control/control_bootstrap.c | 2 +- src/feature/control/control_cmd.c | 2408 +++++++ src/feature/control/control_cmd.h | 112 + src/feature/control/control_cmd_args_st.h | 52 + src/feature/control/control_connection_st.h | 5 +- src/feature/control/control_events.c | 2318 ++++++ src/feature/control/control_events.h | 352 + src/feature/control/control_fmt.c | 181 + src/feature/control/control_fmt.h | 23 + src/feature/control/control_getinfo.c | 1654 +++++ src/feature/control/control_getinfo.h | 61 + src/feature/control/control_proto.c | 276 + src/feature/control/control_proto.h | 48 + src/feature/control/fmt_serverstatus.c | 6 - src/feature/control/fmt_serverstatus.h | 2 +- src/feature/control/getinfo_geoip.h | 2 +- src/feature/dirauth/authmode.h | 6 +- src/feature/dirauth/bridgeauth.c | 55 + src/feature/dirauth/bridgeauth.h | 12 + src/feature/dirauth/bwauth.c | 33 +- src/feature/dirauth/bwauth.h | 2 +- src/feature/dirauth/dirauth_periodic.c | 161 + src/feature/dirauth/dirauth_periodic.h | 25 + src/feature/dirauth/dirauth_sys.c | 40 + src/feature/dirauth/dirauth_sys.h | 12 + src/feature/dirauth/dirvote.c | 11 +- src/feature/dirauth/dirvote.h | 4 +- src/feature/dirauth/dsigs_parse.c | 2 +- src/feature/dirauth/dsigs_parse.h | 2 +- src/feature/dirauth/guardfraction.h | 2 +- src/feature/dirauth/ns_detached_signatures_st.h | 2 +- src/feature/dirauth/process_descs.h | 2 +- src/feature/dirauth/reachability.h | 2 +- src/feature/dirauth/recommend_pkg.h | 14 +- src/feature/dirauth/shared_random.c | 4 +- src/feature/dirauth/shared_random.h | 4 +- src/feature/dirauth/shared_random_state.c | 4 +- src/feature/dirauth/vote_microdesc_hash_st.h | 2 +- src/feature/dirauth/voteflags.c | 102 +- src/feature/dirauth/voteflags.h | 18 +- src/feature/dircache/cached_dir_st.h | 2 +- src/feature/dircache/consdiffmgr.c | 2 +- src/feature/dircache/dircache.c | 28 +- src/feature/dircache/dircache.h | 2 +- src/feature/dircache/dirserv.c | 20 +- src/feature/dirclient/dir_server_st.h | 2 +- src/feature/dirclient/dirclient.c | 4 +- src/feature/dirclient/dirclient.h | 2 +- src/feature/dirclient/dlstatus.h | 2 +- src/feature/dirclient/download_status_st.h | 2 +- src/feature/dircommon/dir_connection_st.h | 2 +- src/feature/dircommon/vote_timing_st.h | 2 +- src/feature/dircommon/voting_schedule.c | 2 +- src/feature/dircommon/voting_schedule.h | 2 +- src/feature/dirparse/microdesc_parse.h | 2 +- src/feature/dirparse/ns_parse.c | 2 +- src/feature/dirparse/ns_parse.h | 4 +- src/feature/dirparse/routerparse.c | 3 + src/feature/dirparse/sigcommon.h | 2 +- src/feature/dirparse/signing.h | 2 +- src/feature/dirparse/unparseable.h | 2 +- src/feature/hibernate/hibernate.c | 6 +- src/feature/hibernate/hibernate.h | 1 + src/feature/hs/hs_cell.c | 9 +- src/feature/hs/hs_circuit.c | 121 +- src/feature/hs/hs_circuit.h | 3 +- src/feature/hs/hs_client.c | 64 +- src/feature/hs/hs_client.h | 4 + src/feature/hs/hs_common.c | 189 +- src/feature/hs/hs_common.h | 7 +- src/feature/hs/hs_config.c | 9 - src/feature/hs/hs_control.c | 39 +- src/feature/hs/hs_control.h | 4 + src/feature/hs/hs_descriptor.c | 226 +- src/feature/hs/hs_descriptor.h | 29 +- src/feature/hs/hs_intropoint.c | 8 +- src/feature/hs/hs_service.c | 189 +- src/feature/hs/hs_service.h | 7 +- src/feature/hs/hs_stats.h | 4 + src/feature/hs/hsdir_index_st.h | 2 +- src/feature/hs_common/shared_random_client.h | 2 +- src/feature/keymgt/loadkey.h | 2 +- src/feature/nodelist/authcert.h | 2 +- src/feature/nodelist/authority_cert_st.h | 2 +- src/feature/nodelist/desc_store_st.h | 2 +- src/feature/nodelist/describe.h | 2 +- src/feature/nodelist/dirlist.c | 2 +- src/feature/nodelist/dirlist.h | 2 +- src/feature/nodelist/document_signature_st.h | 2 +- src/feature/nodelist/extrainfo_st.h | 2 +- src/feature/nodelist/fmt_routerstatus.c | 43 +- src/feature/nodelist/microdesc.c | 6 +- src/feature/nodelist/microdesc_st.h | 2 +- src/feature/nodelist/networkstatus.c | 92 +- src/feature/nodelist/networkstatus.h | 5 +- src/feature/nodelist/networkstatus_sr_info_st.h | 2 +- src/feature/nodelist/networkstatus_st.h | 2 +- src/feature/nodelist/networkstatus_voter_info_st.h | 2 +- src/feature/nodelist/nickname.h | 2 +- src/feature/nodelist/node_select.c | 75 +- src/feature/nodelist/node_select.h | 4 +- src/feature/nodelist/node_st.h | 2 +- src/feature/nodelist/nodefamily.h | 2 +- src/feature/nodelist/nodefamily_st.h | 2 +- src/feature/nodelist/nodelist.c | 104 +- src/feature/nodelist/nodelist.h | 7 +- src/feature/nodelist/routerinfo.h | 2 +- src/feature/nodelist/routerinfo_st.h | 2 +- src/feature/nodelist/routerlist.c | 28 +- src/feature/nodelist/routerlist_st.h | 2 +- src/feature/nodelist/routerset.c | 2 +- src/feature/nodelist/routerstatus_st.h | 2 +- src/feature/nodelist/signed_descriptor_st.h | 2 +- src/feature/nodelist/torcert.c | 6 +- src/feature/nodelist/torcert.h | 2 +- src/feature/nodelist/vote_routerstatus_st.h | 2 +- src/feature/relay/dns.c | 7 +- src/feature/relay/ext_orport.c | 3 +- src/feature/relay/onion_queue.c | 10 +- src/feature/relay/onion_queue.h | 2 +- src/feature/relay/relay_periodic.c | 308 + src/feature/relay/relay_periodic.h | 18 + src/feature/relay/relay_sys.c | 48 + src/feature/relay/relay_sys.h | 17 + src/feature/relay/router.c | 403 +- src/feature/relay/router.h | 23 +- src/feature/relay/routerkeys.c | 20 +- src/feature/relay/routerkeys.h | 4 +- src/feature/relay/selftest.c | 3 +- src/feature/relay/selftest.h | 2 +- src/feature/rend/rend_authorized_client_st.h | 2 +- .../rend/rend_encoded_v2_service_descriptor_st.h | 2 +- src/feature/rend/rend_intro_point_st.h | 2 +- src/feature/rend/rend_service_descriptor_st.h | 2 +- src/feature/rend/rendcache.c | 14 +- src/feature/rend/rendclient.c | 24 +- src/feature/rend/rendcommon.c | 7 +- src/feature/rend/rendparse.c | 17 +- src/feature/rend/rendparse.h | 2 +- src/feature/rend/rendservice.c | 53 +- src/feature/stats/geoip_stats.c | 2 +- src/feature/stats/predict_ports.h | 2 +- src/feature/stats/rephist.h | 2 +- src/include.am | 2 + src/lib/arch/bytes.h | 6 +- src/lib/arch/include.am | 1 + src/lib/buf/include.am | 2 + src/lib/cc/compat_compiler.h | 14 +- src/lib/cc/ctassert.h | 6 +- src/lib/cc/include.am | 1 + src/lib/cc/torint.h | 17 +- src/lib/compress/compress_zstd.c | 16 +- src/lib/compress/include.am | 2 + src/lib/container/bitarray.h | 2 +- src/lib/container/include.am | 5 + src/lib/container/map.h | 2 +- src/lib/container/namemap.c | 184 + src/lib/container/namemap.h | 35 + src/lib/container/namemap_st.h | 34 + src/lib/container/order.h | 2 +- src/lib/container/smartlist.h | 2 +- src/lib/crypt_ops/crypto_cipher.h | 2 +- src/lib/crypt_ops/crypto_curve25519.h | 4 +- src/lib/crypt_ops/crypto_dh_openssl.c | 8 +- src/lib/crypt_ops/crypto_digest.c | 705 +- src/lib/crypt_ops/crypto_digest.h | 2 + src/lib/crypt_ops/crypto_digest_nss.c | 560 ++ src/lib/crypt_ops/crypto_digest_openssl.c | 522 ++ src/lib/crypt_ops/crypto_ed25519.c | 2 +- src/lib/crypt_ops/crypto_format.c | 90 +- src/lib/crypt_ops/crypto_format.h | 12 +- src/lib/crypt_ops/crypto_hkdf.c | 10 +- src/lib/crypt_ops/crypto_init.c | 15 +- src/lib/crypt_ops/crypto_init.h | 2 +- src/lib/crypt_ops/crypto_nss_mgt.h | 4 +- src/lib/crypt_ops/crypto_ope.c | 4 +- src/lib/crypt_ops/crypto_ope.h | 4 +- src/lib/crypt_ops/crypto_openssl_mgt.c | 12 +- src/lib/crypt_ops/crypto_openssl_mgt.h | 2 +- src/lib/crypt_ops/crypto_rand.c | 15 +- src/lib/crypt_ops/crypto_rand.h | 27 +- src/lib/crypt_ops/crypto_rand_fast.c | 220 +- src/lib/crypt_ops/crypto_rand_numeric.c | 30 +- src/lib/crypt_ops/crypto_rsa.c | 2 +- src/lib/crypt_ops/crypto_rsa.h | 8 +- src/lib/crypt_ops/crypto_rsa_nss.c | 2 +- src/lib/crypt_ops/crypto_s2k.c | 4 +- src/lib/crypt_ops/crypto_util.c | 2 +- src/lib/crypt_ops/digestset.h | 2 +- src/lib/crypt_ops/include.am | 4 + src/lib/ctime/include.am | 2 + src/lib/defs/dh_sizes.h | 2 +- src/lib/defs/digest_sizes.h | 2 +- src/lib/defs/include.am | 2 + src/lib/defs/logging_types.h | 23 + src/lib/defs/time.h | 2 +- src/lib/defs/x25519_sizes.h | 2 +- src/lib/dispatch/.may_include | 10 + src/lib/dispatch/dispatch.h | 114 + src/lib/dispatch/dispatch_cfg.c | 141 + src/lib/dispatch/dispatch_cfg.h | 39 + src/lib/dispatch/dispatch_cfg_st.h | 25 + src/lib/dispatch/dispatch_core.c | 260 + src/lib/dispatch/dispatch_naming.c | 63 + src/lib/dispatch/dispatch_naming.h | 46 + src/lib/dispatch/dispatch_new.c | 174 + src/lib/dispatch/dispatch_st.h | 108 + src/lib/dispatch/include.am | 27 + src/lib/dispatch/msgtypes.h | 80 + src/lib/encoding/binascii.c | 10 +- src/lib/encoding/binascii.h | 2 +- src/lib/encoding/confline.c | 13 + src/lib/encoding/confline.h | 2 + src/lib/encoding/include.am | 4 + src/lib/encoding/keyval.h | 2 +- src/lib/encoding/kvline.c | 72 +- src/lib/encoding/kvline.h | 2 + src/lib/encoding/pem.h | 2 +- src/lib/encoding/qstring.c | 90 + src/lib/encoding/qstring.h | 18 + src/lib/encoding/time_fmt.h | 2 +- src/lib/err/.may_include | 3 +- src/lib/err/backtrace.c | 4 +- src/lib/err/backtrace.h | 7 +- src/lib/err/include.am | 2 + src/lib/err/torerr.h | 2 +- src/lib/evloop/include.am | 3 +- src/lib/evloop/token_bucket.h | 4 +- src/lib/evloop/workqueue.c | 10 +- src/lib/fdio/include.am | 2 + src/lib/fs/conffile.h | 2 +- src/lib/fs/dir.h | 2 +- src/lib/fs/files.h | 14 +- src/lib/fs/include.am | 2 + src/lib/fs/lockfile.h | 2 +- src/lib/fs/mmap.c | 2 +- src/lib/fs/mmap.h | 2 +- src/lib/fs/path.h | 2 +- src/lib/fs/userdb.h | 4 +- src/lib/fs/winlib.h | 4 +- src/lib/geoip/country.h | 2 +- src/lib/geoip/include.am | 2 + src/lib/intmath/addsub.h | 2 +- src/lib/intmath/include.am | 2 + src/lib/intmath/logic.h | 2 +- src/lib/intmath/weakrng.h | 2 +- src/lib/lock/compat_mutex.h | 2 +- src/lib/lock/include.am | 2 + src/lib/log/.may_include | 1 + src/lib/log/escape.h | 2 +- src/lib/log/include.am | 2 + src/lib/log/log.c | 16 +- src/lib/log/log.h | 111 +- src/lib/log/ratelim.h | 2 +- src/lib/log/util_bug.c | 61 +- src/lib/log/util_bug.h | 55 +- src/lib/log/win32err.h | 2 +- src/lib/malloc/include.am | 2 + src/lib/malloc/malloc.h | 4 +- src/lib/malloc/map_anon.c | 56 +- src/lib/malloc/map_anon.h | 36 +- src/lib/math/fp.h | 2 +- src/lib/math/include.am | 3 +- src/lib/math/laplace.h | 2 +- src/lib/math/prob_distr.c | 165 +- src/lib/math/prob_distr.h | 101 +- src/lib/memarea/include.am | 2 + src/lib/meminfo/include.am | 2 + src/lib/meminfo/meminfo.h | 2 +- src/lib/net/address.c | 10 +- src/lib/net/alertsock.h | 2 +- src/lib/net/buffers_net.h | 2 +- src/lib/net/gethostname.h | 2 +- src/lib/net/inaddr.h | 2 +- src/lib/net/inaddr_st.h | 2 +- src/lib/net/include.am | 2 + src/lib/net/nettypes.h | 2 +- src/lib/net/resolve.c | 4 +- src/lib/net/resolve.h | 2 +- src/lib/net/socket.c | 8 +- src/lib/net/socket.h | 2 +- src/lib/net/socketpair.c | 4 +- src/lib/net/socketpair.h | 2 +- src/lib/net/socks5_status.h | 2 +- src/lib/osinfo/include.am | 2 + src/lib/osinfo/uname.h | 2 +- src/lib/process/daemon.h | 2 +- src/lib/process/env.h | 2 +- src/lib/process/include.am | 2 + src/lib/process/pidfile.h | 2 +- src/lib/process/process.c | 10 +- src/lib/process/process.h | 6 +- src/lib/process/process_unix.c | 2 +- src/lib/process/process_unix.h | 6 +- src/lib/process/process_win32.c | 4 +- src/lib/process/process_win32.h | 6 +- src/lib/process/setuid.h | 2 +- src/lib/process/winprocess_sys.c | 2 +- src/lib/pubsub/.may_include | 10 + src/lib/pubsub/include.am | 28 + src/lib/pubsub/pub_binding_st.h | 38 + src/lib/pubsub/pubsub.h | 89 + src/lib/pubsub/pubsub_build.c | 307 + src/lib/pubsub/pubsub_build.h | 92 + src/lib/pubsub/pubsub_builder_st.h | 161 + src/lib/pubsub/pubsub_check.c | 428 ++ src/lib/pubsub/pubsub_connect.h | 54 + src/lib/pubsub/pubsub_flags.h | 32 + src/lib/pubsub/pubsub_macros.h | 373 + src/lib/pubsub/pubsub_publish.c | 72 + src/lib/pubsub/pubsub_publish.h | 15 + src/lib/sandbox/include.am | 2 + src/lib/smartlist_core/include.am | 2 + src/lib/smartlist_core/smartlist_core.c | 26 + src/lib/smartlist_core/smartlist_core.h | 3 +- src/lib/smartlist_core/smartlist_split.h | 2 +- src/lib/string/compat_string.h | 8 +- src/lib/string/include.am | 2 + src/lib/string/parse_int.h | 2 +- src/lib/string/printf.c | 24 +- src/lib/string/printf.h | 2 +- src/lib/string/scanf.h | 2 +- src/lib/string/util_string.c | 9 +- src/lib/string/util_string.h | 5 +- src/lib/subsys/include.am | 1 + src/lib/subsys/subsys.h | 6 +- src/lib/term/getpass.h | 2 +- src/lib/term/include.am | 2 + src/lib/testsupport/include.am | 1 + src/lib/testsupport/testsupport.h | 2 +- src/lib/thread/include.am | 2 + src/lib/thread/numcpus.h | 2 +- src/lib/time/compat_time.c | 22 +- src/lib/time/compat_time.h | 52 +- src/lib/time/include.am | 2 + src/lib/time/tvdiff.h | 2 +- src/lib/tls/include.am | 2 + src/lib/tls/nss_countbytes.h | 2 +- src/lib/tls/tortls.h | 10 +- src/lib/tls/tortls_internal.h | 6 +- src/lib/tls/tortls_openssl.c | 14 +- src/lib/tls/tortls_st.h | 4 +- src/lib/tls/x509.h | 6 +- src/lib/tls/x509_internal.h | 2 +- src/lib/tls/x509_nss.c | 8 +- src/lib/tls/x509_openssl.c | 4 +- src/lib/trace/debug.h | 2 +- src/lib/trace/events.h | 6 +- src/lib/trace/include.am | 3 +- src/lib/trace/trace.h | 2 +- src/lib/version/include.am | 2 + src/lib/wallclock/approx_time.h | 2 +- src/lib/wallclock/include.am | 2 + src/lib/wallclock/time_to_tm.h | 2 +- src/lib/wallclock/timeval.h | 23 +- src/lib/wallclock/tor_gettimeofday.h | 2 +- src/rust/protover/ffi.rs | 1 + src/rust/protover/protover.rs | 8 +- src/rust/tor_log/tor_log.rs | 8 +- src/test/bench.c | 4 +- src/test/fuzz/fixup_filenames.sh | 6 +- src/test/fuzz/fuzz_multi.sh | 6 +- src/test/fuzz/fuzz_strops.c | 20 +- src/test/fuzz/fuzzing.h | 2 +- src/test/fuzz/fuzzing_common.c | 4 +- src/test/fuzz/minimize.sh | 2 +- src/test/fuzz_static_testcases.sh | 2 +- src/test/hs_test_helpers.c | 86 +- src/test/include.am | 25 +- src/test/ope_ref.py | 2 +- src/test/ptr_helpers.c | 50 + src/test/ptr_helpers.h | 23 + src/test/rng_test_helpers.c | 259 + src/test/rng_test_helpers.h | 25 + src/test/test-memwipe.c | 2 +- src/test/test-network.sh | 48 +- src/test/test.c | 27 +- src/test/test.h | 6 + src/test/test_addr.c | 45 +- src/test/test_bt.sh | 2 - src/test/test_bt_cl.c | 10 +- src/test/test_channel.c | 6 +- src/test/test_circuitbuild.c | 49 +- src/test/test_circuitpadding.c | 1429 +++- src/test/test_circuitstats.c | 16 +- src/test/test_config.c | 73 +- src/test/test_connection.h | 4 + src/test/test_containers.c | 65 + src/test/test_controller.c | 192 +- src/test/test_controller_events.c | 3 +- src/test/test_crypto.c | 36 +- src/test/test_crypto_rng.c | 8 + src/test/test_crypto_slow.c | 2 +- src/test/test_dir.c | 1211 +++- src/test/test_dir_common.h | 4 + src/test/test_dispatch.c | 249 + src/test/test_dns.c | 4 +- src/test/test_dos.c | 2 +- src/test/test_entrynodes.c | 3 +- src/test/test_extorport.c | 31 +- src/test/test_helpers.c | 2 +- src/test/test_hs.c | 16 +- src/test/test_hs_cache.c | 7 +- src/test/test_hs_cell.c | 4 +- src/test/test_hs_client.c | 41 +- src/test/test_hs_common.c | 6 +- src/test/test_hs_control.c | 7 +- src/test/test_hs_descriptor.c | 132 +- src/test/test_hs_intropoint.c | 4 +- src/test/test_hs_service.c | 98 +- src/test/test_key_expiration.sh | 14 +- src/test/test_keygen.sh | 46 +- src/test/test_link_handshake.c | 8 +- src/test/test_logging.c | 2 +- src/test/test_namemap.c | 174 + src/test/test_options.c | 5 +- src/test/test_periodic_event.c | 41 +- src/test/test_policy.c | 235 + src/test/test_prob_distr.c | 102 +- src/test/test_process.c | 4 +- src/test/test_process_slow.c | 2 +- src/test/test_protover.c | 10 +- src/test/test_pt.c | 3 +- src/test/test_ptr_slow.c | 106 + src/test/test_pubsub_build.c | 621 ++ src/test/test_pubsub_msg.c | 305 + src/test/test_rebind.sh | 11 +- src/test/test_relaycell.c | 7 +- src/test/test_relaycrypt.c | 10 +- src/test/test_rng.c | 2 +- src/test/test_router.c | 3 + src/test/test_routerkeys.c | 12 +- src/test/test_routerlist.c | 2 +- src/test/test_routerset.c | 8 +- src/test/test_rust.sh | 5 +- src/test/test_sendme.c | 365 + src/test/test_shared_random.c | 140 +- src/test/test_slow.c | 1 + src/test/test_status.c | 24 +- src/test/test_switch_id.sh | 4 +- src/test/test_tortls.c | 6 +- src/test/test_tortls.h | 2 +- src/test/test_tortls_openssl.c | 4 +- src/test/test_util.c | 75 +- src/test/test_util_format.c | 6 +- src/test/test_voting_flags.c | 2 +- src/test/test_workqueue_cancel.sh | 2 +- src/test/test_workqueue_efd.sh | 2 +- src/test/test_workqueue_efd2.sh | 2 +- src/test/test_workqueue_pipe.sh | 2 +- src/test/test_workqueue_pipe2.sh | 2 +- src/test/test_workqueue_socketpair.sh | 2 +- src/test/testing_common.c | 3 +- src/test/testing_rsakeys.c | 3 +- src/test/zero_length_keys.sh | 6 +- src/tools/tor-gencert.c | 2 +- src/tools/tor-resolve.c | 1 + src/trunnel/ed25519_cert.trunnel | 6 - src/trunnel/include.am | 3 + src/trunnel/sendme.c | 347 + src/trunnel/sendme.h | 101 + src/trunnel/sendme.trunnel | 19 + src/win32/orconfig.h | 2 +- 740 files changed, 30371 insertions(+), 13664 deletions(-) delete mode 100644 changes/29241_diagnostic delete mode 100644 changes/bug13221 create mode 100644 changes/bug22619 create mode 100644 changes/bug23507 create mode 100644 changes/bug23818_v2 create mode 100644 changes/bug23818_v3 delete mode 100644 changes/bug27199 delete mode 100644 changes/bug28525 delete mode 100644 changes/bug28614_better_logging delete mode 100644 changes/bug28656 delete mode 100644 changes/bug28698 delete mode 100644 changes/bug28925 delete mode 100644 changes/bug28979 delete mode 100644 changes/bug28981 delete mode 100644 changes/bug29017 delete mode 100644 changes/bug29029 create mode 100644 changes/bug29034 delete mode 100644 changes/bug29036 delete mode 100644 changes/bug29040 delete mode 100644 changes/bug29042 delete mode 100644 changes/bug29122 delete mode 100644 changes/bug29135 delete mode 100644 changes/bug29144 delete mode 100644 changes/bug29145 delete mode 100644 changes/bug29150 delete mode 100644 changes/bug29161 delete mode 100644 changes/bug29169 delete mode 100644 changes/bug29175_035 delete mode 100644 changes/bug29204 delete mode 100644 changes/bug29241 delete mode 100644 changes/bug29244 delete mode 100644 changes/bug29298 delete mode 100644 changes/bug29500 delete mode 100644 changes/bug29508 delete mode 100644 changes/bug29527 delete mode 100644 changes/bug29530_035 delete mode 100644 changes/bug29562 delete mode 100644 changes/bug29599 delete mode 100644 changes/bug29601 delete mode 100644 changes/bug29665 delete mode 100644 changes/bug29693 delete mode 100644 changes/bug29703 delete mode 100644 changes/bug29706_minimal delete mode 100644 changes/bug29706_refactor delete mode 100644 changes/bug29874 delete mode 100644 changes/bug29922 delete mode 100644 changes/bug29930 delete mode 100644 changes/bug29959-040 delete mode 100644 changes/bug30001 delete mode 100644 changes/bug30011 delete mode 100644 changes/bug30021 delete mode 100644 changes/bug30040 delete mode 100644 changes/bug30041 delete mode 100644 changes/bug30189 delete mode 100644 changes/bug30263 delete mode 100644 changes/bug30316 delete mode 100644 changes/bug30452 delete mode 100644 changes/bug30475 create mode 100644 changes/bug30781 create mode 100644 changes/bug30894 create mode 100644 changes/bug30942 create mode 100644 changes/bug30956 create mode 100644 changes/bug31003 create mode 100644 changes/bug31024 create mode 100644 changes/bug31027 create mode 100644 changes/bug31080_041 create mode 100644 changes/bug31343 create mode 100644 changes/bug31356_and_logs create mode 100644 changes/bug31463 create mode 100644 changes/chutney_ci delete mode 100644 changes/cid1444119 delete mode 100644 changes/diagnostic_28223_redux delete mode 100644 changes/doc28623 delete mode 100644 changes/doc29121 create mode 100644 changes/doc30630 delete mode 100644 changes/feature28976 delete mode 100644 changes/geoip-2019-02-05 delete mode 100644 changes/geoip-2019-03-04 delete mode 100644 changes/geoip-2019-04-02 delete mode 100644 changes/geoip-2019-05-13 delete mode 100644 changes/ticket21377 delete mode 100644 changes/ticket26698 delete mode 100644 changes/ticket27761 delete mode 100644 changes/ticket28614 delete mode 100644 changes/ticket28668 delete mode 100644 changes/ticket28816 delete mode 100644 changes/ticket29026 delete mode 100644 changes/ticket29072 delete mode 100644 changes/ticket29160 delete mode 100644 changes/ticket29168 delete mode 100644 changes/ticket29357 delete mode 100644 changes/ticket29435 delete mode 100644 changes/ticket29631 delete mode 100644 changes/ticket29702 delete mode 100644 changes/ticket29806 delete mode 100644 changes/ticket29897 delete mode 100644 changes/ticket29962 delete mode 100644 changes/ticket30117 delete mode 100644 changes/ticket30213 delete mode 100644 changes/ticket30234 delete mode 100644 changes/ticket30454 create mode 100644 changes/ticket30591 create mode 100644 changes/ticket30686 create mode 100644 changes/ticket30694 create mode 100644 changes/ticket30871 create mode 100644 changes/ticket31001 create mode 100644 changes/ticket31311 create mode 100644 changes/ticket31374 create mode 100644 changes/ticket31406 delete mode 100644 contrib/dist/suse/tor.sh.in delete mode 100644 contrib/dist/tor.sh.in delete mode 100644 contrib/operator-tools/linux-tor-prio.sh create mode 100644 scripts/coccinelle/ctrl-reply-cleanup.cocci create mode 100644 scripts/coccinelle/ctrl-reply.cocci create mode 100644 scripts/coccinelle/tor-coccinelle.h create mode 100755 scripts/git/git-merge-forward.sh create mode 100755 scripts/git/git-pull-all.sh create mode 100755 scripts/git/git-push-all.sh create mode 100755 scripts/git/post-merge.git-hook create mode 100755 scripts/git/pre-commit.git-hook create mode 100755 scripts/git/pre-push.git-hook create mode 100755 scripts/maint/add_c_file.py create mode 100644 scripts/maint/practracker/exceptions.txt create mode 100644 scripts/maint/practracker/metrics.py create mode 100755 scripts/maint/practracker/practracker.py create mode 100755 scripts/maint/practracker/practracker_tests.py create mode 100644 scripts/maint/practracker/problem.py create mode 100644 scripts/maint/practracker/util.py delete mode 100755 scripts/maint/pre-commit.git-hook delete mode 100755 scripts/maint/pre-push.git-hook create mode 100755 scripts/test/cov-test-determinism.sh create mode 100644 src/app/main/shutdown.c create mode 100644 src/app/main/shutdown.h create mode 100644 src/core/mainloop/mainloop_pubsub.c create mode 100644 src/core/mainloop/mainloop_pubsub.h create mode 100644 src/core/mainloop/mainloop_sys.c create mode 100644 src/core/mainloop/mainloop_sys.h create mode 100644 src/core/or/circuitpadding_machines.c create mode 100644 src/core/or/circuitpadding_machines.h create mode 100644 src/core/or/crypt_path.c create mode 100644 src/core/or/crypt_path.h create mode 100644 src/core/or/or_periodic.c create mode 100644 src/core/or/or_periodic.h create mode 100644 src/core/or/or_sys.c create mode 100644 src/core/or/or_sys.h create mode 100644 src/core/or/sendme.c create mode 100644 src/core/or/sendme.h create mode 100644 src/feature/control/control_auth.c create mode 100644 src/feature/control/control_auth.h create mode 100644 src/feature/control/control_cmd.c create mode 100644 src/feature/control/control_cmd.h create mode 100644 src/feature/control/control_cmd_args_st.h create mode 100644 src/feature/control/control_events.c create mode 100644 src/feature/control/control_events.h create mode 100644 src/feature/control/control_fmt.c create mode 100644 src/feature/control/control_fmt.h create mode 100644 src/feature/control/control_getinfo.c create mode 100644 src/feature/control/control_getinfo.h create mode 100644 src/feature/control/control_proto.c create mode 100644 src/feature/control/control_proto.h create mode 100644 src/feature/dirauth/bridgeauth.c create mode 100644 src/feature/dirauth/bridgeauth.h create mode 100644 src/feature/dirauth/dirauth_periodic.c create mode 100644 src/feature/dirauth/dirauth_periodic.h create mode 100644 src/feature/dirauth/dirauth_sys.c create mode 100644 src/feature/dirauth/dirauth_sys.h create mode 100644 src/feature/relay/relay_periodic.c create mode 100644 src/feature/relay/relay_periodic.h create mode 100644 src/feature/relay/relay_sys.c create mode 100644 src/feature/relay/relay_sys.h create mode 100644 src/lib/container/namemap.c create mode 100644 src/lib/container/namemap.h create mode 100644 src/lib/container/namemap_st.h create mode 100644 src/lib/crypt_ops/crypto_digest_nss.c create mode 100644 src/lib/crypt_ops/crypto_digest_openssl.c create mode 100644 src/lib/defs/logging_types.h create mode 100644 src/lib/dispatch/.may_include create mode 100644 src/lib/dispatch/dispatch.h create mode 100644 src/lib/dispatch/dispatch_cfg.c create mode 100644 src/lib/dispatch/dispatch_cfg.h create mode 100644 src/lib/dispatch/dispatch_cfg_st.h create mode 100644 src/lib/dispatch/dispatch_core.c create mode 100644 src/lib/dispatch/dispatch_naming.c create mode 100644 src/lib/dispatch/dispatch_naming.h create mode 100644 src/lib/dispatch/dispatch_new.c create mode 100644 src/lib/dispatch/dispatch_st.h create mode 100644 src/lib/dispatch/include.am create mode 100644 src/lib/dispatch/msgtypes.h create mode 100644 src/lib/encoding/qstring.c create mode 100644 src/lib/encoding/qstring.h create mode 100644 src/lib/pubsub/.may_include create mode 100644 src/lib/pubsub/include.am create mode 100644 src/lib/pubsub/pub_binding_st.h create mode 100644 src/lib/pubsub/pubsub.h create mode 100644 src/lib/pubsub/pubsub_build.c create mode 100644 src/lib/pubsub/pubsub_build.h create mode 100644 src/lib/pubsub/pubsub_builder_st.h create mode 100644 src/lib/pubsub/pubsub_check.c create mode 100644 src/lib/pubsub/pubsub_connect.h create mode 100644 src/lib/pubsub/pubsub_flags.h create mode 100644 src/lib/pubsub/pubsub_macros.h create mode 100644 src/lib/pubsub/pubsub_publish.c create mode 100644 src/lib/pubsub/pubsub_publish.h create mode 100644 src/test/ptr_helpers.c create mode 100644 src/test/ptr_helpers.h create mode 100644 src/test/rng_test_helpers.c create mode 100644 src/test/rng_test_helpers.h create mode 100644 src/test/test_dispatch.c create mode 100644 src/test/test_namemap.c create mode 100644 src/test/test_ptr_slow.c create mode 100644 src/test/test_pubsub_build.c create mode 100644 src/test/test_pubsub_msg.c create mode 100644 src/test/test_sendme.c create mode 100644 src/trunnel/sendme.c create mode 100644 src/trunnel/sendme.h create mode 100644 src/trunnel/sendme.trunnel (limited to 'changes') diff --git a/.gitignore b/.gitignore index a40cda02dd..0865f981b1 100644 --- a/.gitignore +++ b/.gitignore @@ -168,6 +168,8 @@ uptime-*.json /src/lib/libtor-crypt-ops-testing.a /src/lib/libtor-ctime.a /src/lib/libtor-ctime-testing.a +/src/lib/libtor-dispatch.a +/src/lib/libtor-dispatch-testing.a /src/lib/libtor-encoding.a /src/lib/libtor-encoding-testing.a /src/lib/libtor-evloop.a @@ -200,6 +202,8 @@ uptime-*.json /src/lib/libtor-osinfo-testing.a /src/lib/libtor-process.a /src/lib/libtor-process-testing.a +/src/lib/libtor-pubsub.a +/src/lib/libtor-pubsub-testing.a /src/lib/libtor-sandbox.a /src/lib/libtor-sandbox-testing.a /src/lib/libtor-string.a diff --git a/.travis.yml b/.travis.yml index 7d8877c2ac..bbba0e2048 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,15 +42,18 @@ matrix: ## include creates builds with gcc, linux include: ## We include a single coverage build with the best options for coverage - - env: COVERAGE_OPTIONS="--enable-coverage" HARDENING_OPTIONS="" + - env: COVERAGE_OPTIONS="--enable-coverage" HARDENING_OPTIONS="" TOR_TEST_RNG_SEED="636f766572616765" ## We only want to check these build option combinations once ## (they shouldn't vary by compiler or OS) ## We run rust and coverage with hardening off, which seems like enough # - env: HARDENING_OPTIONS="" ## We check asciidoc with distcheck, to make sure we remove doc products - - env: DISTCHECK="yes" ASCIIDOC_OPTIONS="" + - env: DISTCHECK="yes" ASCIIDOC_OPTIONS="" SKIP_MAKE_CHECK="yes" + # We also try running a hardened clang build with chutney on Linux. + - env: CHUTNEY="yes" SKIP_MAKE_CHECK="yes" CHUTNEY_ALLOW_FAILURES="2" + compiler: clang # We clone our stem repo and run `make test-stem` - - env: TEST_STEM="yes" + - env: TEST_STEM="yes" SKIP_MAKE_CHECK="yes" ## Check rust online with distcheck, to make sure we remove rust products - env: DISTCHECK="yes" RUST_OPTIONS="--enable-rust --enable-cargo-online-mode" ## Check disable module dirauth with and without rust @@ -72,7 +75,7 @@ matrix: ## https://docs.travis-ci.com/user/customizing-the-build#matching-jobs-with-allow_failures allow_failures: ## test-stem sometimes hangs on Travis - - env: TEST_STEM="yes" + - env: TEST_STEM="yes" SKIP_MAKE_CHECK="yes" exclude: ## gcc on OSX is less useful, because the default compiler is clang. @@ -88,7 +91,7 @@ matrix: - compiler: gcc os: linux ## TOR_RUST_DEPENDENCIES is spelt RUST_DEPENDENCIES in 0.3.2 - env: RUST_OPTIONS="--enable-rust" TOR_RUST_DEPENDENCIES=true HARDENING_OPTIONS="" + env: RUST_OPTIONS="--enable-rust" TOR_RUST_DEPENDENCIES=true ## (Linux only) Use the latest Linux image (Ubuntu Trusty) dist: trusty @@ -175,6 +178,9 @@ install: - if [[ "$RUST_OPTIONS" != "" ]]; then source $HOME/.cargo/env; fi ## If we're testing rust builds in offline-mode, then set up our vendored dependencies - if [[ "$TOR_RUST_DEPENDENCIES" == "true" ]]; then export TOR_RUST_DEPENDENCIES=$PWD/src/ext/rust/crates; fi + ## If we're running chutney, install it. + - if [[ "$CHUTNEY" != "" ]]; then git clone --depth 1 https://github.com/torproject/chutney.git ; export CHUTNEY_PATH="$(pwd)/chutney"; fi + ## If we're running stem, install it. - if [[ "$TEST_STEM" != "" ]]; then git clone --depth 1 https://github.com/torproject/stem.git ; export STEM_SOURCE_DIR=`pwd`/stem; fi ## ## Finally, list installed package versions @@ -189,7 +195,9 @@ install: - if [[ "$RUST_OPTIONS" != "" ]]; then cargo --version; fi ## Get python version - python --version - ## run stem tests if they are enabled. + ## If we're running chutney, show the chutney commit + - if [[ "$CHUTNEY" != "" ]]; then pushd "$CHUTNEY_PATH"; git log -1 ; popd ; fi + ## If we're running stem, show the stem version and commit - if [[ "$TEST_STEM" != "" ]]; then pushd stem; python -c "from stem import stem; print(stem.__version__);"; git log -1; popd; fi script: @@ -200,10 +208,12 @@ script: - echo "Configure flags are $CONFIGURE_FLAGS" - ./configure $CONFIGURE_FLAGS ## We run `make check` because that's what https://jenkins.torproject.org does. - - if [[ "$DISTCHECK" == "" && "$TEST_STEM" == "" ]]; then make check; fi - ## Diagnostic for bug 29437: kill stem if it hangs for 15 minutes - - if [[ "$TEST_STEM" != "" ]]; then make src/app/tor; timelimit -p -t 540 -s USR1 -T 30 -S ABRT python3 "$STEM_SOURCE_DIR"/run_tests.py --tor src/app/tor --integ --log notice --target RUN_ALL; fi - - if [[ "$DISTCHECK" != "" && "$TEST_STEM" == "" ]]; then make distcheck DISTCHECK_CONFIGURE_FLAGS="$CONFIGURE_FLAGS"; fi + - if [[ "$SKIP_MAKE_CHECK" == "" ]]; then make check; fi + - if [[ "$DISTCHECK" != "" ]]; then make distcheck DISTCHECK_CONFIGURE_FLAGS="$CONFIGURE_FLAGS"; fi + - if [[ "$CHUTNEY" != "" ]]; then make test-network-all; fi + ## Diagnostic for bug 29437: kill stem if it hangs for 9.5 minutes + ## Travis will kill the job after 10 minutes with no output + - if [[ "$TEST_STEM" != "" ]]; then make src/app/tor; timelimit -p -t 540 -s USR1 -T 30 -S ABRT python3 "$STEM_SOURCE_DIR"/run_tests.py --tor src/app/tor --integ --test control.controller --test control.base_controller --test process --log TRACE --log-file stem.log; fi ## If this build was one that produced coverage, upload it. - if [[ "$COVERAGE_OPTIONS" != "" ]]; then coveralls -b . --exclude src/test --exclude src/trunnel --gcov-options '\-p' || echo "Coverage failed"; fi @@ -212,11 +222,13 @@ after_failure: ## But the log is too long for travis' rendered view, so tail it. - tail -1000 config.log || echo "tail failed" ## `make check` will leave a log file with more details of test failures. - - if [[ "$DISTCHECK" == "" ]]; then cat test-suite.log || echo "cat failed"; fi + - if [[ "$SKIP_MAKE_CHECK" == "" ]]; then cat test-suite.log || echo "cat failed"; fi ## `make distcheck` puts it somewhere different. - if [[ "$DISTCHECK" != "" ]]; then make show-distdir-testlog || echo "make failed"; fi - if [[ "$DISTCHECK" != "" ]]; then make show-distdir-core || echo "make failed"; fi - - if [[ "$TEST_STEM" != "" ]]; then cat "$STEM_SOURCE_DIR"/test/data/tor_log || echo "cat failed"; fi + - if [[ "$CHUTNEY" != "" ]]; then ls test_network_log || echo "ls failed"; cat test_network_log/* || echo "cat failed"; fi + - if [[ "$TEST_STEM" != "" ]]; then tail -1000 "$STEM_SOURCE_DIR"/test/data/tor_log || echo "tail failed"; fi + - if [[ "$TEST_STEM" != "" ]]; then grep -v "SocketClosed" stem.log | tail -1000 || echo "grep | tail failed"; fi before_cache: ## Delete all gcov files. diff --git a/ChangeLog b/ChangeLog index e6bcc806e2..d44ce316c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,1086 @@ +Changes in version 0.4.1.2-alpha - 2019-06-06 + Tor 0.4.1.2-alpha resolves numerous bugs--some of them from the + previous alpha, and some much older. It also contains minor testing + improvements, and an improvement to the security of our authenticated + SENDME implementation. + + o Major bugfixes (bridges): + - Consider our directory information to have changed when our list + of bridges changes. Previously, Tor would not re-compute the + status of its directory information when bridges changed, and + therefore would not realize that it was no longer able to build + circuits. Fixes part of bug 29875. + - Do not count previously configured working bridges towards our + total of working bridges. Previously, when Tor's list of bridges + changed, it would think that the old bridges were still usable, + and delay fetching router descriptors for the new ones. Fixes part + of bug 29875; bugfix on 0.3.0.1-alpha. + + o Major bugfixes (flow control, SENDME): + - Decrement the stream-level package window after packaging a cell. + Previously, it was done inside a log_debug() call, meaning that if + debug logs were not enabled, the decrement would never happen, and + thus the window would be out of sync with the other end point. + Fixes bug 30628; bugfix on 0.4.1.1-alpha. + + o Major bugfixes (onion service reachability): + - Properly clean up the introduction point map and associated state + when circuits change purpose from onion service circuits to + pathbias, measurement, or other circuit types. This may fix some + instances of introduction point failure. Fixes bug 29034; bugfix + on 0.3.2.1-alpha. + + o Minor features (authenticated SENDME): + - Ensure that there is enough randomness on every circuit to prevent + an attacker from successfully predicting the hashes they will need + to include in authenticated SENDME cells. At a random interval, if + we have not sent randomness already, we now leave some extra space + at the end of a cell that we can fill with random bytes. Closes + ticket 26846. + + o Minor features (continuous integration): + - When running coverage builds on Travis, we now set + TOR_TEST_RNG_SEED, to avoid RNG-based coverage differences. Part + of ticket 28878. + + o Minor features (maintenance): + - Add a new "make autostyle" target that developers can use to apply + all automatic Tor style and consistency conversions to the + codebase. Closes ticket 30539. + + o Minor features (testing): + - The circuitpadding tests now use a reproducible RNG implementation, + so that if a test fails, we can learn why. Part of ticket 28878. + - Tor's tests now support an environment variable, TOR_TEST_RNG_SEED, + to set the RNG seed for tests that use a reproducible RNG. Part of + ticket 28878. + - When running tests in coverage mode, take additional care to make + our coverage deterministic, so that we can accurately track + changes in code coverage. Closes ticket 30519. + + o Minor bugfixes (configuration, proxies): + - Fix a bug that prevented us from supporting SOCKS5 proxies that + want authentication along with configured (but unused!) + ClientTransportPlugins. Fixes bug 29670; bugfix on 0.2.6.1-alpha. + + o Minor bugfixes (controller): + - POSTDESCRIPTOR requests should work again. Previously, they were + broken if a "purpose=" flag was specified. Fixes bug 30580; bugfix + on 0.4.1.1-alpha. + - Repair the HSFETCH command so that it works again. Previously, it + expected a body when it shouldn't have. Fixes bug 30646; bugfix + on 0.4.1.1-alpha. + + o Minor bugfixes (developer tooling): + - Fix pre-push hook to allow fixup and squash commits when pushing + to non-upstream git remote. Fixes bug 30286; bugfix + on 0.4.0.1-alpha. + + o Minor bugfixes (directory authority): + - Move the "bandwidth-file-headers" line in directory authority + votes so that it conforms to dir-spec.txt. Fixes bug 30316; bugfix + on 0.3.5.1-alpha. + + o Minor bugfixes (NetBSD): + - Fix usage of minherit() on NetBSD and other platforms that define + MAP_INHERIT_{ZERO,NONE} instead of INHERIT_{ZERO,NONE}. Fixes bug + 30614; bugfix on 0.4.0.2-alpha. Patch from Taylor Campbell. + + o Minor bugfixes (out-of-memory handler): + - When purging the DNS cache because of an out-of-memory condition, + try purging just the older entries at first. Previously, we would + always purge the whole thing. Fixes bug 29617; bugfix + on 0.3.5.1-alpha. + + o Minor bugfixes (portability): + - Avoid crashing in our tor_vasprintf() implementation on systems + that define neither vasprintf() nor _vscprintf(). (This bug has + been here long enough that we question whether people are running + Tor on such systems, but we're applying the fix out of caution.) + Fixes bug 30561; bugfix on 0.2.8.2-alpha. Found and fixed by + Tobias Stoeckmann. + + o Minor bugfixes (shutdown, libevent, memory safety): + - Avoid use-after-free bugs when shutting down, by making sure that + we shut down libevent only after shutting down all of its users. + We believe these are harmless in practice, since they only occur + on the shutdown path, and do not involve any attacker-controlled + data. Fixes bug 30629; bugfix on 0.4.1.1-alpha. + + o Minor bugfixes (static analysis): + - Fix several spurious Coverity warnings about the unit tests, to + lower our chances of missing real warnings in the future. Fixes + bug 30150; bugfix on 0.3.5.1-alpha and various other Tor versions. + + o Testing: + - Specify torrc paths (with empty files) when launching tor in + integration tests; refrain from reading user and system torrcs. + Resolves issue 29702. + + +Changes in version 0.4.1.1-alpha - 2019-05-22 + This is the first alpha in the 0.4.1.x series. It introduces + lightweight circuit padding to make some onion-service circuits harder + to distinguish, includes a new "authenticated SENDME" feature to make + certain denial-of-service attacks more difficult, and improves + performance in several areas. + + o Major features (circuit padding): + - Onion service clients now add padding cells at the start of their + INTRODUCE and RENDEZVOUS circuits, to make those circuits' traffic + look more like general purpose Exit traffic. The overhead for this + is 2 extra cells in each direction for RENDEZVOUS circuits, and 1 + extra upstream cell and 10 downstream cells for INTRODUCE + circuits. This feature is only enabled when also supported by the + circuit's middle node. (Clients may specify fixed middle nodes + with the MiddleNodes option, and may force-disable this feature + with the CircuitPadding torrc.) Closes ticket 28634. + + o Major features (code organization): + - Tor now includes a generic publish-subscribe message-passing + subsystem that we can use to organize intermodule dependencies. We + hope to use this to reduce dependencies between modules that don't + need to be related, and to generally simplify our codebase. Closes + ticket 28226. + + o Major features (controller protocol): + - Controller commands are now parsed using a generalized parsing + subsystem. Previously, each controller command was responsible for + parsing its own input, which led to strange inconsistencies. + Closes ticket 30091. + + o Major features (flow control): + - Implement authenticated SENDMEs as detailed in proposal 289. A + SENDME cell now includes the digest of the traffic that it + acknowledges, so that once an end point receives the SENDME, it + can confirm the other side's knowledge of the previous cells that + were sent, and prevent certain types of denial-of-service attacks. + This behavior is controlled by two new consensus parameters: see + the proposal for more details. Fixes ticket 26288. + + o Major features (performance): + - Our node selection algorithm now excludes nodes in linear time. + Previously, the algorithm was quadratic, which could slow down + heavily used onion services. Closes ticket 30307. + + o Major features (performance, RNG): + - Tor now constructs a fast secure pseudorandom number generator for + each thread, to use when performance is critical. This PRNG is + based on AES-CTR, using a buffering construction similar to + libottery and the (newer) OpenBSD arc4random() code. It + outperforms OpenSSL 1.1.1a's CSPRNG by roughly a factor of 100 for + small outputs. Although we believe it to be cryptographically + strong, we are only using it when necessary for performance. + Implements tickets 29023 and 29536. + + o Major bugfixes (onion service v3): + - Fix an unreachable bug in which an introduction point could try to + send an INTRODUCE_ACK with a status code that Trunnel would refuse + to encode, leading the relay to assert(). We've consolidated the + ABI values into Trunnel now. Fixes bug 30454; bugfix + on 0.3.0.1-alpha. + - Clients can now handle unknown status codes from INTRODUCE_ACK + cells. (The NACK behavior will stay the same.) This will allow us + to extend status codes in the future without breaking the normal + client behavior. Fixes another part of bug 30454; bugfix + on 0.3.0.1-alpha. + + o Minor features (circuit padding): + - We now use a fast PRNG when scheduling circuit padding. Part of + ticket 28636. + - Allow the padding machine designer to pick the edges of their + histogram instead of trying to compute them automatically using an + exponential formula. Resolves some undefined behavior in the case + of small histograms and allows greater flexibility on machine + design. Closes ticket 29298; bugfix on 0.4.0.1-alpha. + - Allow circuit padding machines to hold a circuit open until they + are done padding it. Closes ticket 28780. + + o Minor features (compile-time modules): + - Add a "--list-modules" command to print a list of which compile- + time modules are enabled. Closes ticket 30452. + + o Minor features (continuous integration): + - Remove sudo configuration lines from .travis.yml as they are no + longer needed with current Travis build environment. Resolves + issue 30213. + - In Travis, show stem's tor log after failure. Closes ticket 30234. + + o Minor features (controller): + - Add onion service version 3 support to the HSFETCH command. + Previously, only version 2 onion services were supported. Closes + ticket 25417. Patch by Neel Chauhan. + + o Minor features (debugging): + - Introduce tor_assertf() and tor_assertf_nonfatal() to enable + logging of additional information during assert failure. Now we + can use format strings to include information for trouble + shooting. Resolves ticket 29662. + + o Minor features (defense in depth): + - In smartlist_remove_keeporder(), set unused pointers to NULL, in + case a bug causes them to be used later. Closes ticket 30176. + Patch from Tobias Stoeckmann. + - Tor now uses a cryptographically strong PRNG even for decisions + that we do not believe are security-sensitive. Previously, for + performance reasons, we had used a trivially predictable linear + congruential generator algorithm for certain load-balancing and + statistical sampling decisions. Now we use our fast RNG in those + cases. Closes ticket 29542. + + o Minor features (developer tools): + - Tor's "practracker" test script now checks for files and functions + that seem too long and complicated. Existing overlong functions + and files are accepted for now, but should eventually be + refactored. Closes ticket 29221. + - Add some scripts used for git maintenance to scripts/git. Closes + ticket 29391. + - Call practracker from pre-push and pre-commit git hooks to let + developers know if they made any code style violations. Closes + ticket 30051. + - Add a script to check that each header has a well-formed and + unique guard macro. Closes ticket 29756. + + o Minor features (geoip): + - Update geoip and geoip6 to the May 13 2019 Maxmind GeoLite2 + Country database. Closes ticket 30522. + + o Minor features (HTTP tunnel): + - Return an informative web page when the HTTPTunnelPort is used as + an HTTP proxy. Closes ticket 27821, patch by "eighthave". + + o Minor features (IPv6, v3 onion services): + - Make v3 onion services put IPv6 addresses in service descriptors. + Before this change, service descriptors only contained IPv4 + addresses. Implements 26992. + + o Minor features (modularity): + - The "--disable-module-dirauth" compile-time option now disables + even more dirauth-only code. Closes ticket 30345. + + o Minor features (performance): + - Use OpenSSL's implementations of SHA3 when available (in OpenSSL + 1.1.1 and later), since they tend to be faster than tiny-keccak. + Closes ticket 28837. + + o Minor features (testing): + - Tor's unit test code now contains helper functions to replace the + PRNG with a deterministic or reproducible version for testing. + Previously, various tests implemented this in various ways. + Implements ticket 29732. + - We now have a script, cov-test-determinism.sh, to identify places + where our unit test coverage has become nondeterministic. Closes + ticket 29436. + - Check that representative subsets of values of `int` and `unsigned + int` can be represented by `void *`. Resolves issue 29537. + + o Minor bugfixes (bridge authority): + - Bridge authorities now set bridges as running or non-running when + about to dump their status to a file. Previously, they set bridges + as running in response to a GETINFO command, but those shouldn't + modify data structures. Fixes bug 24490; bugfix on 0.2.0.13-alpha. + Patch by Neel Chauhan. + + o Minor bugfixes (channel padding statistics): + - Channel padding write totals and padding-enabled totals are now + counted properly in relay extrainfo descriptors. Fixes bug 29231; + bugfix on 0.3.1.1-alpha. + + o Minor bugfixes (circuit padding): + - Add a "CircuitPadding" torrc option to disable circuit padding. + Fixes bug 28693; bugfix on 0.4.0.1-alpha. + - Allow circuit padding machines to specify that they do not + contribute much overhead, and provide consensus flags and torrc + options to force clients to only use these low overhead machines. + Fixes bug 29203; bugfix on 0.4.0.1-alpha. + - Provide a consensus parameter to fully disable circuit padding, to + be used in emergency network overload situations. Fixes bug 30173; + bugfix on 0.4.0.1-alpha. + - The circuit padding subsystem will no longer schedule padding if + dormant mode is enabled. Fixes bug 28636; bugfix on 0.4.0.1-alpha. + - Inspect a circuit-level cell queue before sending padding, to + avoid sending padding while too much data is already queued. Fixes + bug 29204; bugfix on 0.4.0.1-alpha. + - Avoid calling monotime_absolute_usec() in circuit padding machines + that do not use token removal or circuit RTT estimation. Fixes bug + 29085; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (compilation, unusual configurations): + - Avoid failures when building with the ALL_BUGS_ARE_FATAL option + due to missing declarations of abort(), and prevent other such + failures in the future. Fixes bug 30189; bugfix on 0.3.4.1-alpha. + + o Minor bugfixes (controller protocol): + - Teach the controller parser to distinguish an object preceded by + an argument list from one without. Previously, it couldn't + distinguish an argument list from the first line of a multiline + object. Fixes bug 29984; bugfix on 0.2.3.8-alpha. + + o Minor bugfixes (directory authority, ipv6): + - Directory authorities with IPv6 support now always mark themselves + as reachable via IPv6. Fixes bug 24338; bugfix on 0.4.0.2-alpha. + Patch by Neel Chauhan. + + o Minor bugfixes (documentation): + - Improve the documentation for using MapAddress with ".exit". Fixes + bug 30109; bugfix on 0.1.0.1-rc. + - Improve the monotonic time module and function documentation to + explain what "monotonic" actually means, and document some results + that have surprised people. Fixes bug 29640; bugfix + on 0.2.9.1-alpha. + - Use proper formatting when providing an example on quoting options + that contain whitespace. Fixes bug 29635; bugfix on 0.2.3.18-rc. + + o Minor bugfixes (logging): + - Do not log a warning when running with an OpenSSL version other + than the one Tor was compiled with, if the two versions should be + compatible. Previously, we would warn whenever the version was + different. Fixes bug 30190; bugfix on 0.2.4.2-alpha. + - Warn operators when the MyFamily option is set but ContactInfo is + missing, as the latter should be set too. Fixes bug 25110; bugfix + on 0.3.3.1-alpha. + + o Minor bugfixes (memory leak): + - Avoid a minor memory leak that could occur on relays when failing + to create a "keys" directory. Fixes bug 30148; bugfix + on 0.3.3.1-alpha. + + o Minor bugfixes (onion services): + - Avoid a GCC 9.1.1 warning (and possible crash depending on libc + implemenation) when failing to load an onion service client + authorization file. Fixes bug 30475; bugfix on 0.3.5.1-alpha. + - When refusing to launch a controller's HSFETCH request because of + rate-limiting, respond to the controller with a new response, + "QUERY_RATE_LIMITED". Previously, we would log QUERY_NO_HSDIR for + this case. Fixes bug 28269; bugfix on 0.3.1.1-alpha. Patch by + Neel Chauhan. + - When relaunching a circuit to a rendezvous service, mark the + circuit as needing high-uptime routers as appropriate. Fixes bug + 17357; bugfix on 0.4.0.2-alpha. Patch by Neel Chauhan. + - Stop ignoring IPv6 link specifiers sent to v3 onion services. + (IPv6 support for v3 onion services is still incomplete: see + ticket 23493 for details.) Fixes bug 23588; bugfix on + 0.3.2.1-alpha. Patch by Neel Chauhan. + + o Minor bugfixes (onion services, performance): + - When building circuits to onion services, call tor_addr_parse() + less often. Previously, we called tor_addr_parse() in + circuit_is_acceptable() even if its output wasn't used. This + change should improve performance when building circuits. Fixes + bug 22210; bugfix on 0.2.8.12. Patch by Neel Chauhan. + + o Minor bugfixes (performance): + - When checking whether a node is a bridge, use a fast check to make + sure that its identity is set. Previously, we used a constant-time + check, which is not necessary in this case. Fixes bug 30308; + bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (pluggable transports): + - Tor now sets TOR_PT_EXIT_ON_STDIN_CLOSE=1 for client transports as + well as servers. Fixes bug 25614; bugfix on 0.2.7.1-alpha. + + o Minor bugfixes (probability distributions): + - Refactor and improve parts of the probability distribution code + that made Coverity complain. Fixes bug 29805; bugfix + on 0.4.0.1-alpha. + + o Minor bugfixes (python): + - Stop assuming that /usr/bin/python3 exists. For scripts that work + with python2, use /usr/bin/python. Otherwise, use /usr/bin/env + python3. Fixes bug 29913; bugfix on 0.2.5.3-alpha. + + o Minor bugfixes (relay): + - When running as a relay, if IPv6Exit is set to 1 while ExitRelay + is auto, act as if ExitRelay is 1. Previously, we would ignore + IPv6Exit if ExitRelay was 0 or auto. Fixes bug 29613; bugfix on + 0.3.5.1-alpha. Patch by Neel Chauhan. + + o Minor bugfixes (stats): + - When ExtraInfoStatistics is 0, stop including bandwidth usage + statistics, GeoIPFile hashes, ServerTransportPlugin lines, and + bridge statistics by country in extra-info documents. Fixes bug + 29018; bugfix on 0.2.4.1-alpha. + + o Minor bugfixes (testing): + - Call setrlimit() to disable core dumps in test_bt_cl.c. Previously + we used `ulimit -c` in test_bt.sh, which violates POSIX shell + compatibility. Fixes bug 29061; bugfix on 0.3.5.1-alpha. + - Fix some incorrect code in the v3 onion service unit tests. Fixes + bug 29243; bugfix on 0.3.2.1-alpha. + - In the "routerkeys/*" tests, check the return values of mkdir() + for possible failures. Fixes bug 29939; bugfix on 0.2.7.2-alpha. + Found by Coverity as CID 1444254. + - Split test_utils_general() into several smaller test functions. + This makes it easier to perform resource deallocation on assert + failure, and fixes Coverity warnings CID 1444117 and CID 1444118. + Fixes bug 29823; bugfix on 0.2.9.1-alpha. + + o Minor bugfixes (tor-resolve): + - Fix a memory leak in tor-resolve that could happen if Tor gave it + a malformed SOCKS response. (Memory leaks in tor-resolve don't + actually matter, but it's good to fix them anyway.) Fixes bug + 30151; bugfix on 0.4.0.1-alpha. + + o Code simplification and refactoring: + - Abstract out the low-level formatting of replies on the control + port. Implements ticket 30007. + - Add several assertions in an attempt to fix some Coverity + warnings. Closes ticket 30149. + - Introduce a connection_dir_buf_add() helper function that checks + for compress_state of dir_connection_t and automatically writes a + string to directory connection with or without compression. + Resolves issue 28816. + - Make the base32_decode() API return the number of bytes written, + for consistency with base64_decode(). Closes ticket 28913. + - Move most relay-only periodic events out of mainloop.c into the + relay subsystem. Closes ticket 30414. + - Refactor and encapsulate parts of the codebase that manipulate + crypt_path_t objects. Resolves issue 30236. + - Refactor several places in our code that Coverity incorrectly + believed might have memory leaks. Closes ticket 30147. + - Remove redundant return values in crypto_format, and the + associated return value checks elsewhere in the code. Make the + implementations in crypto_format consistent, and remove redundant + code. Resolves ticket 29660. + - Rename tor_mem_is_zero() to fast_mem_is_zero(), to emphasize that + it is not a constant-time function. Closes ticket 30309. + - Replace hs_desc_link_specifier_t with link_specifier_t, and remove + all hs_desc_link_specifier_t-specific code. Fixes bug 22781; + bugfix on 0.3.2.1-alpha. + - Simplify v3 onion service link specifier handling code. Fixes bug + 23576; bugfix on 0.3.2.1-alpha. + - Split crypto_digest.c into NSS code, OpenSSL code, and shared + code. Resolves ticket 29108. + - Split control.c into several submodules, in preparation for + distributing its current responsibilities throughout the codebase. + Closes ticket 29894. + - Start to move responsibility for knowing about periodic events to + the appropriate subsystems, so that the mainloop doesn't need to + know all the periodic events in the rest of the codebase. + Implements tickets 30293 and 30294. + + o Documentation: + - Document how to find git commits and tags for bug fixes in + CodingStandards.md. Update some file documentation. Closes + ticket 30261. + + o Removed features: + - Remove the linux-tor-prio.sh script from contrib/operator-tools + directory. Resolves issue 29434. + - Remove the obsolete OpenSUSE initscript. Resolves issue 30076. + - Remove the obsolete script at contrib/dist/tor.sh.in. Resolves + issue 30075. + + o Code simplification and refactoring (shell scripts): + - Clean up many of our shell scripts to fix shellcheck warnings. + These include autogen.sh (ticket 26069), test_keygen.sh (ticket + 29062), test_switch_id.sh (ticket 29065), test_rebind.sh (ticket + 29063), src/test/fuzz/minimize.sh (ticket 30079), test_rust.sh + (ticket 29064), torify (ticket 29070), asciidoc-helper.sh (29926), + fuzz_multi.sh (30077), fuzz_static_testcases.sh (ticket 29059), + nagios-check-tor-authority-cert (ticket 29071), + src/test/fuzz/fixup_filenames.sh (ticket 30078), test-network.sh + (ticket 29060), test_key_expiration.sh (ticket 30002), + zero_length_keys.sh (ticket 29068), and test_workqueue_*.sh + (ticket 29067). + + o Testing (chutney): + - In "make test-network-all", test IPv6-only v3 single onion + services, using the chutney network single-onion-v23-ipv6-md. + Closes ticket 27251. + + +Changes in version 0.4.0.5 - 2019-05-02 + This is the first stable release in the 0.4.0.x series. It contains + improvements for power management and bootstrap reporting, as well as + preliminary backend support for circuit padding to prevent some kinds + of traffic analysis. It also continues our work in refactoring Tor for + long-term maintainability. + + Per our support policy, we will support the 0.4.0.x series for nine + months, or until three months after the release of a stable 0.4.1.x: + whichever is longer. If you need longer-term support, please stick + with 0.3.5.x, which will we plan to support until Feb 2022. + + Below are the changes since 0.4.0.4-rc. For a complete list of changes + since 0.3.5.7, see the ReleaseNotes file. + + o Minor features (continuous integration): + - In Travis, tell timelimit to use stem's backtrace signals, and + launch python directly from timelimit, so python receives the + signals from timelimit, rather than make. Closes ticket 30117. + + o Minor features (diagnostic): + - Add more diagnostic log messages in an attempt to solve the issue + of NUL bytes appearing in a microdescriptor cache. Related to + ticket 28223. + + o Minor features (testing): + - Use the approx_time() function when setting the "Expires" header + in directory replies, to make them more testable. Needed for + ticket 30001. + + o Minor bugfixes (rust): + - Abort on panic in all build profiles, instead of potentially + unwinding into C code. Fixes bug 27199; bugfix on 0.3.3.1-alpha. + + o Minor bugfixes (shellcheck): + - Look for scripts in their correct locations during "make + shellcheck". Previously we had looked in the wrong place during + out-of-tree builds. Fixes bug 30263; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (testing): + - Check the time in the "Expires" header using approx_time(). Fixes + bug 30001; bugfix on 0.4.0.4-rc. + + o Minor bugfixes (UI): + - Lower log level of unlink() errors during bootstrap. Fixes bug + 29930; bugfix on 0.4.0.1-alpha. + + +Changes in version 0.4.0.4-rc - 2019-04-11 + Tor 0.4.0.4-rc is the first release candidate in its series; it fixes + several bugs from earlier versions, including some that had affected + stability, and one that prevented relays from working with NSS. + + o Major bugfixes (NSS, relay): + - When running with NSS, disable TLS 1.2 ciphersuites that use + SHA384 for their PRF. Due to an NSS bug, the TLS key exporters for + these ciphersuites don't work -- which caused relays to fail to + handshake with one another when these ciphersuites were enabled. + Fixes bug 29241; bugfix on 0.3.5.1-alpha. + + o Minor features (bandwidth authority): + - Make bandwidth authorities ignore relays that are reported in the + bandwidth file with the flag "vote=0". This change allows us to + report unmeasured relays for diagnostic reasons without including + their bandwidth in the bandwidth authorities' vote. Closes + ticket 29806. + - When a directory authority is using a bandwidth file to obtain the + bandwidth values that will be included in the next vote, serve + this bandwidth file at /tor/status-vote/next/bandwidth. Closes + ticket 21377. + + o Minor features (circuit padding): + - Stop warning about undefined behavior in the probability + distribution tests. Float division by zero may technically be + undefined behavior in C, but it's well defined in IEEE 754. + Partial backport of 29298. Closes ticket 29527; bugfix + on 0.4.0.1-alpha. + + o Minor features (continuous integration): + - On Travis Rust builds, cleanup Rust registry and refrain from + caching the "target/" directory to speed up builds. Resolves + issue 29962. + + o Minor features (dormant mode): + - Add a DormantCanceledByStartup option to tell Tor that it should + treat a startup event as cancelling any previous dormant state. + Integrators should use this option with caution: it should only be + used if Tor is being started because of something that the user + did, and not if Tor is being automatically started in the + background. Closes ticket 29357. + + o Minor features (geoip): + - Update geoip and geoip6 to the April 2 2019 Maxmind GeoLite2 + Country database. Closes ticket 29992. + + o Minor features (NSS, diagnostic): + - Try to log an error from NSS (if there is any) and a more useful + description of our situation if we are using NSS and a call to + SSL_ExportKeyingMaterial() fails. Diagnostic for ticket 29241. + + o Minor bugfixes (security): + - Fix a potential double free bug when reading huge bandwidth files. + The issue is not exploitable in the current Tor network because + the vulnerable code is only reached when directory authorities + read bandwidth files, but bandwidth files come from a trusted + source (usually the authorities themselves). Furthermore, the + issue is only exploitable in rare (non-POSIX) 32-bit architectures, + which are not used by any of the current authorities. Fixes bug + 30040; bugfix on 0.3.5.1-alpha. Bug found and fixed by + Tobias Stoeckmann. + - Verify in more places that we are not about to create a buffer + with more than INT_MAX bytes, to avoid possible OOB access in the + event of bugs. Fixes bug 30041; bugfix on 0.2.0.16. Found and + fixed by Tobias Stoeckmann. + + o Minor bugfix (continuous integration): + - Reset coverage state on disk after Travis CI has finished. This + should prevent future coverage merge errors from causing the test + suite for the "process" subsystem to fail. The process subsystem + was introduced in 0.4.0.1-alpha. Fixes bug 29036; bugfix + on 0.2.9.15. + - Terminate test-stem if it takes more than 9.5 minutes to run. + (Travis terminates the job after 10 minutes of no output.) + Diagnostic for 29437. Fixes bug 30011; bugfix on 0.3.5.4-alpha. + + o Minor bugfixes (bootstrap reporting): + - During bootstrap reporting, correctly distinguish pluggable + transports from plain proxies. Fixes bug 28925; bugfix + on 0.4.0.1-alpha. + + o Minor bugfixes (C correctness): + - Fix an unlikely memory leak in consensus_diff_apply(). Fixes bug + 29824; bugfix on 0.3.1.1-alpha. This is Coverity warning + CID 1444119. + + o Minor bugfixes (circuitpadding testing): + - Minor tweaks to avoid rare test failures related to timers and + monotonic time. Fixes bug 29500; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (directory authorities): + - Actually include the bandwidth-file-digest line in directory + authority votes. Fixes bug 29959; bugfix on 0.4.0.2-alpha. + + o Minor bugfixes (logging): + - On Windows, when errors cause us to reload a consensus from disk, + tell the user that we are retrying at log level "notice". + Previously we only logged this information at "info", which was + confusing because the errors themselves were logged at "warning". + Improves previous fix for 28614. Fixes bug 30004; bugfix + on 0.4.0.2-alpha. + + o Minor bugfixes (pluggable transports): + - Restore old behavior when it comes to discovering the path of a + given Pluggable Transport executable file. A change in + 0.4.0.1-alpha had broken this behavior on paths containing a + space. Fixes bug 29874; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (testing): + - Backport the 0.3.4 src/test/test-network.sh to 0.2.9. We need a + recent test-network.sh to use new chutney features in CI. Fixes + bug 29703; bugfix on 0.2.9.1-alpha. + - Fix a test failure on Windows caused by an unexpected "BUG" + warning in our tests for tor_gmtime_r(-1). Fixes bug 29922; bugfix + on 0.2.9.3-alpha. + + o Minor bugfixes (TLS protocol): + - When classifying a client's selection of TLS ciphers, if the + client ciphers are not yet available, do not cache the result. + Previously, we had cached the unavailability of the cipher list + and never looked again, which in turn led us to assume that the + client only supported the ancient V1 link protocol. This, in turn, + was causing Stem integration tests to stall in some cases. Fixes + bug 30021; bugfix on 0.2.4.8-alpha. + + o Code simplification and refactoring: + - Introduce a connection_dir_buf_add() helper function that detects + whether compression is in use, and adds a string accordingly. + Resolves issue 28816. + - Refactor handle_get_next_bandwidth() to use + connection_dir_buf_add(). Implements ticket 29897. + + o Documentation: + - Clarify that Tor performs stream isolation among *Port listeners + by default. Resolves issue 29121. + + +Changes in version 0.4.0.3-alpha - 2019-03-22 + Tor 0.4.0.3-alpha is the third in its series; it fixes several small + bugs from earlier versions. + + o Minor features (address selection): + - Treat the subnet 100.64.0.0/10 as public for some purposes; + private for others. This subnet is the RFC 6598 (Carrier Grade + NAT) IP range, and is deployed by many ISPs as an alternative to + RFC 1918 that does not break existing internal networks. Tor now + blocks SOCKS and control ports on these addresses and warns users + if client ports or ExtORPorts are listening on a RFC 6598 address. + Closes ticket 28525. Patch by Neel Chauhan. + + o Minor features (geoip): + - Update geoip and geoip6 to the March 4 2019 Maxmind GeoLite2 + Country database. Closes ticket 29666. + + o Minor bugfixes (circuitpadding): + - Inspect the circuit-level cell queue before sending padding, to + avoid sending padding when too much data is queued. Fixes bug + 29204; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (logging): + - Correct a misleading error message when IPv4Only or IPv6Only is + used but the resolved address can not be interpreted as an address + of the specified IP version. Fixes bug 13221; bugfix on + 0.2.3.9-alpha. Patch from Kris Katterjohn. + - Log the correct port number for listening sockets when "auto" is + used to let Tor pick the port number. Previously, port 0 was + logged instead of the actual port number. Fixes bug 29144; bugfix + on 0.3.5.1-alpha. Patch from Kris Katterjohn. + - Stop logging a BUG() warning when Tor is waiting for exit + descriptors. Fixes bug 28656; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (memory management): + - Refactor the shared random state's memory management so that it + actually takes ownership of the shared random value pointers. + Fixes bug 29706; bugfix on 0.2.9.1-alpha. + + o Minor bugfixes (memory management, testing): + - Stop leaking parts of the shared random state in the shared-random + unit tests. Fixes bug 29599; bugfix on 0.2.9.1-alpha. + + o Minor bugfixes (pluggable transports): + - Fix an assertion failure crash bug when a pluggable transport is + terminated during the bootstrap phase. Fixes bug 29562; bugfix + on 0.4.0.1-alpha. + + o Minor bugfixes (Rust, protover): + - Add a missing "Padding" value to the Rust implementation of + protover. Fixes bug 29631; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (single onion services): + - Allow connections to single onion services to remain idle without + being disconnected. Previously, relays acting as rendezvous points + for single onion services were mistakenly closing idle rendezvous + circuits after 60 seconds, thinking that they were unused + directory-fetching circuits that had served their purpose. Fixes + bug 29665; bugfix on 0.2.1.26. + + o Minor bugfixes (stats): + - When ExtraInfoStatistics is 0, stop including PaddingStatistics in + relay and bridge extra-info documents. Fixes bug 29017; bugfix + on 0.3.1.1-alpha. + + o Minor bugfixes (testing): + - Downgrade some LOG_ERR messages in the address/* tests to + warnings. The LOG_ERR messages were occurring when we had no + configured network. We were failing the unit tests, because we + backported 28668 to 0.3.5.8, but did not backport 29530. Fixes bug + 29530; bugfix on 0.3.5.8. + - Fix our gcov wrapper script to look for object files at the + correct locations. Fixes bug 29435; bugfix on 0.3.5.1-alpha. + - Decrease the false positive rate of stochastic probability + distribution tests. Fixes bug 29693; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (Windows, CI): + - Skip the Appveyor 32-bit Windows Server 2016 job, and 64-bit + Windows Server 2012 R2 job. The remaining 2 jobs still provide + coverage of 64/32-bit, and Windows Server 2016/2012 R2. Also set + fast_finish, so failed jobs terminate the build immediately. Fixes + bug 29601; bugfix on 0.3.5.4-alpha. + + +Changes in version 0.3.5.8 - 2019-02-21 + Tor 0.3.5.8 backports several fixes from later releases, including fixes + for an annoying SOCKS-parsing bug that affected users in earlier 0.3.5.x + releases. + + It also includes a fix for a medium-severity security bug affecting Tor + 0.3.2.1-alpha and later. All Tor instances running an affected release + should upgrade to 0.3.3.12, 0.3.4.11, 0.3.5.8, or 0.4.0.2-alpha. + + o Major bugfixes (cell scheduler, KIST, security): + - Make KIST consider the outbuf length when computing what it can + put in the outbuf. Previously, KIST acted as though the outbuf + were empty, which could lead to the outbuf becoming too full. It + is possible that an attacker could exploit this bug to cause a Tor + client or relay to run out of memory and crash. Fixes bug 29168; + bugfix on 0.3.2.1-alpha. This issue is also being tracked as + TROVE-2019-001 and CVE-2019-8955. + + o Major bugfixes (networking, backport from 0.4.0.2-alpha): + - Gracefully handle empty username/password fields in SOCKS5 + username/password auth message and allow SOCKS5 handshake to + continue. Previously, we had rejected these handshakes, breaking + certain applications. Fixes bug 29175; bugfix on 0.3.5.1-alpha. + + o Minor features (compilation, backport from 0.4.0.2-alpha): + - Compile correctly when OpenSSL is built with engine support + disabled, or with deprecated APIs disabled. Closes ticket 29026. + Patches from "Mangix". + + o Minor features (geoip): + - Update geoip and geoip6 to the February 5 2019 Maxmind GeoLite2 + Country database. Closes ticket 29478. + + o Minor features (testing, backport from 0.4.0.2-alpha): + - Treat all unexpected ERR and BUG messages as test failures. Closes + ticket 28668. + + o Minor bugfixes (onion service v3, client, backport from 0.4.0.1-alpha): + - Stop logging a "BUG()" warning and stacktrace when we find a SOCKS + connection waiting for a descriptor that we actually have in the + cache. It turns out that this can actually happen, though it is + rare. Now, tor will recover and retry the descriptor. Fixes bug + 28669; bugfix on 0.3.2.4-alpha. + + o Minor bugfixes (IPv6, backport from 0.4.0.1-alpha): + - Fix tor_ersatz_socketpair on IPv6-only systems. Previously, the + IPv6 socket was bound using an address family of AF_INET instead + of AF_INET6. Fixes bug 28995; bugfix on 0.3.5.1-alpha. Patch from + Kris Katterjohn. + + o Minor bugfixes (build, compatibility, rust, backport from 0.4.0.2-alpha): + - Update Cargo.lock file to match the version made by the latest + version of Rust, so that "make distcheck" will pass again. Fixes + bug 29244; bugfix on 0.3.3.4-alpha. + + o Minor bugfixes (client, clock skew, backport from 0.4.0.1-alpha): + - Select guards even if the consensus has expired, as long as the + consensus is still reasonably live. Fixes bug 24661; bugfix + on 0.3.0.1-alpha. + + o Minor bugfixes (compilation, backport from 0.4.0.1-alpha): + - Compile correctly on OpenBSD; previously, we were missing some + headers required in order to detect it properly. Fixes bug 28938; + bugfix on 0.3.5.1-alpha. Patch from Kris Katterjohn. + + o Minor bugfixes (documentation, backport from 0.4.0.2-alpha): + - Describe the contents of the v3 onion service client authorization + files correctly: They hold public keys, not private keys. Fixes + bug 28979; bugfix on 0.3.5.1-alpha. Spotted by "Felixix". + + o Minor bugfixes (logging, backport from 0.4.0.1-alpha): + - Rework rep_hist_log_link_protocol_counts() to iterate through all + link protocol versions when logging incoming/outgoing connection + counts. Tor no longer skips version 5, and we won't have to + remember to update this function when new link protocol version is + developed. Fixes bug 28920; bugfix on 0.2.6.10. + + o Minor bugfixes (logging, backport from 0.4.0.2-alpha): + - Log more information at "warning" level when unable to read a + private key; log more information at "info" level when unable to + read a public key. We had warnings here before, but they were lost + during our NSS work. Fixes bug 29042; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (misc, backport from 0.4.0.2-alpha): + - The amount of total available physical memory is now determined + using the sysctl identifier HW_PHYSMEM (rather than HW_USERMEM) + when it is defined and a 64-bit variant is not available. Fixes + bug 28981; bugfix on 0.2.5.4-alpha. Patch from Kris Katterjohn. + + o Minor bugfixes (onion services, backport from 0.4.0.2-alpha): + - Avoid crashing if ClientOnionAuthDir (incorrectly) contains more + than one private key for a hidden service. Fixes bug 29040; bugfix + on 0.3.5.1-alpha. + - In hs_cache_store_as_client() log an HSDesc we failed to parse at + "debug" level. Tor used to log it as a warning, which caused very + long log lines to appear for some users. Fixes bug 29135; bugfix + on 0.3.2.1-alpha. + - Stop logging "Tried to establish rendezvous on non-OR circuit..." + as a warning. Instead, log it as a protocol warning, because there + is nothing that relay operators can do to fix it. Fixes bug 29029; + bugfix on 0.2.5.7-rc. + + o Minor bugfixes (tests, directory clients, backport from 0.4.0.1-alpha): + - Mark outdated dirservers when Tor only has a reasonably live + consensus. Fixes bug 28569; bugfix on 0.3.2.5-alpha. + + o Minor bugfixes (tests, backport from 0.4.0.2-alpha): + - Detect and suppress "bug" warnings from the util/time test on + Windows. Fixes bug 29161; bugfix on 0.2.9.3-alpha. + - Do not log an error-level message if we fail to find an IPv6 + network interface from the unit tests. Fixes bug 29160; bugfix + on 0.2.7.3-rc. + + o Minor bugfixes (usability, backport from 0.4.0.1-alpha): + - Stop saying "Your Guard ..." in pathbias_measure_{use,close}_rate(). + Some users took this phrasing to mean that the mentioned guard was + under their control or responsibility, which it is not. Fixes bug + 28895; bugfix on Tor 0.3.0.1-alpha. + + +Changes in version 0.3.4.11 - 2019-02-21 + Tor 0.3.4.11 is the third stable release in its series. It includes + a fix for a medium-severity security bug affecting Tor 0.3.2.1-alpha and + later. All Tor instances running an affected release should upgrade to + 0.3.3.12, 0.3.4.11, 0.3.5.8, or 0.4.0.2-alpha. + + o Major bugfixes (cell scheduler, KIST, security): + - Make KIST consider the outbuf length when computing what it can + put in the outbuf. Previously, KIST acted as though the outbuf + were empty, which could lead to the outbuf becoming too full. It + is possible that an attacker could exploit this bug to cause a Tor + client or relay to run out of memory and crash. Fixes bug 29168; + bugfix on 0.3.2.1-alpha. This issue is also being tracked as + TROVE-2019-001 and CVE-2019-8955. + + o Minor features (geoip): + - Update geoip and geoip6 to the February 5 2019 Maxmind GeoLite2 + Country database. Closes ticket 29478. + + o Minor bugfixes (build, compatibility, rust, backport from 0.4.0.2-alpha): + - Update Cargo.lock file to match the version made by the latest + version of Rust, so that "make distcheck" will pass again. Fixes + bug 29244; bugfix on 0.3.3.4-alpha. + + o Minor bugfixes (onion services, backport from 0.4.0.2-alpha): + - Stop logging "Tried to establish rendezvous on non-OR circuit..." + as a warning. Instead, log it as a protocol warning, because there + is nothing that relay operators can do to fix it. Fixes bug 29029; + bugfix on 0.2.5.7-rc. + + +Changes in version 0.3.3.12 - 2019-02-21 + Tor 0.3.3.12 fixes a medium-severity security bug affecting Tor + 0.3.2.1-alpha and later. All Tor instances running an affected release + should upgrade to 0.3.3.12, 0.3.4.11, 0.3.5.8, or 0.4.0.2-alpha. + + This release marks the end of support for the Tor 0.3.3.x series. We + recommend that users switch to either the Tor 0.3.4 series (supported + until at least 10 June 2019), or the Tor 0.3.5 series, which will + receive long-term support until at least 1 Feb 2022. + + o Major bugfixes (cell scheduler, KIST, security): + - Make KIST consider the outbuf length when computing what it can + put in the outbuf. Previously, KIST acted as though the outbuf + were empty, which could lead to the outbuf becoming too full. It + is possible that an attacker could exploit this bug to cause a Tor + client or relay to run out of memory and crash. Fixes bug 29168; + bugfix on 0.3.2.1-alpha. This issue is also being tracked as + TROVE-2019-001 and CVE-2019-8955. + + o Minor features (geoip): + - Update geoip and geoip6 to the February 5 2019 Maxmind GeoLite2 + Country database. Closes ticket 29478. + + o Minor bugfixes (build, compatibility, rust, backport from 0.4.0.2-alpha): + - Update Cargo.lock file to match the version made by the latest + version of Rust, so that "make distcheck" will pass again. Fixes + bug 29244; bugfix on 0.3.3.4-alpha. + + o Minor bugfixes (onion services, backport from 0.4.0.2-alpha): + - Stop logging "Tried to establish rendezvous on non-OR circuit..." + as a warning. Instead, log it as a protocol warning, because there + is nothing that relay operators can do to fix it. Fixes bug 29029; + bugfix on 0.2.5.7-rc. + + +Changes in version 0.4.0.2-alpha - 2019-02-21 + Tor 0.4.0.2-alpha is the second alpha in its series; it fixes several + bugs from earlier versions, including several that had broken + backward compatibility. + + It also includes a fix for a medium-severity security bug affecting Tor + 0.3.2.1-alpha and later. All Tor instances running an affected release + should upgrade to 0.3.3.12, 0.3.4.11, 0.3.5.8, or 0.4.0.2-alpha. + + o Major bugfixes (cell scheduler, KIST, security): + - Make KIST consider the outbuf length when computing what it can + put in the outbuf. Previously, KIST acted as though the outbuf + were empty, which could lead to the outbuf becoming too full. It + is possible that an attacker could exploit this bug to cause a Tor + client or relay to run out of memory and crash. Fixes bug 29168; + bugfix on 0.3.2.1-alpha. This issue is also being tracked as + TROVE-2019-001 and CVE-2019-8955. + + o Major bugfixes (networking): + - Gracefully handle empty username/password fields in SOCKS5 + username/password auth messsage and allow SOCKS5 handshake to + continue. Previously, we had rejected these handshakes, breaking + certain applications. Fixes bug 29175; bugfix on 0.3.5.1-alpha. + + o Major bugfixes (windows, startup): + - When reading a consensus file from disk, detect whether it was + written in text mode, and re-read it in text mode if so. Always + write consensus files in binary mode so that we can map them into + memory later. Previously, we had written in text mode, which + confused us when we tried to map the file on windows. Fixes bug + 28614; bugfix on 0.4.0.1-alpha. + + o Minor features (compilation): + - Compile correctly when OpenSSL is built with engine support + disabled, or with deprecated APIs disabled. Closes ticket 29026. + Patches from "Mangix". + + o Minor features (developer tooling): + - Check that bugfix versions in changes files look like Tor versions + from the versions spec. Warn when bugfixes claim to be on a future + release. Closes ticket 27761. + - Provide a git pre-commit hook that disallows committing if we have + any failures in our code and changelog formatting checks. It is + now available in scripts/maint/pre-commit.git-hook. Implements + feature 28976. + + o Minor features (directory authority): + - When a directory authority is using a bandwidth file to obtain + bandwidth values, include the digest of that file in the vote. + Closes ticket 26698. + + o Minor features (geoip): + - Update geoip and geoip6 to the February 5 2019 Maxmind GeoLite2 + Country database. Closes ticket 29478. + + o Minor features (testing): + - Treat all unexpected ERR and BUG messages as test failures. Closes + ticket 28668. + + o Minor bugfixes (build, compatibility, rust): + - Update Cargo.lock file to match the version made by the latest + version of Rust, so that "make distcheck" will pass again. Fixes + bug 29244; bugfix on 0.3.3.4-alpha. + + o Minor bugfixes (compilation): + - Fix compilation warnings in test_circuitpadding.c. Fixes bug + 29169; bugfix on 0.4.0.1-alpha. + - Silence a compiler warning in test-memwipe.c on OpenBSD. Fixes bug + 29145; bugfix on 0.2.9.3-alpha. Patch from Kris Katterjohn. + + o Minor bugfixes (documentation): + - Describe the contents of the v3 onion service client authorization + files correctly: They hold public keys, not private keys. Fixes + bug 28979; bugfix on 0.3.5.1-alpha. Spotted by "Felixix". + + o Minor bugfixes (linux seccomp sandbox): + - Fix startup crash when experimental sandbox support is enabled. + Fixes bug 29150; bugfix on 0.4.0.1-alpha. Patch by Peter Gerber. + + o Minor bugfixes (logging): + - Avoid logging that we are relaxing a circuit timeout when that + timeout is fixed. Fixes bug 28698; bugfix on 0.2.4.7-alpha. + - Log more information at "warning" level when unable to read a + private key; log more information at "info" level when unable to + read a public key. We had warnings here before, but they were lost + during our NSS work. Fixes bug 29042; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (misc): + - The amount of total available physical memory is now determined + using the sysctl identifier HW_PHYSMEM (rather than HW_USERMEM) + when it is defined and a 64-bit variant is not available. Fixes + bug 28981; bugfix on 0.2.5.4-alpha. Patch from Kris Katterjohn. + + o Minor bugfixes (onion services): + - Avoid crashing if ClientOnionAuthDir (incorrectly) contains more + than one private key for a hidden service. Fixes bug 29040; bugfix + on 0.3.5.1-alpha. + - In hs_cache_store_as_client() log an HSDesc we failed to parse at + "debug" level. Tor used to log it as a warning, which caused very + long log lines to appear for some users. Fixes bug 29135; bugfix + on 0.3.2.1-alpha. + - Stop logging "Tried to establish rendezvous on non-OR circuit..." + as a warning. Instead, log it as a protocol warning, because there + is nothing that relay operators can do to fix it. Fixes bug 29029; + bugfix on 0.2.5.7-rc. + + o Minor bugfixes (scheduler): + - When re-adding channels to the pending list, check the correct + channel's sched_heap_idx. This issue has had no effect in mainline + Tor, but could have led to bugs down the road in improved versions + of our circuit scheduling code. Fixes bug 29508; bugfix + on 0.3.2.10. + + o Minor bugfixes (tests): + - Fix intermittent failures on an adaptive padding test. Fixes one + case of bug 29122; bugfix on 0.4.0.1-alpha. + - Disable an unstable circuit-padding test that was failing + intermittently because of an ill-defined small histogram. Such + histograms will be allowed again after 29298 is implemented. Fixes + a second case of bug 29122; bugfix on 0.4.0.1-alpha. + - Detect and suppress "bug" warnings from the util/time test on + Windows. Fixes bug 29161; bugfix on 0.2.9.3-alpha. + - Do not log an error-level message if we fail to find an IPv6 + network interface from the unit tests. Fixes bug 29160; bugfix + on 0.2.7.3-rc. + + o Documentation: + - In the manpage entry describing MapAddress torrc setting, use + example IP addresses from ranges specified for use in documentation + by RFC 5737. Resolves issue 28623. + + o Removed features: + - Remove the old check-tor script. Resolves issue 29072. + + Changes in version 0.4.0.1-alpha - 2019-01-18 Tor 0.4.0.1-alpha is the first release in the new 0.4.0.x series. It introduces improved features for power and bandwidth conservation, diff --git a/Makefile.am b/Makefile.am index 8bf2aaf910..10bd4b45c2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,6 +41,8 @@ TOR_UTIL_LIBS = \ src/lib/libtor-geoip.a \ src/lib/libtor-process.a \ src/lib/libtor-buf.a \ + src/lib/libtor-pubsub.a \ + src/lib/libtor-dispatch.a \ src/lib/libtor-time.a \ src/lib/libtor-fs.a \ src/lib/libtor-encoding.a \ @@ -72,6 +74,8 @@ TOR_UTIL_TESTING_LIBS = \ src/lib/libtor-geoip-testing.a \ src/lib/libtor-process-testing.a \ src/lib/libtor-buf-testing.a \ + src/lib/libtor-pubsub-testing.a \ + src/lib/libtor-dispatch-testing.a \ src/lib/libtor-time-testing.a \ src/lib/libtor-fs-testing.a \ src/lib/libtor-encoding-testing.a \ @@ -161,7 +165,12 @@ EXTRA_DIST+= \ README \ ReleaseNotes \ scripts/maint/checkIncludes.py \ - scripts/maint/checkSpace.pl + scripts/maint/checkSpace.pl \ + scripts/maint/practracker/exceptions.txt \ + scripts/maint/practracker/metrics.py \ + scripts/maint/practracker/practracker.py \ + scripts/maint/practracker/problem.py \ + scripts/maint/practracker/util.py ## This tells etags how to find mockable function definitions. AM_ETAGSFLAGS=--regex='{c}/MOCK_IMPL([^,]+,\W*\([a-zA-Z0-9_]+\)\W*,/\1/s' @@ -328,11 +337,8 @@ coverage-html-full: all lcov --remove "$(HTML_COVER_DIR)/lcov.tmp" --rc lcov_branch_coverage=1 'test/*' 'ext/tinytest*' '/usr/*' --output-file "$(HTML_COVER_DIR)/lcov.info" genhtml --branch-coverage -o "$(HTML_COVER_DIR)" "$(HTML_COVER_DIR)/lcov.info" -# Avoid strlcpy.c, strlcat.c, aes.c, OpenBSD_malloc_Linux.c, sha256.c, -# tinytest*.[ch] -check-spaces: -if USE_PERL - $(PERL) $(top_srcdir)/scripts/maint/checkSpace.pl -C \ +# For scripts: avoid src/ext and src/trunnel. +OWNED_TOR_C_FILES=\ $(top_srcdir)/src/lib/*/*.[ch] \ $(top_srcdir)/src/core/*/*.[ch] \ $(top_srcdir)/src/feature/*/*.[ch] \ @@ -340,6 +346,11 @@ if USE_PERL $(top_srcdir)/src/test/*.[ch] \ $(top_srcdir)/src/test/*/*.[ch] \ $(top_srcdir)/src/tools/*.[ch] + +check-spaces: +if USE_PERL + $(PERL) $(top_srcdir)/scripts/maint/checkSpace.pl -C \ + $(OWNED_TOR_C_FILES) endif check-includes: @@ -347,6 +358,14 @@ if USEPYTHON $(PYTHON) $(top_srcdir)/scripts/maint/checkIncludes.py endif +check-best-practices: +if USEPYTHON + $(PYTHON) $(top_srcdir)/scripts/maint/practracker/practracker.py $(top_srcdir) +endif + +practracker-regen: + $(PYTHON) $(top_srcdir)/scripts/maint/practracker/practracker.py --regen $(top_srcdir) + check-docs: all $(PERL) $(top_builddir)/scripts/maint/checkOptionDocs.pl @@ -442,6 +461,25 @@ version: (cd "$(top_srcdir)" && git rev-parse --short=16 HEAD); \ fi +.PHONY: autostyle-ifdefs +autostyle-ifdefs: + $(PYTHON) scripts/maint/annotate_ifdef_directives $(OWNED_TOR_C_FILES) + +.PHONY: autostyle-ifdefs +autostyle-operators: + $(PERL) scripts/coccinelle/test-operator-cleanup $(OWNED_TOR_C_FILES) + +.PHONY: rectify-includes +rectify-includes: + $(PYTHON) scripts/maint/rectify_include_paths.py + +.PHONY: update-copyright +update-copyright: + $(PERL) scripts/maint/updateCopyright.pl $(OWNED_TOR_C_FILES) + +.PHONY: autostyle +autostyle: update-versions rustfmt autostyle-ifdefs rectify-includes + mostlyclean-local: rm -f $(top_builddir)/src/*/*.gc{da,no} $(top_builddir)/src/*/*/*.gc{da,no} rm -rf $(HTML_COVER_DIR) diff --git a/ReleaseNotes b/ReleaseNotes index 6c9aa3c294..788804236b 100644 --- a/ReleaseNotes +++ b/ReleaseNotes @@ -2,6 +2,791 @@ This document summarizes new features and bugfixes in each stable release of Tor. If you want to see more detailed descriptions of the changes in each development snapshot, see the ChangeLog file. +Changes in version 0.4.0.5 - 2019-05-02 + This is the first stable release in the 0.4.0.x series. It contains + improvements for power management and bootstrap reporting, as well as + preliminary backend support for circuit padding to prevent some kinds + of traffic analysis. It also continues our work in refactoring Tor for + long-term maintainability. + + Per our support policy, we will support the 0.4.0.x series for nine + months, or until three months after the release of a stable 0.4.1.x: + whichever is longer. If you need longer-term support, please stick + with 0.3.5.x, which will we plan to support until Feb 2022. + + Below are the changes since 0.3.5.7. For a complete list of changes + since 0.4.0.4-rc, see the ChangeLog file. + + o Major features (battery management, client, dormant mode): + - When Tor is running as a client, and it is unused for a long time, + it can now enter a "dormant" state. When Tor is dormant, it avoids + network and CPU activity until it is reawoken either by a user + request or by a controller command. For more information, see the + configuration options starting with "Dormant". Implements tickets + 2149 and 28335. + - The client's memory of whether it is "dormant", and how long it + has spent idle, persists across invocations. Implements + ticket 28624. + - There is a DormantOnFirstStartup option that integrators can use + if they expect that in many cases, Tor will be installed but + not used. + + o Major features (bootstrap reporting): + - When reporting bootstrap progress, report the first connection + uniformly, regardless of whether it's a connection for building + application circuits. This allows finer-grained reporting of early + progress than previously possible, with the improvements of ticket + 27169. Closes tickets 27167 and 27103. Addresses ticket 27308. + - When reporting bootstrap progress, treat connecting to a proxy or + pluggable transport as separate from having successfully used that + proxy or pluggable transport to connect to a relay. Closes tickets + 27100 and 28884. + + o Major features (circuit padding): + - Implement preliminary support for the circuit padding portion of + Proposal 254. The implementation supports Adaptive Padding (aka + WTF-PAD) state machines for use between experimental clients and + relays. Support is also provided for APE-style state machines that + use probability distributions instead of histograms to specify + inter-packet delay. At the moment, Tor does not provide any + padding state machines that are used in normal operation: for now, + this feature exists solely for experimentation. Closes + ticket 28142. + + o Major features (refactoring): + - Tor now uses an explicit list of its own subsystems when + initializing and shutting down. Previously, these systems were + managed implicitly in various places throughout the codebase. + (There may still be some subsystems using the old system.) Closes + ticket 28330. + + o Major bugfixes (cell scheduler, KIST, security): + - Make KIST consider the outbuf length when computing what it can + put in the outbuf. Previously, KIST acted as though the outbuf + were empty, which could lead to the outbuf becoming too full. It + is possible that an attacker could exploit this bug to cause a Tor + client or relay to run out of memory and crash. Fixes bug 29168; + bugfix on 0.3.2.1-alpha. This issue is also being tracked as + TROVE-2019-001 and CVE-2019-8955. + + o Major bugfixes (networking): + - Gracefully handle empty username/password fields in SOCKS5 + username/password auth message and allow SOCKS5 handshake to + continue. Previously, we had rejected these handshakes, breaking + certain applications. Fixes bug 29175; bugfix on 0.3.5.1-alpha. + + o Major bugfixes (NSS, relay): + - When running with NSS, disable TLS 1.2 ciphersuites that use + SHA384 for their PRF. Due to an NSS bug, the TLS key exporters for + these ciphersuites don't work -- which caused relays to fail to + handshake with one another when these ciphersuites were enabled. + Fixes bug 29241; bugfix on 0.3.5.1-alpha. + + o Major bugfixes (windows, startup): + - When reading a consensus file from disk, detect whether it was + written in text mode, and re-read it in text mode if so. Always + write consensus files in binary mode so that we can map them into + memory later. Previously, we had written in text mode, which + confused us when we tried to map the file on windows. Fixes bug + 28614; bugfix on 0.4.0.1-alpha. + + o Minor features (address selection): + - Treat the subnet 100.64.0.0/10 as public for some purposes; + private for others. This subnet is the RFC 6598 (Carrier Grade + NAT) IP range, and is deployed by many ISPs as an alternative to + RFC 1918 that does not break existing internal networks. Tor now + blocks SOCKS and control ports on these addresses and warns users + if client ports or ExtORPorts are listening on a RFC 6598 address. + Closes ticket 28525. Patch by Neel Chauhan. + + o Minor features (bandwidth authority): + - Make bandwidth authorities ignore relays that are reported in the + bandwidth file with the flag "vote=0". This change allows us to + report unmeasured relays for diagnostic reasons without including + their bandwidth in the bandwidth authorities' vote. Closes + ticket 29806. + - When a directory authority is using a bandwidth file to obtain the + bandwidth values that will be included in the next vote, serve + this bandwidth file at /tor/status-vote/next/bandwidth. Closes + ticket 21377. + + o Minor features (bootstrap reporting): + - When reporting bootstrap progress, stop distinguishing between + situations where only internal paths are available and situations + where external paths are available. Previously, Tor would often + erroneously report that it had only internal paths. Closes + ticket 27402. + + o Minor features (compilation): + - Compile correctly when OpenSSL is built with engine support + disabled, or with deprecated APIs disabled. Closes ticket 29026. + Patches from "Mangix". + + o Minor features (continuous integration): + - On Travis Rust builds, cleanup Rust registry and refrain from + caching the "target/" directory to speed up builds. Resolves + issue 29962. + - Log Python version during each Travis CI job. Resolves + issue 28551. + - In Travis, tell timelimit to use stem's backtrace signals, and + launch python directly from timelimit, so python receives the + signals from timelimit, rather than make. Closes ticket 30117. + + o Minor features (controller): + - Add a DROPOWNERSHIP command to undo the effects of TAKEOWNERSHIP. + Implements ticket 28843. + + o Minor features (developer tooling): + - Check that bugfix versions in changes files look like Tor versions + from the versions spec. Warn when bugfixes claim to be on a future + release. Closes ticket 27761. + - Provide a git pre-commit hook that disallows committing if we have + any failures in our code and changelog formatting checks. It is + now available in scripts/maint/pre-commit.git-hook. Implements + feature 28976. + - Provide a git hook script to prevent "fixup!" and "squash!" + commits from ending up in the master branch, as scripts/main/pre- + push.git-hook. Closes ticket 27993. + + o Minor features (diagnostic): + - Add more diagnostic log messages in an attempt to solve the issue + of NUL bytes appearing in a microdescriptor cache. Related to + ticket 28223. + + o Minor features (directory authority): + - When a directory authority is using a bandwidth file to obtain + bandwidth values, include the digest of that file in the vote. + Closes ticket 26698. + - Directory authorities support a new consensus algorithm, under + which the family lines in microdescriptors are encoded in a + canonical form. This change makes family lines more compressible + in transit, and on the client. Closes ticket 28266; implements + proposal 298. + + o Minor features (directory authority, relay): + - Authorities now vote on a "StaleDesc" flag to indicate that a + relay's descriptor is so old that the relay should upload again + soon. Relays treat this flag as a signal to upload a new + descriptor. This flag will eventually let us remove the + 'published' date from routerstatus entries, and make our consensus + diffs much smaller. Closes ticket 26770; implements proposal 293. + + o Minor features (dormant mode): + - Add a DormantCanceledByStartup option to tell Tor that it should + treat a startup event as cancelling any previous dormant state. + Integrators should use this option with caution: it should only be + used if Tor is being started because of something that the user + did, and not if Tor is being automatically started in the + background. Closes ticket 29357. + + o Minor features (fallback directory mirrors): + - Update the fallback whitelist based on operator opt-ins and opt- + outs. Closes ticket 24805, patch by Phoul. + + o Minor features (FreeBSD): + - On FreeBSD-based systems, warn relay operators if the + "net.inet.ip.random_id" sysctl (IP ID randomization) is disabled. + Closes ticket 28518. + + o Minor features (geoip): + - Update geoip and geoip6 to the April 2 2019 Maxmind GeoLite2 + Country database. Closes ticket 29992. + + o Minor features (HTTP standards compliance): + - Stop sending the header "Content-type: application/octet-stream" + along with transparently compressed documents: this confused + browsers. Closes ticket 28100. + + o Minor features (IPv6): + - We add an option ClientAutoIPv6ORPort, to make clients randomly + prefer a node's IPv4 or IPv6 ORPort. The random preference is set + every time a node is loaded from a new consensus or bridge config. + We expect that this option will enable clients to bootstrap more + quickly without having to determine whether they support IPv4, + IPv6, or both. Closes ticket 27490. Patch by Neel Chauhan. + - When using addrs_in_same_network_family(), avoid choosing circuit + paths that pass through the same IPv6 subnet more than once. + Previously, we only checked IPv4 subnets. Closes ticket 24393. + Patch by Neel Chauhan. + + o Minor features (log messages): + - Improve log message in v3 onion services that could print out + negative revision counters. Closes ticket 27707. Patch + by "ffmancera". + + o Minor features (memory usage): + - Save memory by storing microdescriptor family lists with a more + compact representation. Closes ticket 27359. + - Tor clients now use mmap() to read consensus files from disk, so + that they no longer need keep the full text of a consensus in + memory when parsing it or applying a diff. Closes ticket 27244. + + o Minor features (NSS, diagnostic): + - Try to log an error from NSS (if there is any) and a more useful + description of our situation if we are using NSS and a call to + SSL_ExportKeyingMaterial() fails. Diagnostic for ticket 29241. + + o Minor features (parsing): + - Directory authorities now validate that router descriptors and + ExtraInfo documents are in a valid subset of UTF-8, and reject + them if they are not. Closes ticket 27367. + + o Minor features (performance): + - Cache the results of summarize_protocol_flags(), so that we don't + have to parse the same protocol-versions string over and over. + This should save us a huge number of malloc calls on startup, and + may reduce memory fragmentation with some allocators. Closes + ticket 27225. + - Remove a needless memset() call from get_token_arguments, thereby + speeding up the tokenization of directory objects by about 20%. + Closes ticket 28852. + - Replace parse_short_policy() with a faster implementation, to + improve microdescriptor parsing time. Closes ticket 28853. + - Speed up directory parsing a little by avoiding use of the non- + inlined strcmp_len() function. Closes ticket 28856. + - Speed up microdescriptor parsing by about 30%, to help improve + startup time. Closes ticket 28839. + + o Minor features (pluggable transports): + - Add support for emitting STATUS updates to Tor's control port from + a pluggable transport process. Closes ticket 28846. + - Add support for logging to Tor's logging subsystem from a + pluggable transport process. Closes ticket 28180. + + o Minor features (process management): + - Add a new process API for handling child processes. This new API + allows Tor to have bi-directional communication with child + processes on both Unix and Windows. Closes ticket 28179. + - Use the subsystem manager to initialize and shut down the process + module. Closes ticket 28847. + + o Minor features (relay): + - When listing relay families, list them in canonical form including + the relay's own identity, and try to give a more useful set of + warnings. Part of ticket 28266 and proposal 298. + + o Minor features (required protocols): + - Before exiting because of a missing required protocol, Tor will + now check the publication time of the consensus, and not exit + unless the consensus is newer than the Tor program's own release + date. Previously, Tor would not check the consensus publication + time, and so might exit because of a missing protocol that might + no longer be required in a current consensus. Implements proposal + 297; closes ticket 27735. + + o Minor features (testing): + - Treat all unexpected ERR and BUG messages as test failures. Closes + ticket 28668. + - Allow a HeartbeatPeriod of less than 30 minutes in testing Tor + networks. Closes ticket 28840. Patch by Rob Jansen. + - Use the approx_time() function when setting the "Expires" header + in directory replies, to make them more testable. Needed for + ticket 30001. + + o Minor bugfixes (security): + - Fix a potential double free bug when reading huge bandwidth files. + The issue is not exploitable in the current Tor network because + the vulnerable code is only reached when directory authorities + read bandwidth files, but bandwidth files come from a trusted + source (usually the authorities themselves). Furthermore, the + issue is only exploitable in rare (non-POSIX) 32-bit architectures, + which are not used by any of the current authorities. Fixes bug + 30040; bugfix on 0.3.5.1-alpha. Bug found and fixed by + Tobias Stoeckmann. + - Verify in more places that we are not about to create a buffer + with more than INT_MAX bytes, to avoid possible OOB access in the + event of bugs. Fixes bug 30041; bugfix on 0.2.0.16. Found and + fixed by Tobias Stoeckmann. + + o Minor bugfix (continuous integration): + - Reset coverage state on disk after Travis CI has finished. This + should prevent future coverage merge errors from causing the test + suite for the "process" subsystem to fail. The process subsystem + was introduced in 0.4.0.1-alpha. Fixes bug 29036; bugfix + on 0.2.9.15. + - Terminate test-stem if it takes more than 9.5 minutes to run. + (Travis terminates the job after 10 minutes of no output.) + Diagnostic for 29437. Fixes bug 30011; bugfix on 0.3.5.4-alpha. + + o Minor bugfixes (build, compatibility, rust): + - Update Cargo.lock file to match the version made by the latest + version of Rust, so that "make distcheck" will pass again. Fixes + bug 29244; bugfix on 0.3.3.4-alpha. + + o Minor bugfixes (C correctness): + - Fix an unlikely memory leak in consensus_diff_apply(). Fixes bug + 29824; bugfix on 0.3.1.1-alpha. This is Coverity warning + CID 1444119. + + o Minor bugfixes (client, clock skew): + - Bootstrap successfully even when Tor's clock is behind the clocks + on the authorities. Fixes bug 28591; bugfix on 0.2.0.9-alpha. + - Select guards even if the consensus has expired, as long as the + consensus is still reasonably live. Fixes bug 24661; bugfix + on 0.3.0.1-alpha. + + o Minor bugfixes (compilation): + - Fix compilation warnings in test_circuitpadding.c. Fixes bug + 29169; bugfix on 0.4.0.1-alpha. + - Silence a compiler warning in test-memwipe.c on OpenBSD. Fixes bug + 29145; bugfix on 0.2.9.3-alpha. Patch from Kris Katterjohn. + - Compile correctly on OpenBSD; previously, we were missing some + headers required in order to detect it properly. Fixes bug 28938; + bugfix on 0.3.5.1-alpha. Patch from Kris Katterjohn. + + o Minor bugfixes (directory clients): + - Mark outdated dirservers when Tor only has a reasonably live + consensus. Fixes bug 28569; bugfix on 0.3.2.5-alpha. + + o Minor bugfixes (directory mirrors): + - Even when a directory mirror's clock is behind the clocks on the + authorities, we now allow the mirror to serve "future" + consensuses. Fixes bug 28654; bugfix on 0.3.0.1-alpha. + + o Minor bugfixes (DNS): + - Gracefully handle an empty or absent resolve.conf file by falling + back to using "localhost" as a DNS server (and hoping it works). + Previously, we would just stop running as an exit. Fixes bug + 21900; bugfix on 0.2.1.10-alpha. + + o Minor bugfixes (documentation): + - Describe the contents of the v3 onion service client authorization + files correctly: They hold public keys, not private keys. Fixes + bug 28979; bugfix on 0.3.5.1-alpha. Spotted by "Felixix". + + o Minor bugfixes (guards): + - In count_acceptable_nodes(), the minimum number is now one bridge + or guard node, and two non-guard nodes for a circuit. Previously, + we had added up the sum of all nodes with a descriptor, but that + could cause us to build failing circuits when we had either too + many bridges or not enough guard nodes. Fixes bug 25885; bugfix on + 0.3.6.1-alpha. Patch by Neel Chauhan. + + o Minor bugfixes (IPv6): + - Fix tor_ersatz_socketpair on IPv6-only systems. Previously, the + IPv6 socket was bound using an address family of AF_INET instead + of AF_INET6. Fixes bug 28995; bugfix on 0.3.5.1-alpha. Patch from + Kris Katterjohn. + + o Minor bugfixes (linux seccomp sandbox): + - Fix startup crash when experimental sandbox support is enabled. + Fixes bug 29150; bugfix on 0.4.0.1-alpha. Patch by Peter Gerber. + + o Minor bugfixes (logging): + - Correct a misleading error message when IPv4Only or IPv6Only is + used but the resolved address can not be interpreted as an address + of the specified IP version. Fixes bug 13221; bugfix on + 0.2.3.9-alpha. Patch from Kris Katterjohn. + - Log the correct port number for listening sockets when "auto" is + used to let Tor pick the port number. Previously, port 0 was + logged instead of the actual port number. Fixes bug 29144; bugfix + on 0.3.5.1-alpha. Patch from Kris Katterjohn. + - Stop logging a BUG() warning when Tor is waiting for exit + descriptors. Fixes bug 28656; bugfix on 0.3.5.1-alpha. + - Avoid logging that we are relaxing a circuit timeout when that + timeout is fixed. Fixes bug 28698; bugfix on 0.2.4.7-alpha. + - Log more information at "warning" level when unable to read a + private key; log more information at "info" level when unable to + read a public key. We had warnings here before, but they were lost + during our NSS work. Fixes bug 29042; bugfix on 0.3.5.1-alpha. + - Rework rep_hist_log_link_protocol_counts() to iterate through all + link protocol versions when logging incoming/outgoing connection + counts. Tor no longer skips version 5, and we won't have to + remember to update this function when new link protocol version is + developed. Fixes bug 28920; bugfix on 0.2.6.10. + + o Minor bugfixes (memory management): + - Refactor the shared random state's memory management so that it + actually takes ownership of the shared random value pointers. + Fixes bug 29706; bugfix on 0.2.9.1-alpha. + - Stop leaking parts of the shared random state in the shared-random + unit tests. Fixes bug 29599; bugfix on 0.2.9.1-alpha. + + o Minor bugfixes (misc): + - The amount of total available physical memory is now determined + using the sysctl identifier HW_PHYSMEM (rather than HW_USERMEM) + when it is defined and a 64-bit variant is not available. Fixes + bug 28981; bugfix on 0.2.5.4-alpha. Patch from Kris Katterjohn. + + o Minor bugfixes (networking): + - Introduce additional checks into tor_addr_parse() to reject + certain incorrect inputs that previously were not detected. Fixes + bug 23082; bugfix on 0.2.0.10-alpha. + + o Minor bugfixes (onion service v3, client): + - Stop logging a "BUG()" warning and stacktrace when we find a SOCKS + connection waiting for a descriptor that we actually have in the + cache. It turns out that this can actually happen, though it is + rare. Now, tor will recover and retry the descriptor. Fixes bug + 28669; bugfix on 0.3.2.4-alpha. + + o Minor bugfixes (onion services): + - Avoid crashing if ClientOnionAuthDir (incorrectly) contains more + than one private key for a hidden service. Fixes bug 29040; bugfix + on 0.3.5.1-alpha. + - In hs_cache_store_as_client() log an HSDesc we failed to parse at + "debug" level. Tor used to log it as a warning, which caused very + long log lines to appear for some users. Fixes bug 29135; bugfix + on 0.3.2.1-alpha. + - Stop logging "Tried to establish rendezvous on non-OR circuit..." + as a warning. Instead, log it as a protocol warning, because there + is nothing that relay operators can do to fix it. Fixes bug 29029; + bugfix on 0.2.5.7-rc. + + o Minor bugfixes (periodic events): + - Refrain from calling routerlist_remove_old_routers() from + check_descriptor_callback(). Instead, create a new hourly periodic + event. Fixes bug 27929; bugfix on 0.2.8.1-alpha. + + o Minor bugfixes (pluggable transports): + - Make sure that data is continously read from standard output and + standard error pipes of a pluggable transport child-process, to + avoid deadlocking when a pipe's buffer is full. Fixes bug 26360; + bugfix on 0.2.3.6-alpha. + + o Minor bugfixes (rust): + - Abort on panic in all build profiles, instead of potentially + unwinding into C code. Fixes bug 27199; bugfix on 0.3.3.1-alpha. + + o Minor bugfixes (scheduler): + - When re-adding channels to the pending list, check the correct + channel's sched_heap_idx. This issue has had no effect in mainline + Tor, but could have led to bugs down the road in improved versions + of our circuit scheduling code. Fixes bug 29508; bugfix + on 0.3.2.10. + + o Minor bugfixes (shellcheck): + - Look for scripts in their correct locations during "make + shellcheck". Previously we had looked in the wrong place during + out-of-tree builds. Fixes bug 30263; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (single onion services): + - Allow connections to single onion services to remain idle without + being disconnected. Previously, relays acting as rendezvous points + for single onion services were mistakenly closing idle rendezvous + circuits after 60 seconds, thinking that they were unused + directory-fetching circuits that had served their purpose. Fixes + bug 29665; bugfix on 0.2.1.26. + + o Minor bugfixes (stats): + - When ExtraInfoStatistics is 0, stop including PaddingStatistics in + relay and bridge extra-info documents. Fixes bug 29017; bugfix + on 0.3.1.1-alpha. + + o Minor bugfixes (testing): + - Backport the 0.3.4 src/test/test-network.sh to 0.2.9. We need a + recent test-network.sh to use new chutney features in CI. Fixes + bug 29703; bugfix on 0.2.9.1-alpha. + - Fix a test failure on Windows caused by an unexpected "BUG" + warning in our tests for tor_gmtime_r(-1). Fixes bug 29922; bugfix + on 0.2.9.3-alpha. + - Downgrade some LOG_ERR messages in the address/* tests to + warnings. The LOG_ERR messages were occurring when we had no + configured network. We were failing the unit tests, because we + backported 28668 to 0.3.5.8, but did not backport 29530. Fixes bug + 29530; bugfix on 0.3.5.8. + - Fix our gcov wrapper script to look for object files at the + correct locations. Fixes bug 29435; bugfix on 0.3.5.1-alpha. + - Decrease the false positive rate of stochastic probability + distribution tests. Fixes bug 29693; bugfix on 0.4.0.1-alpha. + - Fix intermittent failures on an adaptive padding test. Fixes one + case of bug 29122; bugfix on 0.4.0.1-alpha. + - Disable an unstable circuit-padding test that was failing + intermittently because of an ill-defined small histogram. Such + histograms will be allowed again after 29298 is implemented. Fixes + a second case of bug 29122; bugfix on 0.4.0.1-alpha. + - Detect and suppress "bug" warnings from the util/time test on + Windows. Fixes bug 29161; bugfix on 0.2.9.3-alpha. + - Do not log an error-level message if we fail to find an IPv6 + network interface from the unit tests. Fixes bug 29160; bugfix + on 0.2.7.3-rc. + - Instead of relying on hs_free_all() to clean up all onion service + objects in test_build_descriptors(), we now deallocate them one by + one. This lets Coverity know that we are not leaking memory there + and fixes CID 1442277. Fixes bug 28989; bugfix on 0.3.5.1-alpha. + - Check the time in the "Expires" header using approx_time(). Fixes + bug 30001; bugfix on 0.4.0.4-rc. + + o Minor bugfixes (TLS protocol): + - When classifying a client's selection of TLS ciphers, if the + client ciphers are not yet available, do not cache the result. + Previously, we had cached the unavailability of the cipher list + and never looked again, which in turn led us to assume that the + client only supported the ancient V1 link protocol. This, in turn, + was causing Stem integration tests to stall in some cases. Fixes + bug 30021; bugfix on 0.2.4.8-alpha. + + o Minor bugfixes (UI): + - Lower log level of unlink() errors during bootstrap. Fixes bug + 29930; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (usability): + - Stop saying "Your Guard ..." in pathbias_measure_{use,close}_rate(). + Some users took this phrasing to mean that the mentioned guard was + under their control or responsibility, which it is not. Fixes bug + 28895; bugfix on Tor 0.3.0.1-alpha. + + o Minor bugfixes (Windows, CI): + - Skip the Appveyor 32-bit Windows Server 2016 job, and 64-bit + Windows Server 2012 R2 job. The remaining 2 jobs still provide + coverage of 64/32-bit, and Windows Server 2016/2012 R2. Also set + fast_finish, so failed jobs terminate the build immediately. Fixes + bug 29601; bugfix on 0.3.5.4-alpha. + + o Code simplification and refactoring: + - Introduce a connection_dir_buf_add() helper function that detects + whether compression is in use, and adds a string accordingly. + Resolves issue 28816. + - Refactor handle_get_next_bandwidth() to use + connection_dir_buf_add(). Implements ticket 29897. + - Reimplement NETINFO cell parsing and generation to rely on + trunnel-generated wire format handling code. Closes ticket 27325. + - Remove unnecessary unsafe code from the Rust macro "cstr!". Closes + ticket 28077. + - Rework SOCKS wire format handling to rely on trunnel-generated + parsing/generation code. Resolves ticket 27620. + - Split out bootstrap progress reporting from control.c into a + separate file. Part of ticket 27402. + - The .may_include files that we use to describe our directory-by- + directory dependency structure now describe a noncircular + dependency graph over the directories that they cover. Our + checkIncludes.py tool now enforces this noncircularity. Closes + ticket 28362. + + o Documentation: + - Clarify that Tor performs stream isolation among *Port listeners + by default. Resolves issue 29121. + - In the manpage entry describing MapAddress torrc setting, use + example IP addresses from ranges specified for use in documentation + by RFC 5737. Resolves issue 28623. + - Mention that you cannot add a new onion service if Tor is already + running with Sandbox enabled. Closes ticket 28560. + - Improve ControlPort documentation. Mention that it accepts + address:port pairs, and can be used multiple times. Closes + ticket 28805. + - Document the exact output of "tor --version". Closes ticket 28889. + + o Removed features: + - Remove the old check-tor script. Resolves issue 29072. + - Stop responding to the 'GETINFO status/version/num-concurring' and + 'GETINFO status/version/num-versioning' control port commands, as + those were deprecated back in 0.2.0.30. Also stop listing them in + output of 'GETINFO info/names'. Resolves ticket 28757. + - The scripts used to generate and maintain the list of fallback + directories have been extracted into a new "fallback-scripts" + repository. Closes ticket 27914. + + o Testing: + - Run shellcheck for scripts in the in scripts/ directory. Closes + ticket 28058. + - Add unit tests for tokenize_string() and get_next_token() + functions. Resolves ticket 27625. + + o Code simplification and refactoring (onion service v3): + - Consolidate the authorized client descriptor cookie computation + code from client and service into one function. Closes + ticket 27549. + + o Code simplification and refactoring (shell scripts): + - Cleanup scan-build.sh to silence shellcheck warnings. Closes + ticket 28007. + - Fix issues that shellcheck found in chutney-git-bisect.sh. + Resolves ticket 28006. + - Fix issues that shellcheck found in updateRustDependencies.sh. + Resolves ticket 28012. + - Fix shellcheck warnings in cov-diff script. Resolves issue 28009. + - Fix shellcheck warnings in run_calltool.sh. Resolves ticket 28011. + - Fix shellcheck warnings in run_trunnel.sh. Resolves issue 28010. + - Fix shellcheck warnings in scripts/test/coverage. Resolves + issue 28008. + + +Changes in version 0.3.5.8 - 2019-02-21 + Tor 0.3.5.8 backports several fixes from later releases, including fixes + for an annoying SOCKS-parsing bug that affected users in earlier 0.3.5.x + releases. + + It also includes a fix for a medium-severity security bug affecting Tor + 0.3.2.1-alpha and later. All Tor instances running an affected release + should upgrade to 0.3.3.12, 0.3.4.11, 0.3.5.8, or 0.4.0.2-alpha. + + o Major bugfixes (cell scheduler, KIST, security): + - Make KIST consider the outbuf length when computing what it can + put in the outbuf. Previously, KIST acted as though the outbuf + were empty, which could lead to the outbuf becoming too full. It + is possible that an attacker could exploit this bug to cause a Tor + client or relay to run out of memory and crash. Fixes bug 29168; + bugfix on 0.3.2.1-alpha. This issue is also being tracked as + TROVE-2019-001 and CVE-2019-8955. + + o Major bugfixes (networking, backport from 0.4.0.2-alpha): + - Gracefully handle empty username/password fields in SOCKS5 + username/password auth messsage and allow SOCKS5 handshake to + continue. Previously, we had rejected these handshakes, breaking + certain applications. Fixes bug 29175; bugfix on 0.3.5.1-alpha. + + o Minor features (compilation, backport from 0.4.0.2-alpha): + - Compile correctly when OpenSSL is built with engine support + disabled, or with deprecated APIs disabled. Closes ticket 29026. + Patches from "Mangix". + + o Minor features (geoip): + - Update geoip and geoip6 to the February 5 2019 Maxmind GeoLite2 + Country database. Closes ticket 29478. + + o Minor features (testing, backport from 0.4.0.2-alpha): + - Treat all unexpected ERR and BUG messages as test failures. Closes + ticket 28668. + + o Minor bugfixes (onion service v3, client, backport from 0.4.0.1-alpha): + - Stop logging a "BUG()" warning and stacktrace when we find a SOCKS + connection waiting for a descriptor that we actually have in the + cache. It turns out that this can actually happen, though it is + rare. Now, tor will recover and retry the descriptor. Fixes bug + 28669; bugfix on 0.3.2.4-alpha. + + o Minor bugfixes (IPv6, backport from 0.4.0.1-alpha): + - Fix tor_ersatz_socketpair on IPv6-only systems. Previously, the + IPv6 socket was bound using an address family of AF_INET instead + of AF_INET6. Fixes bug 28995; bugfix on 0.3.5.1-alpha. Patch from + Kris Katterjohn. + + o Minor bugfixes (build, compatibility, rust, backport from 0.4.0.2-alpha): + - Update Cargo.lock file to match the version made by the latest + version of Rust, so that "make distcheck" will pass again. Fixes + bug 29244; bugfix on 0.3.3.4-alpha. + + o Minor bugfixes (client, clock skew, backport from 0.4.0.1-alpha): + - Select guards even if the consensus has expired, as long as the + consensus is still reasonably live. Fixes bug 24661; bugfix + on 0.3.0.1-alpha. + + o Minor bugfixes (compilation, backport from 0.4.0.1-alpha): + - Compile correctly on OpenBSD; previously, we were missing some + headers required in order to detect it properly. Fixes bug 28938; + bugfix on 0.3.5.1-alpha. Patch from Kris Katterjohn. + + o Minor bugfixes (documentation, backport from 0.4.0.2-alpha): + - Describe the contents of the v3 onion service client authorization + files correctly: They hold public keys, not private keys. Fixes + bug 28979; bugfix on 0.3.5.1-alpha. Spotted by "Felixix". + + o Minor bugfixes (logging, backport from 0.4.0.1-alpha): + - Rework rep_hist_log_link_protocol_counts() to iterate through all + link protocol versions when logging incoming/outgoing connection + counts. Tor no longer skips version 5, and we won't have to + remember to update this function when new link protocol version is + developed. Fixes bug 28920; bugfix on 0.2.6.10. + + o Minor bugfixes (logging, backport from 0.4.0.2-alpha): + - Log more information at "warning" level when unable to read a + private key; log more information at "info" level when unable to + read a public key. We had warnings here before, but they were lost + during our NSS work. Fixes bug 29042; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (misc, backport from 0.4.0.2-alpha): + - The amount of total available physical memory is now determined + using the sysctl identifier HW_PHYSMEM (rather than HW_USERMEM) + when it is defined and a 64-bit variant is not available. Fixes + bug 28981; bugfix on 0.2.5.4-alpha. Patch from Kris Katterjohn. + + o Minor bugfixes (onion services, backport from 0.4.0.2-alpha): + - Avoid crashing if ClientOnionAuthDir (incorrectly) contains more + than one private key for a hidden service. Fixes bug 29040; bugfix + on 0.3.5.1-alpha. + - In hs_cache_store_as_client() log an HSDesc we failed to parse at + "debug" level. Tor used to log it as a warning, which caused very + long log lines to appear for some users. Fixes bug 29135; bugfix + on 0.3.2.1-alpha. + - Stop logging "Tried to establish rendezvous on non-OR circuit..." + as a warning. Instead, log it as a protocol warning, because there + is nothing that relay operators can do to fix it. Fixes bug 29029; + bugfix on 0.2.5.7-rc. + + o Minor bugfixes (tests, directory clients, backport from 0.4.0.1-alpha): + - Mark outdated dirservers when Tor only has a reasonably live + consensus. Fixes bug 28569; bugfix on 0.3.2.5-alpha. + + o Minor bugfixes (tests, backport from 0.4.0.2-alpha): + - Detect and suppress "bug" warnings from the util/time test on + Windows. Fixes bug 29161; bugfix on 0.2.9.3-alpha. + - Do not log an error-level message if we fail to find an IPv6 + network interface from the unit tests. Fixes bug 29160; bugfix + on 0.2.7.3-rc. + + o Minor bugfixes (usability, backport from 0.4.0.1-alpha): + - Stop saying "Your Guard ..." in pathbias_measure_{use,close}_rate(). + Some users took this phrasing to mean that the mentioned guard was + under their control or responsibility, which it is not. Fixes bug + 28895; bugfix on Tor 0.3.0.1-alpha. + + +Changes in version 0.3.4.11 - 2019-02-21 + Tor 0.3.4.11 is the third stable release in its series. It includes + a fix for a medium-severity security bug affecting Tor 0.3.2.1-alpha and + later. All Tor instances running an affected release should upgrade to + 0.3.3.12, 0.3.4.11, 0.3.5.8, or 0.4.0.2-alpha. + + o Major bugfixes (cell scheduler, KIST, security): + - Make KIST consider the outbuf length when computing what it can + put in the outbuf. Previously, KIST acted as though the outbuf + were empty, which could lead to the outbuf becoming too full. It + is possible that an attacker could exploit this bug to cause a Tor + client or relay to run out of memory and crash. Fixes bug 29168; + bugfix on 0.3.2.1-alpha. This issue is also being tracked as + TROVE-2019-001 and CVE-2019-8955. + + o Minor features (geoip): + - Update geoip and geoip6 to the February 5 2019 Maxmind GeoLite2 + Country database. Closes ticket 29478. + + o Minor bugfixes (build, compatibility, rust, backport from 0.4.0.2-alpha): + - Update Cargo.lock file to match the version made by the latest + version of Rust, so that "make distcheck" will pass again. Fixes + bug 29244; bugfix on 0.3.3.4-alpha. + + o Minor bugfixes (onion services, backport from 0.4.0.2-alpha): + - Stop logging "Tried to establish rendezvous on non-OR circuit..." + as a warning. Instead, log it as a protocol warning, because there + is nothing that relay operators can do to fix it. Fixes bug 29029; + bugfix on 0.2.5.7-rc. + + +Changes in version 0.3.3.12 - 2019-02-21 + Tor 0.3.3.12 fixes a medium-severity security bug affecting Tor + 0.3.2.1-alpha and later. All Tor instances running an affected release + should upgrade to 0.3.3.12, 0.3.4.11, 0.3.5.8, or 0.4.0.2-alpha. + + This release marks the end of support for the Tor 0.3.3.x series. We + recommend that users switch to either the Tor 0.3.4 series (supported + until at least 10 June 2019), or the Tor 0.3.5 series, which will + receive long-term support until at least 1 Feb 2022. + + o Major bugfixes (cell scheduler, KIST, security): + - Make KIST consider the outbuf length when computing what it can + put in the outbuf. Previously, KIST acted as though the outbuf + were empty, which could lead to the outbuf becoming too full. It + is possible that an attacker could exploit this bug to cause a Tor + client or relay to run out of memory and crash. Fixes bug 29168; + bugfix on 0.3.2.1-alpha. This issue is also being tracked as + TROVE-2019-001 and CVE-2019-8955. + + o Minor features (geoip): + - Update geoip and geoip6 to the February 5 2019 Maxmind GeoLite2 + Country database. Closes ticket 29478. + + o Minor bugfixes (build, compatibility, rust, backport from 0.4.0.2-alpha): + - Update Cargo.lock file to match the version made by the latest + version of Rust, so that "make distcheck" will pass again. Fixes + bug 29244; bugfix on 0.3.3.4-alpha. + + o Minor bugfixes (onion services, backport from 0.4.0.2-alpha): + - Stop logging "Tried to establish rendezvous on non-OR circuit..." + as a warning. Instead, log it as a protocol warning, because there + is nothing that relay operators can do to fix it. Fixes bug 29029; + bugfix on 0.2.5.7-rc. + + Changes in version 0.3.3.11 - 2019-01-07 Tor 0.3.3.11 backports numerous fixes from later versions of Tor. numerous fixes, including an important fix for anyone using OpenSSL diff --git a/autogen.sh b/autogen.sh index 276dd4047c..63ef6d49ef 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,9 +1,9 @@ #!/bin/sh -if [ -x "`which autoreconf 2>/dev/null`" ] ; then +if command -v autoreconf; then opt="-i -f -W all,error" - for i in $@; do + for i in "$@"; do case "$i" in -v) opt="${opt} -v" @@ -11,6 +11,7 @@ if [ -x "`which autoreconf 2>/dev/null`" ] ; then esac done + # shellcheck disable=SC2086 exec autoreconf $opt fi diff --git a/changes/29241_diagnostic b/changes/29241_diagnostic deleted file mode 100644 index 1e38654957..0000000000 --- a/changes/29241_diagnostic +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (NSS, diagnostic): - - Try to log an error from NSS (if there is any) and a more useful - description of our situation if we are using NSS and a call to - SSL_ExportKeyingMaterial() fails. Diagnostic for ticket 29241. diff --git a/changes/bug13221 b/changes/bug13221 deleted file mode 100644 index 13935a1921..0000000000 --- a/changes/bug13221 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (logging): - - Correct a misleading error message when IPv4Only or IPv6Only - is used but the resolved address can not be interpreted as an - address of the specified IP version. Fixes bug 13221; bugfix - on 0.2.3.9-alpha. Patch from Kris Katterjohn. diff --git a/changes/bug22619 b/changes/bug22619 new file mode 100644 index 0000000000..9c71996f5b --- /dev/null +++ b/changes/bug22619 @@ -0,0 +1,3 @@ + o Minor bugfixes (circuit isolation): + - Fix a logic error that prevented the SessionGroup sub-option from + being accepted. Fixes bug 22619; bugfix on 0.2.7.2-alpha. diff --git a/changes/bug23507 b/changes/bug23507 new file mode 100644 index 0000000000..de18273fdb --- /dev/null +++ b/changes/bug23507 @@ -0,0 +1,5 @@ + o Minor bugfixes (v3 single onion services): + - Make v3 single onion services fall back to a 3-hop intro, when there + all intro points are unreachable via a 1-hop path. Previously, v3 + single onion services failed when all intro nodes were unreachable + via a 1-hop path. Fixes bug 23507; bugfix on 0.3.2.1-alpha. diff --git a/changes/bug23818_v2 b/changes/bug23818_v2 new file mode 100644 index 0000000000..0219a20f49 --- /dev/null +++ b/changes/bug23818_v2 @@ -0,0 +1,6 @@ + o Minor bugfixes (v2 single onion services): + - Always retry v2 single onion service intro and rend circuits with a + 3-hop path. Previously, v2 single onion services used a 3-hop path + when rend circuits were retried after a remote or delayed failure, + but a 1-hop path for immediate retries. Fixes bug 23818; + bugfix on 0.2.9.3-alpha. diff --git a/changes/bug23818_v3 b/changes/bug23818_v3 new file mode 100644 index 0000000000..c430144d81 --- /dev/null +++ b/changes/bug23818_v3 @@ -0,0 +1,6 @@ + o Minor bugfixes (v3 single onion services): + - Always retry v3 single onion service intro and rend circuits with a + 3-hop path. Previously, v3 single onion services used a 3-hop path + when rend circuits were retried after a remote or delayed failure, + but a 1-hop path for immediate retries. Fixes bug 23818; + bugfix on 0.3.2.1-alpha. diff --git a/changes/bug27199 b/changes/bug27199 deleted file mode 100644 index f9d2a422f9..0000000000 --- a/changes/bug27199 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (rust): - - Abort on panic in all build profiles, instead of potentially unwinding - into C code. Fixes bug 27199; bugfix on 0.3.3.1-alpha. diff --git a/changes/bug28525 b/changes/bug28525 deleted file mode 100644 index 988ffb2192..0000000000 --- a/changes/bug28525 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (address selection): - - Make Tor aware of the RFC 6598 (Carrier Grade NAT) IP range, which is the - subnet 100.64.0.0/10. This is deployed by many ISPs as an alternative to - RFC 1918 that does not break existing internal networks. This patch fixes - security issues caused by RFC 6518 by blocking control ports on these - addresses and warns users if client ports or ExtORPorts are listening on - a RFC 6598 address. Closes ticket 28525. Patch by Neel Chauhan. diff --git a/changes/bug28614_better_logging b/changes/bug28614_better_logging deleted file mode 100644 index 26d19c3c11..0000000000 --- a/changes/bug28614_better_logging +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (logging): - - On Windows, when errors cause us to reload a consensus from disk, tell - the user that we are retrying at log level "notice". Previously we only - logged this information at "info", which was confusing because the - errors themselves were logged at "warning". Improves previous fix for - 28614. Fixes bug 30004; bugfix on 0.4.0.2-alpha. diff --git a/changes/bug28656 b/changes/bug28656 deleted file mode 100644 index d3a13d196c..0000000000 --- a/changes/bug28656 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (logging): - - Stop logging a BUG() warning when tor is waiting for exit descriptors. - Fixes bug 28656; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug28698 b/changes/bug28698 deleted file mode 100644 index 716aa0c552..0000000000 --- a/changes/bug28698 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfix (logging): - - Avoid logging about relaxing circuits when their time is fixed. - Fixes bug 28698; bugfix on 0.2.4.7-alpha diff --git a/changes/bug28925 b/changes/bug28925 deleted file mode 100644 index a867443885..0000000000 --- a/changes/bug28925 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (bootstrap reporting): - - During bootstrap reporting, correctly distinguish pluggable - transports from plain proxies. Fixes bug 28925; bugfix on - 0.4.0.1-alpha. diff --git a/changes/bug28979 b/changes/bug28979 deleted file mode 100644 index 0625fd5d25..0000000000 --- a/changes/bug28979 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (documentation): - - Describe the contents of the v3 onion service client authorization - files correctly: They hold public keys, not private keys. Fixes bug - 28979; bugfix on 0.3.5.1-alpha. Spotted by "Felixix". diff --git a/changes/bug28981 b/changes/bug28981 deleted file mode 100644 index c0ea92ab35..0000000000 --- a/changes/bug28981 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (misc): - - The amount of total available physical memory is now determined - using the sysctl identifier HW_PHYSMEM (rather than HW_USERMEM) - when it is defined and a 64-bit variant is not available. Fixes - bug 28981; bugfix on 0.2.5.4-alpha. Patch from Kris Katterjohn. diff --git a/changes/bug29017 b/changes/bug29017 deleted file mode 100644 index 5c4a53c43f..0000000000 --- a/changes/bug29017 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (stats): - - When ExtraInfoStatistics is 0, stop including PaddingStatistics in - relay and bridge extra-info documents. Fixes bug 29017; - bugfix on 0.3.1.1-alpha. diff --git a/changes/bug29029 b/changes/bug29029 deleted file mode 100644 index e100a8c2ed..0000000000 --- a/changes/bug29029 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (logging, onion services): - - Stop logging "Tried to establish rendezvous on non-OR circuit..." as - a warning. Instead, log it as a protocol warning, because there is - nothing that relay operators can do to fix it. Fixes bug 29029; - bugfix on 0.2.5.7-rc. diff --git a/changes/bug29034 b/changes/bug29034 new file mode 100644 index 0000000000..e7aa9af00b --- /dev/null +++ b/changes/bug29034 @@ -0,0 +1,5 @@ + o Major bugfixes (Onion service reachability): + - Properly clean up the introduction point map when circuits change purpose + from onion service circuits to pathbias, measurement, or other circuit types. + This should fix some service-side instances of introduction point failure. + Fixes bug 29034; bugfix on 0.3.2.1-alpha. diff --git a/changes/bug29036 b/changes/bug29036 deleted file mode 100644 index 8b96c5c8fa..0000000000 --- a/changes/bug29036 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfix (continuous integration): - - Reset coverage state on disk after Travis CI has finished. This is being - done to prevent future gcda file merge errors which causes the test suite - for the process subsystem to fail. The process subsystem was introduced - in 0.4.0.1-alpha. Fixes bug 29036; bugfix on 0.2.9.15. diff --git a/changes/bug29040 b/changes/bug29040 deleted file mode 100644 index 0662aaa8a5..0000000000 --- a/changes/bug29040 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (onion services): - - Avoid crashing if ClientOnionAuthDir (incorrectly) contains - more than one private key for a hidden service. Fixes bug 29040; - bugfix on 0.3.5.1-alpha. diff --git a/changes/bug29042 b/changes/bug29042 deleted file mode 100644 index 8d76939cea..0000000000 --- a/changes/bug29042 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (logging): - - Log more information at "warning" level when unable to read a private - key; log more information ad "info" level when unable to read a public - key. We had warnings here before, but they were lost during our - NSS work. Fixes bug 29042; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug29122 b/changes/bug29122 deleted file mode 100644 index 020052ff8f..0000000000 --- a/changes/bug29122 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (unit tests): - - Fix intermittent failures on an adaptive padding unittest. Fixes bug - 29122; bugfix on 0.4.0.1-alpha diff --git a/changes/bug29135 b/changes/bug29135 deleted file mode 100644 index fd7b1ae80e..0000000000 --- a/changes/bug29135 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (onion services, logging): - - In hs_cache_store_as_client() log an HSDesc we failed to parse at Debug - loglevel. Tor used to log it at Warning loglevel, which caused - very long log lines to appear for some users. Fixes bug 29135; bugfix on - 0.3.2.1-alpha. diff --git a/changes/bug29144 b/changes/bug29144 deleted file mode 100644 index 5801224f14..0000000000 --- a/changes/bug29144 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (logging): - - Log the correct port number for listening sockets when "auto" is - used to let Tor pick the port number. Previously, port 0 was - logged instead of the actual port number. Fixes bug 29144; - bugfix on 0.3.5.1-alpha. Patch from Kris Katterjohn. diff --git a/changes/bug29145 b/changes/bug29145 deleted file mode 100644 index 40d3da4b91..0000000000 --- a/changes/bug29145 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (compilation, testing): - - Silence a compiler warning in test-memwipe.c on OpenBSD. Fixes - bug 29145; bugfix on 0.2.9.3-alpha. Patch from Kris Katterjohn. diff --git a/changes/bug29150 b/changes/bug29150 deleted file mode 100644 index 7696b90378..0000000000 --- a/changes/bug29150 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (linux seccomp sandbox): - - Fix startup crash when experimental sandbox support is enabled. - Fixes bug 29150; bugfix on 0.4.0.1-alpha. Patch by Peter Gerber. diff --git a/changes/bug29161 b/changes/bug29161 deleted file mode 100644 index 39a638acf6..0000000000 --- a/changes/bug29161 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (tests): - - Detect and suppress "bug" warnings from the util/time test on Windows. - Fixes bug 29161; bugfix on 0.2.9.3-alpha. diff --git a/changes/bug29169 b/changes/bug29169 deleted file mode 100644 index 41d4b76ef5..0000000000 --- a/changes/bug29169 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (compilation): - - Fix compilation warnings in test_circuitpadding.c. Fixes bug 29169; - bugfix on 0.4.0.1-alpha. diff --git a/changes/bug29175_035 b/changes/bug29175_035 deleted file mode 100644 index 134c1d9529..0000000000 --- a/changes/bug29175_035 +++ /dev/null @@ -1,4 +0,0 @@ - o Major bugfixes (networking): - - Gracefully handle empty username/password fields in SOCKS5 - username/password auth messsage and allow SOCKS5 handshake to - continue. Fixes bug 29175; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug29204 b/changes/bug29204 deleted file mode 100644 index ec2cf67b2f..0000000000 --- a/changes/bug29204 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (circuitpadding): - - Inspect circuit-level cell queue before sending padding, to avoid - sending padding while too much data is queued. Fixes bug 29204; - bugfix on 0.4.0.1-alpha. diff --git a/changes/bug29241 b/changes/bug29241 deleted file mode 100644 index 7f25e154d1..0000000000 --- a/changes/bug29241 +++ /dev/null @@ -1,6 +0,0 @@ - o Major bugfixes (NSS, relay): - - When running with NSS, disable TLS 1.2 ciphersuites that use SHA384 - for their PRF. Due to an NSS bug, the TLS key exporters for these - ciphersuites don't work -- which caused relays to fail to handshake - with one another when these ciphersuites were enabled. - Fixes bug 29241; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug29244 b/changes/bug29244 deleted file mode 100644 index 6206a95463..0000000000 --- a/changes/bug29244 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (build, compatibility): - - Update Cargo.lock file to match the version made by the latest - version of Rust, so that "make distcheck" will pass again. - Fixes bug 29244; bugfix on 0.3.3.4-alpha. diff --git a/changes/bug29298 b/changes/bug29298 deleted file mode 100644 index df12db77d7..0000000000 --- a/changes/bug29298 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (testing, circuit padding): - - Disabled unstable circuit padding unittest that was causing intermittent - test failures because of ill-defined small histogram. Such histograms - will be allowed again after 29298 is implemented. Fixes second case of - bug 29122; bugfix on 0.4.0.1-alpha. \ No newline at end of file diff --git a/changes/bug29500 b/changes/bug29500 deleted file mode 100644 index 16550935b2..0000000000 --- a/changes/bug29500 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (circuitpadding testing): - - Minor tweaks to avoid very rare test failures related to timers and - monotime. Fixes bug 29500; bugfix on 0.4.0.1-alpha diff --git a/changes/bug29508 b/changes/bug29508 deleted file mode 100644 index ee728bbbc9..0000000000 --- a/changes/bug29508 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (scheduler): - - When readding channels to the pending list, check the correct channel's - sched_heap_idx. Fixes bug 29508; bugfix on 0.3.2.10 diff --git a/changes/bug29527 b/changes/bug29527 deleted file mode 100644 index 6f36a9e1a0..0000000000 --- a/changes/bug29527 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (circuit padding): - - Stop warning about undefined behavior in the probability distribution - tests. Float division by zero may technically be undefined behaviour in - C, but it's well-defined in IEEE 754. Partial backport of 29298. - Closes ticket 29527; bugfix on 0.4.0.1-alpha. diff --git a/changes/bug29530_035 b/changes/bug29530_035 deleted file mode 100644 index 6dfcd51e7b..0000000000 --- a/changes/bug29530_035 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (testing): - - Downgrade some LOG_ERR messages in the address/* tests to warnings. - The LOG_ERR messages were occurring when we had no configured network. - We were failing the unit tests, because we backported 28668 to 0.3.5.8, - but did not backport 29530. Fixes bug 29530; bugfix on 0.3.5.8. diff --git a/changes/bug29562 b/changes/bug29562 deleted file mode 100644 index 0621cd09a0..0000000000 --- a/changes/bug29562 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (pluggable transports): - - Fix an assertion failure crash bug when a pluggable transport process is - terminated during the bootstrap phase. Fixes bug 29562; bugfix on - 0.4.0.1-alpha. diff --git a/changes/bug29599 b/changes/bug29599 deleted file mode 100644 index 14e2f5d077..0000000000 --- a/changes/bug29599 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (memory management, testing): - - Stop leaking parts of the shared random state in the shared-random unit - tests. Fixes bug 29599; bugfix on 0.2.9.1-alpha. diff --git a/changes/bug29601 b/changes/bug29601 deleted file mode 100644 index c4ba5fbc8b..0000000000 --- a/changes/bug29601 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (Windows, CI): - - Skip the Appveyor 32-bit Windows Server 2016 job, and 64-bit Windows - Server 2012 R2 job. The remaining 2 jobs still provide coverage of - 64/32-bit, and Windows Server 2016/2012 R2. Also set fast_finish, so - failed jobs terminate the build immediately. - Fixes bug 29601; bugfix on 0.3.5.4-alpha. diff --git a/changes/bug29665 b/changes/bug29665 deleted file mode 100644 index d89046faf5..0000000000 --- a/changes/bug29665 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor bugfixes (single onion services): - - Allow connections to single onion services to remain idle without - being disconnected. Relays acting as rendezvous points for - single onion services were mistakenly closing idle established - rendezvous circuits after 60 seconds, thinking that they are unused - directory-fetching circuits that had served their purpose. Fixes - bug 29665; bugfix on 0.2.1.26. diff --git a/changes/bug29693 b/changes/bug29693 deleted file mode 100644 index 33ce051c40..0000000000 --- a/changes/bug29693 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (unit tests): - - Decrease the false positive rate of stochastic probability distribution - tests. Fixes bug 29693; bugfix on 0.4.0.1-alpha. \ No newline at end of file diff --git a/changes/bug29703 b/changes/bug29703 deleted file mode 100644 index 0e17ee45e6..0000000000 --- a/changes/bug29703 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (testing): - - Backport the 0.3.4 src/test/test-network.sh to 0.2.9. - We need a recent test-network.sh to use new chutney features in CI. - Fixes bug 29703; bugfix on 0.2.9.1-alpha. diff --git a/changes/bug29706_minimal b/changes/bug29706_minimal deleted file mode 100644 index 9d4a43326c..0000000000 --- a/changes/bug29706_minimal +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (memory management, testing): - - Stop leaking parts of the shared random state in the shared-random unit - tests. The previous fix in 29599 was incomplete. - Fixes bug 29706; bugfix on 0.2.9.1-alpha. diff --git a/changes/bug29706_refactor b/changes/bug29706_refactor deleted file mode 100644 index ba1d0c7edd..0000000000 --- a/changes/bug29706_refactor +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (memory management): - - Refactor the shared random state's memory management so that it actually - takes ownership of the shared random value pointers. - Fixes bug 29706; bugfix on 0.2.9.1-alpha. diff --git a/changes/bug29874 b/changes/bug29874 deleted file mode 100644 index 8534753b51..0000000000 --- a/changes/bug29874 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (pluggable transports): - - Restore old behaviour when it comes to discovering the path of a given - Pluggable Transport exe-file. Fixes bug 29874; bugfix on 0.4.0.1-alpha. - diff --git a/changes/bug29922 b/changes/bug29922 deleted file mode 100644 index dacb951097..0000000000 --- a/changes/bug29922 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (testing, windows): - - Fix a test failure caused by an unexpected bug warning in - our test for tor_gmtime_r(-1). Fixes bug 29922; - bugfix on 0.2.9.3-alpha. diff --git a/changes/bug29930 b/changes/bug29930 deleted file mode 100644 index a99b11430b..0000000000 --- a/changes/bug29930 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (UI): - - Lower log level of unlink() errors during bootstrap. Fixes bug 29930; - bugfix on 0.4.0.1-alpha. - diff --git a/changes/bug29959-040 b/changes/bug29959-040 deleted file mode 100644 index 3740e0169a..0000000000 --- a/changes/bug29959-040 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (directory authorities): - - Actually include the bandwidth-file-digest line in directory authority - votes. Fixes bug 29959; bugfix on 0.4.0.2-alpha. diff --git a/changes/bug30001 b/changes/bug30001 deleted file mode 100644 index 52e58872ef..0000000000 --- a/changes/bug30001 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (testing): - - Use the approx_time() function when setting the "Expires" header - in directory replies, to make them more testable. Needed for - ticket 30001. - o Minor bug fixes (testing): - - Check the time in the "Expires" header with approx_time(). - Fixes bug 30001; bugfix on 0.4.0.4-rc. diff --git a/changes/bug30011 b/changes/bug30011 deleted file mode 100644 index 4c9069e291..0000000000 --- a/changes/bug30011 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (CI): - - Terminate test-stem if it takes more than 9.5 minutes to run. - (Travis terminates the job after 10 minutes of no output.) - Diagnostic for 29437. Fixes bug 30011; bugfix on 0.3.5.4-alpha. diff --git a/changes/bug30021 b/changes/bug30021 deleted file mode 100644 index 2a887f3cf2..0000000000 --- a/changes/bug30021 +++ /dev/null @@ -1,8 +0,0 @@ - o Minor bugfixes (TLS protocol, integration tests): - - When classifying a client's selection of TLS ciphers, if the client - ciphers are not yet available, do not cache the result. Previously, - we had cached the unavailability of the cipher list and never looked - again, which in turn led us to assume that the client only supported - the ancient V1 link protocol. This, in turn, was causing Stem - integration tests to stall in some cases. - Fixes bug 30021; bugfix on 0.2.4.8-alpha. diff --git a/changes/bug30040 b/changes/bug30040 deleted file mode 100644 index 7d80528a10..0000000000 --- a/changes/bug30040 +++ /dev/null @@ -1,9 +0,0 @@ - o Minor bugfixes (security): - - Fix a potential double free bug when reading huge bandwidth files. The - issue is not exploitable in the current Tor network because the - vulnerable code is only reached when directory authorities read bandwidth - files, but bandwidth files come from a trusted source (usually the - authorities themselves). Furthermore, the issue is only exploitable in - rare (non-POSIX) 32-bit architectures which are not used by any of the - current authorities. Fixes bug 30040; bugfix on 0.3.5.1-alpha. Bug found - and fixed by Tobias Stoeckmann. diff --git a/changes/bug30041 b/changes/bug30041 deleted file mode 100644 index 801c8f67ac..0000000000 --- a/changes/bug30041 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (hardening): - - Verify in more places that we are not about to create a buffer - with more than INT_MAX bytes, to avoid possible OOB access in the event - of bugs. Fixes bug 30041; bugfix on 0.2.0.16. Found and fixed by - Tobias Stoeckmann. diff --git a/changes/bug30189 b/changes/bug30189 deleted file mode 100644 index f8c932a5f9..0000000000 --- a/changes/bug30189 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (compilation, unusual configuration): - - Avoid failures when building with ALL_BUGS_ARE_FAILED due to - missing declarations of abort(), and prevent other such failures - in the future. Fixes bug 30189; bugfix on 0.3.4.1-alpha. diff --git a/changes/bug30263 b/changes/bug30263 deleted file mode 100644 index ba81c1b8a1..0000000000 --- a/changes/bug30263 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (shellcheck): - - Stop looking for scripts in the build directory during - "make shellcheck". Fixes bug 30263; bugfix on 0.4.0.1-alpha. diff --git a/changes/bug30316 b/changes/bug30316 deleted file mode 100644 index 3e396318ad..0000000000 --- a/changes/bug30316 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (directory authority): - - Move the "bandwidth-file-headers" line in directory authority votes - so that it conforms to dir-spec.txt. Fixes bug 30316; bugfix on - 0.3.5.1-alpha. diff --git a/changes/bug30452 b/changes/bug30452 deleted file mode 100644 index 2bb401d87d..0000000000 --- a/changes/bug30452 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (compile-time modules): - - Add a --list-modules command to print a list of which compile-time - modules are enabled. Closes ticket 30452. diff --git a/changes/bug30475 b/changes/bug30475 deleted file mode 100644 index 839597b885..0000000000 --- a/changes/bug30475 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (): - - Avoid a GCC 9.1.1 warning (and possible crash depending on libc - implemenation) when failing to load a hidden service client authorization - file. Fixes bug 30475; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug30781 b/changes/bug30781 new file mode 100644 index 0000000000..7c7adf470e --- /dev/null +++ b/changes/bug30781 @@ -0,0 +1,4 @@ + o Minor bugfixes (directory authorities): + - Stop crashing after parsing an unknown descriptor purpose annotation. + We think this bug can only be triggered by modifying a local file. + Fixes bug 30781; bugfix on 0.2.0.8-alpha. diff --git a/changes/bug30894 b/changes/bug30894 new file mode 100644 index 0000000000..64c14c4e6d --- /dev/null +++ b/changes/bug30894 @@ -0,0 +1,4 @@ + o Minor bugfixes (memory leaks): + - Fix a trivial memory leak when parsing an invalid value + from a download schedule in the configuration. Fixes bug + 30894; bugfix on 0.3.4.1-alpha. diff --git a/changes/bug30942 b/changes/bug30942 new file mode 100644 index 0000000000..bd6b2ff581 --- /dev/null +++ b/changes/bug30942 @@ -0,0 +1,4 @@ + o Minor bugfixes (circuit padding): + - Ignore non-padding cells on padding circuits. This addresses various + warning messages from subsystems that were not expecting padding + circuits. Fixes bug 30942; bugfix on 0.4.1.1-alpha. \ No newline at end of file diff --git a/changes/bug30956 b/changes/bug30956 new file mode 100644 index 0000000000..8f52a81de3 --- /dev/null +++ b/changes/bug30956 @@ -0,0 +1,4 @@ + o Minor bugfixes (pluggable transports): + - Always publish bridge pluggable transport information in the extra info + descriptor, even if ExtraInfoStatistics is 0. This information is + needed by BridgeDB. Fixes bug 30956; bugfix on 0.4.1.1-alpha. diff --git a/changes/bug31003 b/changes/bug31003 new file mode 100644 index 0000000000..6c75163380 --- /dev/null +++ b/changes/bug31003 @@ -0,0 +1,4 @@ + o Minor bugfixes (crash on exit): + - Avoid a set of possible code paths that could use try to use freed memory + in routerlist_free() while Tor was exiting. Fixes bug 31003; bugfix on + 0.1.2.2-alpha. diff --git a/changes/bug31024 b/changes/bug31024 new file mode 100644 index 0000000000..888fb2a26b --- /dev/null +++ b/changes/bug31024 @@ -0,0 +1,4 @@ + o Minor bugfixes (circuitpadding): + - Add two NULL checks in unreachable places to silence Coverity (CID 144729 + and 1447291) and better future proof ourselves. Fixes bug 31024; bugfix + on 0.4.1.1-alpha. \ No newline at end of file diff --git a/changes/bug31027 b/changes/bug31027 new file mode 100644 index 0000000000..dd3ce20b60 --- /dev/null +++ b/changes/bug31027 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Remove some dead code from circpad_machine_remove_token() to fix some + Coverity warnings (CID 1447298). Fixes bug 31027; bugfix on 0.4.1.1-alpha. \ No newline at end of file diff --git a/changes/bug31080_041 b/changes/bug31080_041 new file mode 100644 index 0000000000..1fe9ec508d --- /dev/null +++ b/changes/bug31080_041 @@ -0,0 +1,4 @@ + o Minor bugfixes (logging): + - Fix a conflict between the flag used for messaging-domain + log messages, and the LD_NO_MOCK testing flag. Fixes bug 31080; + bugfix on 0.4.1.1-alpha. diff --git a/changes/bug31343 b/changes/bug31343 new file mode 100644 index 0000000000..17a8057ead --- /dev/null +++ b/changes/bug31343 @@ -0,0 +1,9 @@ + o Minor bugfixes (compilation): + - Avoid using labs() on time_t, which can cause compilation warnings + on 64-bit Windows builds. Fixes bug 31343; bugfix on 0.2.4.4-alpha. + + o Minor bugfixes (clock skew detection): + - Don't believe clock skew results from NETINFO cells that appear to + arrive before the VERSIONS cells they are responding to were sent. + Previously, we would accept them up to 3 minutes "in the past". + Fixes bug 31343; bugfix on 0.2.4.4-alpha. diff --git a/changes/bug31356_and_logs b/changes/bug31356_and_logs new file mode 100644 index 0000000000..fb5307cb69 --- /dev/null +++ b/changes/bug31356_and_logs @@ -0,0 +1,11 @@ + o Minor bugfixes (circuit padding negotiation): + - Bump circuit padding protover to explicitly signify that the hs setup + machine support is finalized in 0.4.1.x-stable. This also means that + 0.4.1.x-alpha clients will not negotiate padding with 0.4.1.x-stable + relays, and 0.4.1.x-stable clients will not negotiate padding with + 0.4.1.x-alpha relays (or 0.4.0.x relays). Fixes bug 31356; + bugfix on 0.4.1.1-alpha. + o Minor features (circuit padding logging): + - Demote noisy client-side warn log to a protocol warning. Add additional + log messages and circuit id fields to help with fixing bug 30992 and any + other future issues. diff --git a/changes/bug31463 b/changes/bug31463 new file mode 100644 index 0000000000..d85c0887c3 --- /dev/null +++ b/changes/bug31463 @@ -0,0 +1,3 @@ + o Minor bugfixes (rust): + - Correctly exclude a redundant rust build job in Travis. Fixes bug 31463; + bugfix on 0.3.5.4-alpha. diff --git a/changes/chutney_ci b/changes/chutney_ci new file mode 100644 index 0000000000..b17d587329 --- /dev/null +++ b/changes/chutney_ci @@ -0,0 +1,3 @@ + o Minor features (continuous integration): + - Our Travis configuration now uses Chutney to run some network + integration tests automatically. Closes ticket 29280. diff --git a/changes/cid1444119 b/changes/cid1444119 deleted file mode 100644 index bb6854e66f..0000000000 --- a/changes/cid1444119 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (C correctness): - - Fix an unlikely memory leak in consensus_diff_apply(). Fixes bug 29824; - bugfix on 0.3.1.1-alpha. This is Coverity warning CID 1444119. diff --git a/changes/diagnostic_28223_redux b/changes/diagnostic_28223_redux deleted file mode 100644 index 0d7499832e..0000000000 --- a/changes/diagnostic_28223_redux +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (diagnostic): - - Add more diagnostic log messages in an attempt to solve - the issue of NUL bytes appearing in a microdescriptor cache. - Related to ticket 28223. diff --git a/changes/doc28623 b/changes/doc28623 deleted file mode 100644 index 3c3313abdd..0000000000 --- a/changes/doc28623 +++ /dev/null @@ -1,3 +0,0 @@ - o Documentation: - - In manpage entry describing MapAddress torrc setting, use example - IP addresses from ranges specified by RFC 5737. Resolves issue 28623. diff --git a/changes/doc29121 b/changes/doc29121 deleted file mode 100644 index dd31cc9c70..0000000000 --- a/changes/doc29121 +++ /dev/null @@ -1,3 +0,0 @@ - o Documentation: - - Clarify that Tor performs stream isolation between *Port listeners by - default. Resolves issue 29121. diff --git a/changes/doc30630 b/changes/doc30630 new file mode 100644 index 0000000000..0fbd8d4dd4 --- /dev/null +++ b/changes/doc30630 @@ -0,0 +1,3 @@ + o Documentation: + - Mention URLs for Travis/Appveyor/Jenkins in ReleasingTor.md. Closes + ticket 30630. diff --git a/changes/feature28976 b/changes/feature28976 deleted file mode 100644 index c7ebc207f7..0000000000 --- a/changes/feature28976 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (developer tooling): - - Provide a git pre-commit hook that disallows commiting if we have any - failures in our code and changelog formatting checks. It is now available - in scripts/maint/pre-commit.git-hook. Implements feature 28976. diff --git a/changes/geoip-2019-02-05 b/changes/geoip-2019-02-05 deleted file mode 100644 index 78ee6d4242..0000000000 --- a/changes/geoip-2019-02-05 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (geoip): - - Update geoip and geoip6 to the February 5 2019 Maxmind GeoLite2 - Country database. Closes ticket 29478. - diff --git a/changes/geoip-2019-03-04 b/changes/geoip-2019-03-04 deleted file mode 100644 index c8ce5dad5d..0000000000 --- a/changes/geoip-2019-03-04 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (geoip): - - Update geoip and geoip6 to the March 4 2019 Maxmind GeoLite2 - Country database. Closes ticket 29666. - diff --git a/changes/geoip-2019-04-02 b/changes/geoip-2019-04-02 deleted file mode 100644 index 7302d939f6..0000000000 --- a/changes/geoip-2019-04-02 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (geoip): - - Update geoip and geoip6 to the April 2 2019 Maxmind GeoLite2 - Country database. Closes ticket 29992. - diff --git a/changes/geoip-2019-05-13 b/changes/geoip-2019-05-13 deleted file mode 100644 index 0a2fa18971..0000000000 --- a/changes/geoip-2019-05-13 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (geoip): - - Update geoip and geoip6 to the May 13 2019 Maxmind GeoLite2 - Country database. Closes ticket 30522. - diff --git a/changes/ticket21377 b/changes/ticket21377 deleted file mode 100644 index 2bf5149a0a..0000000000 --- a/changes/ticket21377 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (dircache): - - When a directory authority is using a bandwidth file to obtain the - bandwidth values that will be included in the next vote, serve this - bandwidth file at /tor/status-vote/next/bandwidth. Closes ticket 21377. \ No newline at end of file diff --git a/changes/ticket26698 b/changes/ticket26698 deleted file mode 100644 index 6b029a1b73..0000000000 --- a/changes/ticket26698 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (directory authority): - - When a directory authority is using a bandwidth file to obtain the - bandwidth values, include the digest of the file in the vote. - Closes ticket 26698. diff --git a/changes/ticket27761 b/changes/ticket27761 deleted file mode 100644 index 35106ee9c6..0000000000 --- a/changes/ticket27761 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (changelogs): - - Check that bugfix versions in changes files look like Tor versions - from the versions spec. Warn when bugfixes claim to be on a future - release. Closes ticket 27761. diff --git a/changes/ticket28614 b/changes/ticket28614 deleted file mode 100644 index 3c93313726..0000000000 --- a/changes/ticket28614 +++ /dev/null @@ -1,8 +0,0 @@ - o Major bugfixes (windows, startup): - - When writing a consensus file to disk, always write in - "binary" mode so that we can safely map it into memory later. - Fixes part of bug 28614; bugfix on 0.4.0.1-alpha. - - When reading a consensus file from disk, detect whether it - was written in text mode, and re-read it in text mode if so. - Fixes part of bug 28614; bugfix on 0.4.0.1-alpha. - diff --git a/changes/ticket28668 b/changes/ticket28668 deleted file mode 100644 index 6386e0051f..0000000000 --- a/changes/ticket28668 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (testing): - - Treat all unexpected ERR and BUG messages as test failures. - Closes ticket 28668. diff --git a/changes/ticket28816 b/changes/ticket28816 deleted file mode 100644 index 02878ccfdc..0000000000 --- a/changes/ticket28816 +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring: - - Introduce a connection_dir_buf_add() helper function that checks for - compress_state of dir_connection_t and automatically writes a string to - directory connection with or without compression. Resolves issue 28816. diff --git a/changes/ticket29026 b/changes/ticket29026 deleted file mode 100644 index 1db873dfcf..0000000000 --- a/changes/ticket29026 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (compilation): - - Compile correctly when OpenSSL is built with engine support - disabled, or with deprecated APIs disabled. Closes ticket - 29026. Patches from "Mangix". diff --git a/changes/ticket29072 b/changes/ticket29072 deleted file mode 100644 index 3526330f30..0000000000 --- a/changes/ticket29072 +++ /dev/null @@ -1,2 +0,0 @@ - o Removed features: - - Remove check-tor script from repository. Resolves issue 29072. diff --git a/changes/ticket29160 b/changes/ticket29160 deleted file mode 100644 index 8e11183064..0000000000 --- a/changes/ticket29160 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (tests): - - Do not log an error-level message if we fail to find an IPv6 - network interface from the unit tests. Fixes bug 29160; bugfix on - 0.2.7.3-rc. diff --git a/changes/ticket29168 b/changes/ticket29168 deleted file mode 100644 index 65c5232f65..0000000000 --- a/changes/ticket29168 +++ /dev/null @@ -1,5 +0,0 @@ - o Major bugfixes (cell scheduler, KIST): - - Make KIST to always take into account the outbuf length when computing - what we can actually put in the outbuf. This could lead to the outbuf - being filled up and thus a possible memory DoS vector. TROVE-2019-001. - Fixes bug 29168; bugfix on 0.3.2.1-alpha. diff --git a/changes/ticket29357 b/changes/ticket29357 deleted file mode 100644 index 3aab930cd4..0000000000 --- a/changes/ticket29357 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (dormant mode): - - Add a DormantCanceledByStartup option to tell Tor that it should - treat a startup event as cancelling any previous dormant state. - Integrators should use this option with caution: it should - only be used if Tor is being started because of something that the - user did, and not if Tor is being automatically started in the - background. Closes ticket 29357. diff --git a/changes/ticket29435 b/changes/ticket29435 deleted file mode 100644 index d48ae98e4b..0000000000 --- a/changes/ticket29435 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (testing): - - Fix our gcov wrapper script to look for object files at the - correct locations. Fixes bug 29435; bugfix on 0.3.5.1-alpha. diff --git a/changes/ticket29631 b/changes/ticket29631 deleted file mode 100644 index 9fc194ba96..0000000000 --- a/changes/ticket29631 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (Rust, protover): - - The Rust implementation of protover was missing the "Padding" value in - the translate function from C to Rust. Fixes bug 29631; bugfix on - 0.4.0.1-alpha. diff --git a/changes/ticket29702 b/changes/ticket29702 deleted file mode 100644 index e1cc1f867b..0000000000 --- a/changes/ticket29702 +++ /dev/null @@ -1,4 +0,0 @@ - o Testing: - - Specify torrc paths (with empty files) when launching tor in - integration tests; refrain from reading user and system torrcs. - Resolves issue 29702. diff --git a/changes/ticket29806 b/changes/ticket29806 deleted file mode 100644 index 6afefd4c04..0000000000 --- a/changes/ticket29806 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (bandwidth authority): - - Make bandwidth authorities to ignore relays that are reported in the - bandwidth file with the key-value "vote=0". - This change allows to report the relays that were not measured due - some failure and diagnose the reasons without the bandwidth being included in the - bandwidth authorities vote. - Closes ticket 29806. diff --git a/changes/ticket29897 b/changes/ticket29897 deleted file mode 100644 index 232a79fbce..0000000000 --- a/changes/ticket29897 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Refactor handle_get_next_bandwidth() to use connection_dir_buf_add(). - Implements ticket 29897. diff --git a/changes/ticket29962 b/changes/ticket29962 deleted file mode 100644 index e36cc0cf9a..0000000000 --- a/changes/ticket29962 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (continuous integration): - - On Travis Rust builds, cleanup Rust registry and refrain from caching - target/ directory to speed up builds. Resolves issue 29962. diff --git a/changes/ticket30117 b/changes/ticket30117 deleted file mode 100644 index 5b6e6dabf7..0000000000 --- a/changes/ticket30117 +++ /dev/null @@ -1,4 +0,0 @@ - o Testing (continuous integration): - - In Travis, tell timelimit to use stem's backtrace signals. And launch - python directly from timelimit, so python receives the signals from - timelimit, rather than make. Closes ticket 30117. diff --git a/changes/ticket30213 b/changes/ticket30213 deleted file mode 100644 index acb7614807..0000000000 --- a/changes/ticket30213 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (continuous integration): - - Remove sudo configuration lines from .travis.yml as they are no longer - needed with current Travis build environment. Resolves issue 30213. diff --git a/changes/ticket30234 b/changes/ticket30234 deleted file mode 100644 index 5a0076bad2..0000000000 --- a/changes/ticket30234 +++ /dev/null @@ -1,2 +0,0 @@ - o Testing (continuous integration): - - In Travis, show stem's tor log after failure. Closes ticket 30234. diff --git a/changes/ticket30454 b/changes/ticket30454 deleted file mode 100644 index 77c45d0feb..0000000000 --- a/changes/ticket30454 +++ /dev/null @@ -1,10 +0,0 @@ - o Major bugfixes (hidden service v3): - - An intro point could try to send an INTRODUCE_ACK with a status code - that it wasn't able to encode leading to a hard assert() of the relay. - Fortunately, that specific code path can not be reached thus this issue - can't be triggered. We've consolidated the ABI values into trunnel now. - Fixes bug 30454; bugfix on 0.3.0.1-alpha. - - HSv3 client will now be able to properly handle unknown status code from - a INTRODUCE_ACK cell (nack) even if they do not know it. The NACK - behavior will stay the same. This will allow us to extend status code if - we want in the future without breaking the normal client behavior. diff --git a/changes/ticket30591 b/changes/ticket30591 new file mode 100644 index 0000000000..f97c024009 --- /dev/null +++ b/changes/ticket30591 @@ -0,0 +1,3 @@ + o Testing (continuous integration): + - In Travis, make stem log a controller trace to the console. And tail + stem's tor log after failure. Closes ticket 30591. diff --git a/changes/ticket30686 b/changes/ticket30686 new file mode 100644 index 0000000000..36473c1a02 --- /dev/null +++ b/changes/ticket30686 @@ -0,0 +1,5 @@ + o Minor features (logging): + - Give a more useful assertion failure message if we think we have + minherit() but we fail to make a region non-inheritable. Give a + compile-time warning if our support for minherit() is + incomplete. Closes ticket 30686. diff --git a/changes/ticket30694 b/changes/ticket30694 new file mode 100644 index 0000000000..70dbf6481a --- /dev/null +++ b/changes/ticket30694 @@ -0,0 +1,3 @@ + o Testing (continuous integration): + - In Travis, only run the stem tests that use a tor binary. + Closes ticket 30694. diff --git a/changes/ticket30871 b/changes/ticket30871 new file mode 100644 index 0000000000..81c076bb02 --- /dev/null +++ b/changes/ticket30871 @@ -0,0 +1,6 @@ + o Major bugfixes (circuit build, guard): + - When considering upgrading circuits from "waiting for guard" to "open", + always ignore the ones that are mark for close. Else, we can end up in + the situation where a subsystem is notified of that circuit opening but + still marked for close leading to undesirable behavior. Fixes bug 30871; + bugfix on 0.3.0.1-alpha. diff --git a/changes/ticket31001 b/changes/ticket31001 new file mode 100644 index 0000000000..2ce1cbdf34 --- /dev/null +++ b/changes/ticket31001 @@ -0,0 +1,6 @@ + o Minor bugfixes (compatibility, standards compliance): + - Fix a bug that would invoke undefined behavior on certain operating + systems when trying to asprintf() a string exactly INT_MAX bytes + long. We don't believe this is exploitable, but it's better + to fix it anyway. Fixes bug 31001; bugfix on 0.2.2.11-alpha. + Found and fixed by Tobias Stoeckmann. diff --git a/changes/ticket31311 b/changes/ticket31311 new file mode 100644 index 0000000000..88dfb85736 --- /dev/null +++ b/changes/ticket31311 @@ -0,0 +1,3 @@ + o Minor bugfixes (distribution): + - Do not ship any temporary files found in the scripts/maint/practracker + directory. Fixes bug 31311; bugfix on 0.4.1.1-alpha. diff --git a/changes/ticket31374 b/changes/ticket31374 new file mode 100644 index 0000000000..e8eef9cd49 --- /dev/null +++ b/changes/ticket31374 @@ -0,0 +1,4 @@ + o Minor bugfixes (compilation warning): + - Fix a compilation warning on Windows about casting a function + pointer for GetTickCount64(). Fixes bug 31374; bugfix on + 0.2.9.1-alpha. diff --git a/changes/ticket31406 b/changes/ticket31406 new file mode 100644 index 0000000000..0ebe6f6c47 --- /dev/null +++ b/changes/ticket31406 @@ -0,0 +1,3 @@ + o Minor features (directory authority): + - A new IP address the directory authority "dizum" has been changed. Closes + ticket 31406; diff --git a/configure.ac b/configure.ac index 4b69b3c89d..2295a9131d 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ dnl Copyright (c) 2007-2019, The Tor Project, Inc. dnl See LICENSE for licensing information AC_PREREQ([2.63]) -AC_INIT([tor],[0.4.0.5-dev]) +AC_INIT([tor],[0.4.1.5-dev]) AC_CONFIG_SRCDIR([src/app/main/tor_main.c]) AC_CONFIG_MACRO_DIR([m4]) @@ -14,7 +14,7 @@ AC_CONFIG_MACRO_DIR([m4]) # version number changes. Tor uses it to make sure that it # only shuts down for missing "required protocols" when those protocols # are listed as required by a consensus after this date. -AC_DEFINE(APPROX_RELEASE_DATE, ["2019-05-02"], # for 0.4.0.5-dev +AC_DEFINE(APPROX_RELEASE_DATE, ["2019-08-20"], # for 0.4.1.5-dev [Approximate date when this software was released. (Updated when the version changes.)]) # "foreign" means we don't follow GNU package layout standards @@ -949,21 +949,24 @@ AC_CHECK_MEMBERS([struct ssl_method_st.get_cipher_by_char], , , [#include ]) +dnl OpenSSL functions which we might not have. In theory, we could just +dnl check the openssl version number, but in practice that gets pretty +dnl confusing with LibreSSL, OpenSSL, and various distributions' patches +dnl to them. AC_CHECK_FUNCS([ \ ERR_load_KDF_strings \ + EVP_PBE_scrypt \ + EVP_sha3_256 \ + SSL_CIPHER_find \ + SSL_CTX_set1_groups_list \ + SSL_CTX_set_security_level \ SSL_SESSION_get_master_key \ + SSL_get_client_ciphers \ + SSL_get_client_random \ SSL_get_server_random \ - SSL_get_client_ciphers \ - SSL_get_client_random \ - SSL_CTX_set1_groups_list \ - SSL_CIPHER_find \ - SSL_CTX_set_security_level \ - TLS_method + TLS_method \ ]) -dnl Check if OpenSSL has scrypt implementation. -AC_CHECK_FUNCS([ EVP_PBE_scrypt ]) - dnl Check if OpenSSL structures are opaque AC_CHECK_MEMBERS([SSL.state], , , [#include @@ -975,6 +978,15 @@ AC_CHECK_SIZEOF(SHA_CTX, , [AC_INCLUDES_DEFAULT() fi # enable_nss +dnl We will someday make KECCAK_TINY optional, but for now we still need +dnl it for SHAKE, since OpenSSL's SHAKE can't be squeezed more than +dnl once. See comment in the definition of crypto_xof_t. + +dnl AM_CONDITIONAL(BUILD_KECCAK_TINY, +dnl test "x$ac_cv_func_EVP_sha3_256" != "xyes") + +AM_CONDITIONAL(BUILD_KECCAK_TINY, true) + dnl ====================================================================== dnl Can we use KIST? @@ -1593,6 +1605,7 @@ AC_CHECK_MEMBERS([struct timeval.tv_sec], , , AC_CHECK_SIZEOF(char) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(unsigned int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long long) AC_CHECK_SIZEOF(__int64) @@ -2444,9 +2457,7 @@ AC_CONFIG_FILES([ Doxyfile Makefile config.rust - contrib/dist/suse/tor.sh contrib/operator-tools/tor.logrotate - contrib/dist/tor.sh contrib/dist/torctl contrib/dist/tor.service src/config/torrc.sample diff --git a/contrib/README b/contrib/README index 3a94bb5016..735fcf4c9f 100644 --- a/contrib/README +++ b/contrib/README @@ -34,8 +34,6 @@ tools. Everybody likes to write init scripts differently, it seems. tor.service is a sample service file for use with systemd. -The suse/ subdirectory contains files used by the suse distribution. - operator-tools/ -- Tools for Tor relay operators ------------------------------------------------ diff --git a/contrib/client-tools/torify b/contrib/client-tools/torify index 54acfed654..ac4c9b5c7f 100755 --- a/contrib/client-tools/torify +++ b/contrib/client-tools/torify @@ -53,7 +53,7 @@ pathfind() { if pathfind torsocks; then exec torsocks "$@" - echo "$0: Failed to exec torsocks $@" >&2 + echo "$0: Failed to exec torsocks $*" >&2 exit 1 else echo "$0: torsocks not found in your PATH. Perhaps it isn't installed? (tsocks is no longer supported, for security reasons.)" >&2 diff --git a/contrib/dirauth-tools/nagios-check-tor-authority-cert b/contrib/dirauth-tools/nagios-check-tor-authority-cert index 46dc7284b7..75ff479a53 100755 --- a/contrib/dirauth-tools/nagios-check-tor-authority-cert +++ b/contrib/dirauth-tools/nagios-check-tor-authority-cert @@ -49,12 +49,12 @@ DIRSERVERS="$DIRSERVERS 80.190.246.100:80" # gabelmoo DIRSERVERS="$DIRSERVERS 194.109.206.212:80" # dizum DIRSERVERS="$DIRSERVERS 213.73.91.31:80" # dannenberg -TMPFILE="`tempfile`" +TMPFILE=$(mktemp) trap 'rm -f "$TMPFILE"' 0 for dirserver in $DIRSERVERS; do - wget -q -O "$TMPFILE" "http://$dirserver/tor/keys/fp/$identity" - if [ "$?" = 0 ]; then + if wget -q -O "$TMPFILE" "http://$dirserver/tor/keys/fp/$identity" + then break else cat /dev/null > "$TMPFILE" @@ -74,10 +74,10 @@ now=$(date +%s) if [ "$now" -ge "$expiryunix" ]; then echo "CRITICAL: Certificate expired $expirydate (authority $identity)." exit 2 -elif [ "$(( $now + 7*24*60*60 ))" -ge "$expiryunix" ]; then +elif [ "$(( now + 7*24*60*60 ))" -ge "$expiryunix" ]; then echo "CRITICAL: Certificate expires $expirydate (authority $identity)." exit 2 -elif [ "$(( $now + 30*24*60*60 ))" -ge "$expiryunix" ]; then +elif [ "$(( now + 30*24*60*60 ))" -ge "$expiryunix" ]; then echo "WARNING: Certificate expires $expirydate (authority $identity)." exit 1 else diff --git a/contrib/dist/suse/tor.sh.in b/contrib/dist/suse/tor.sh.in deleted file mode 100644 index b7e9005eb5..0000000000 --- a/contrib/dist/suse/tor.sh.in +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006-2007 Andrew Lewman -# -# tor The Onion Router -# -# Startup/shutdown script for tor. This is a wrapper around torctl; -# torctl does the actual work in a relatively system-independent, or at least -# distribution-independent, way, and this script deals with fitting the -# whole thing into the conventions of the particular system at hand. -# -# These next couple of lines "declare" tor for the "chkconfig" program, -# originally from SGI, used on Red Hat/Fedora and probably elsewhere. -# -# chkconfig: 2345 90 10 -# description: Onion Router - A low-latency anonymous proxy -# - -### BEGIN INIT INFO -# Provides: tor -# Required-Start: $remote_fs $network -# Required-Stop: $remote_fs $network -# Default-Start: 3 5 -# Default-Stop: 0 1 2 6 -# Short-Description: Start the tor daemon -# Description: Start the tor daemon: the anon-proxy server -### END INIT INFO - -. /etc/rc.status - -# Shell functions sourced from /etc/rc.status: -# rc_check check and set local and overall rc status -# rc_status check and set local and overall rc status -# rc_status -v ditto but be verbose in local rc status -# rc_status -v -r ditto and clear the local rc status -# rc_failed set local and overall rc status to failed -# rc_reset clear local rc status (overall remains) -# rc_exit exit appropriate to overall rc status - -# First reset status of this service -rc_reset - -# Increase open file descriptors a reasonable amount -ulimit -n 8192 - -TORCTL=@BINDIR@/torctl - -# torctl will use these environment variables -TORUSER=@TORUSER@ -export TORUSER -TORGROUP=@TORGROUP@ -export TORGROUP - -TOR_DAEMON_PID_DIR="@LOCALSTATEDIR@/run/tor" - -if [ -x /bin/su ] ; then - SUPROG=/bin/su -elif [ -x /sbin/su ] ; then - SUPROG=/sbin/su -elif [ -x /usr/bin/su ] ; then - SUPROG=/usr/bin/su -elif [ -x /usr/sbin/su ] ; then - SUPROG=/usr/sbin/su -else - SUPROG=/bin/su -fi - -case "$1" in - - start) - echo "Starting tor daemon" - - if [ ! -d $TOR_DAEMON_PID_DIR ] ; then - mkdir -p $TOR_DAEMON_PID_DIR - chown $TORUSER:$TORGROUP $TOR_DAEMON_PID_DIR - fi - - ## Start daemon with startproc(8). If this fails - ## the echo return value is set appropriate. - - startproc -f $TORCTL start - # Remember status and be verbose - rc_status -v - ;; - - stop) - echo "Stopping tor daemon" - startproc -f $TORCTL stop - # Remember status and be verbose - rc_status -v - ;; - - restart) - echo "Restarting tor daemon" - startproc -f $TORCTL restart - # Remember status and be verbose - rc_status -v - ;; - - reload) - echo "Reloading tor daemon" - startproc -f $TORCTL reload - # Remember status and be verbose - rc_status -v - ;; - - status) - startproc -f $TORCTL status - # Remember status and be verbose - rc_status -v - ;; - - *) - echo "Usage: $0 (start|stop|restart|reload|status)" - RETVAL=1 -esac - -rc_exit diff --git a/contrib/dist/tor.sh.in b/contrib/dist/tor.sh.in deleted file mode 100644 index 92f890681f..0000000000 --- a/contrib/dist/tor.sh.in +++ /dev/null @@ -1,123 +0,0 @@ -#!/bin/sh -# -# tor The Onion Router -# -# Startup/shutdown script for tor. This is a wrapper around torctl; -# torctl does the actual work in a relatively system-independent, or at least -# distribution-independent, way, and this script deals with fitting the -# whole thing into the conventions of the particular system at hand. -# This particular script is written for Red Hat/Fedora Linux, and may -# also work on Mandrake, but not SuSE. -# -# These next couple of lines "declare" tor for the "chkconfig" program, -# originally from SGI, used on Red Hat/Fedora and probably elsewhere. -# -# chkconfig: 2345 90 10 -# description: Onion Router - A low-latency anonymous proxy -# - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/sbin/tor -NAME=tor -DESC="tor daemon" -TORPIDDIR=/var/run/tor -TORPID=$TORPIDDIR/tor.pid -WAITFORDAEMON=60 -ARGS="" - -# Library functions -if [ -f /etc/rc.d/init.d/functions ]; then - . /etc/rc.d/init.d/functions -elif [ -f /etc/init.d/functions ]; then - . /etc/init.d/functions -fi - -TORCTL=@BINDIR@/torctl - -# torctl will use these environment variables -TORUSER=@TORUSER@ -export TORUSER - -if [ -x /bin/su ] ; then - SUPROG=/bin/su -elif [ -x /sbin/su ] ; then - SUPROG=/sbin/su -elif [ -x /usr/bin/su ] ; then - SUPROG=/usr/bin/su -elif [ -x /usr/sbin/su ] ; then - SUPROG=/usr/sbin/su -else - SUPROG=/bin/su -fi - -# Raise ulimit based on number of file descriptors available (thanks, Debian) - -if [ -r /proc/sys/fs/file-max ]; then - system_max=`cat /proc/sys/fs/file-max` - if [ "$system_max" -gt "80000" ] ; then - MAX_FILEDESCRIPTORS=32768 - elif [ "$system_max" -gt "40000" ] ; then - MAX_FILEDESCRIPTORS=16384 - elif [ "$system_max" -gt "10000" ] ; then - MAX_FILEDESCRIPTORS=8192 - else - MAX_FILEDESCRIPTORS=1024 - cat << EOF - -Warning: Your system has very few filedescriptors available in total. - -Maybe you should try raising that by adding 'fs.file-max=100000' to your -/etc/sysctl.conf file. Feel free to pick any number that you deem appropriate. -Then run 'sysctl -p'. See /proc/sys/fs/file-max for the current value, and -file-nr in the same directory for how many of those are used at the moment. - -EOF - fi -else - MAX_FILEDESCRIPTORS=8192 -fi - -NICE="" - -case "$1" in - - start) - if [ -n "$MAX_FILEDESCRIPTORS" ]; then - echo -n "Raising maximum number of filedescriptors (ulimit -n) to $MAX_FILEDESCRIPTORS" - if ulimit -n "$MAX_FILEDESCRIPTORS" ; then - echo "." - else - echo ": FAILED." - fi - fi - - action $"Starting tor:" $TORCTL start - RETVAL=$? - ;; - - stop) - action $"Stopping tor:" $TORCTL stop - RETVAL=$? - ;; - - restart) - action $"Restarting tor:" $TORCTL restart - RETVAL=$? - ;; - - reload) - action $"Reloading tor:" $TORCTL reload - RETVAL=$? - ;; - - status) - $TORCTL status - RETVAL=$? - ;; - - *) - echo "Usage: $0 (start|stop|restart|reload|status)" - RETVAL=1 -esac - -exit $RETVAL diff --git a/contrib/include.am b/contrib/include.am index a23e82d6da..8dd8593304 100644 --- a/contrib/include.am +++ b/contrib/include.am @@ -3,11 +3,8 @@ EXTRA_DIST+= \ contrib/README \ contrib/client-tools/torify \ contrib/dist/rc.subr \ - contrib/dist/suse/tor.sh.in \ - contrib/dist/tor.sh \ contrib/dist/torctl \ contrib/dist/tor.service.in \ - contrib/operator-tools/linux-tor-prio.sh \ contrib/operator-tools/tor-exit-notice.html \ contrib/or-tools/exitlist \ contrib/win32build/tor-mingw.nsi.in \ diff --git a/contrib/operator-tools/linux-tor-prio.sh b/contrib/operator-tools/linux-tor-prio.sh deleted file mode 100644 index 30ea5fc659..0000000000 --- a/contrib/operator-tools/linux-tor-prio.sh +++ /dev/null @@ -1,192 +0,0 @@ -#!/bin/bash -# Written by Marco Bonetti & Mike Perry -# Based on instructions from Dan Singletary's ADSL BW Management HOWTO: -# http://www.faqs.org/docs/Linux-HOWTO/ADSL-Bandwidth-Management-HOWTO.html -# This script is Public Domain. - -############################### README ################################# - -# This script provides prioritization of Tor traffic below other -# traffic on a Linux server. It has two modes of operation: UID based -# and IP based. - -# UID BASED PRIORITIZATION -# -# The UID based method requires that Tor be launched from -# a specific user ID. The "User" Tor config setting is -# insufficient, as it sets the UID after the socket is created. -# Here is a C wrapper you can use to execute Tor and drop privs before -# it creates any sockets. -# -# Compile with: -# gcc -DUID=`id -u tor` -DGID=`id -g tor` tor_wrap.c -o tor_wrap -# -# #include -# int main(int argc, char **argv) { -# if(initgroups("tor", GID) == -1) { perror("initgroups"); return 1; } -# if(setresgid(GID, GID, GID) == -1) { perror("setresgid"); return 1; } -# if(setresuid(UID, UID, UID) == -1) { perror("setresuid"); return 1; } -# execl("/bin/tor", "/bin/tor", "-f", "/etc/tor/torrc", NULL); -# perror("execl"); return 1; -# } - -# IP BASED PRIORITIZATION -# -# The IP setting requires that a separate IP address be dedicated to Tor. -# Your Torrc should be set to bind to this IP for "OutboundBindAddress", -# "ListenAddress", and "Address". - -# GENERAL USAGE -# -# You should also tune the individual connection rate parameters below -# to your individual connection. In particular, you should leave *some* -# minimum amount of bandwidth for Tor, so that Tor users are not -# completely choked out when you use your server's bandwidth. 30% is -# probably a reasonable choice. More is better of course. -# -# To start the shaping, run it as: -# ./linux-tor-prio.sh -# -# To get status information (useful to verify packets are getting marked -# and prioritized), run: -# ./linux-tor-prio.sh status -# -# And to stop prioritization: -# ./linux-tor-prio.sh stop -# -######################################################################## - -# BEGIN USER TUNABLE PARAMETERS - -DEV=eth0 - -# NOTE! You must START Tor under this UID. Using the Tor User -# config setting is NOT sufficient. See above. -TOR_UID=$(id -u tor) - -# If the UID mechanism doesn't work for you, you can set this parameter -# instead. If set, it will take precedence over the UID setting. Note that -# you need multiple IPs with one specifically devoted to Tor for this to -# work. -#TOR_IP="42.42.42.42" - -# Average ping to most places on the net, milliseconds -RTT_LATENCY=40 - -# RATE_UP must be less than your connection's upload capacity in -# kbits/sec. If it is larger, then the bottleneck will be at your -# router's queue, which you do not control. This will cause congestion -# and a revert to normal TCP fairness no matter what the queing -# priority is. -RATE_UP=5000 - -# RATE_UP_TOR is the minimum speed your Tor connections will have in -# kbits/sec. They will have at least this much bandwidth for upload. -# In general, you probably shouldn't set this too low, or else Tor -# users who use your node will be completely choked out whenever your -# machine does any other network activity. That is not very fun. -RATE_UP_TOR=1500 - -# RATE_UP_TOR_CEIL is the maximum rate allowed for all Tor traffic in -# kbits/sec. -RATE_UP_TOR_CEIL=5000 - -CHAIN=OUTPUT -#CHAIN=PREROUTING -#CHAIN=POSTROUTING - -MTU=1500 -AVG_PKT=900 # should be more like 600 for non-exit nodes - -# END USER TUNABLE PARAMETERS - - - -# The queue size should be no larger than your bandwidth-delay -# product. This is RT latency*bandwidth/MTU/2 - -BDP=$(expr $RTT_LATENCY \* $RATE_UP / $AVG_PKT) - -# Further research indicates that the BDP calculations should use -# RTT/sqrt(n) where n is the expected number of active connections.. - -BDP=$(expr $BDP / 4) - -if [ "$1" = "status" ] -then - echo "[qdisc]" - tc -s qdisc show dev $DEV - tc -s qdisc show dev imq0 - echo "[class]" - tc -s class show dev $DEV - tc -s class show dev imq0 - echo "[filter]" - tc -s filter show dev $DEV - tc -s filter show dev imq0 - echo "[iptables]" - iptables -t mangle -L TORSHAPER-OUT -v -x 2> /dev/null - exit -fi - - -# Reset everything to a known state (cleared) -tc qdisc del dev $DEV root 2> /dev/null > /dev/null -tc qdisc del dev imq0 root 2> /dev/null > /dev/null -iptables -t mangle -D POSTROUTING -o $DEV -j TORSHAPER-OUT 2> /dev/null > /dev/null -iptables -t mangle -D PREROUTING -o $DEV -j TORSHAPER-OUT 2> /dev/null > /dev/null -iptables -t mangle -D OUTPUT -o $DEV -j TORSHAPER-OUT 2> /dev/null > /dev/null -iptables -t mangle -F TORSHAPER-OUT 2> /dev/null > /dev/null -iptables -t mangle -X TORSHAPER-OUT 2> /dev/null > /dev/null -ip link set imq0 down 2> /dev/null > /dev/null -rmmod imq 2> /dev/null > /dev/null - -if [ "$1" = "stop" ] -then - echo "Shaping removed on $DEV." - exit -fi - -# Outbound Shaping (limits total bandwidth to RATE_UP) - -ip link set dev $DEV qlen $BDP - -# Add HTB root qdisc, default is high prio -tc qdisc add dev $DEV root handle 1: htb default 20 - -# Add main rate limit class -tc class add dev $DEV parent 1: classid 1:1 htb rate ${RATE_UP}kbit - -# Create the two classes, giving Tor at least RATE_UP_TOR kbit and capping -# total upstream at RATE_UP so the queue is under our control. -tc class add dev $DEV parent 1:1 classid 1:20 htb rate $(expr $RATE_UP - $RATE_UP_TOR)kbit ceil ${RATE_UP}kbit prio 0 -tc class add dev $DEV parent 1:1 classid 1:21 htb rate $[$RATE_UP_TOR]kbit ceil ${RATE_UP_TOR_CEIL}kbit prio 10 - -# Start up pfifo -tc qdisc add dev $DEV parent 1:20 handle 20: pfifo limit $BDP -tc qdisc add dev $DEV parent 1:21 handle 21: pfifo limit $BDP - -# filter traffic into classes by fwmark -tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 20 fw flowid 1:20 -tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 21 fw flowid 1:21 - -# add TORSHAPER-OUT chain to the mangle table in iptables -iptables -t mangle -N TORSHAPER-OUT -iptables -t mangle -I $CHAIN -o $DEV -j TORSHAPER-OUT - - -# Set firewall marks -# Low priority to Tor -if [ ""$TOR_IP == "" ] -then - echo "Using UID-based QoS. UID $TOR_UID marked as low priority." - iptables -t mangle -A TORSHAPER-OUT -m owner --uid-owner $TOR_UID -j MARK --set-mark 21 -else - echo "Using IP-based QoS. $TOR_IP marked as low priority." - iptables -t mangle -A TORSHAPER-OUT -s $TOR_IP -j MARK --set-mark 21 -fi - -# High prio for everything else -iptables -t mangle -A TORSHAPER-OUT -m mark --mark 0 -j MARK --set-mark 20 - -echo "Outbound shaping added to $DEV. Rate for Tor upload at least: ${RATE_UP_TOR}Kbyte/sec." - diff --git a/contrib/win32build/tor-mingw.nsi.in b/contrib/win32build/tor-mingw.nsi.in index 7b3cf21160..25c911d937 100644 --- a/contrib/win32build/tor-mingw.nsi.in +++ b/contrib/win32build/tor-mingw.nsi.in @@ -8,7 +8,7 @@ !include "LogicLib.nsh" !include "FileFunc.nsh" !insertmacro GetParameters -!define VERSION "0.4.0.5-dev" +!define VERSION "0.4.1.5-dev" !define INSTALLER "tor-${VERSION}-win32.exe" !define WEBSITE "https://www.torproject.org/" !define LICENSE "LICENSE" diff --git a/doc/HACKING/CodingStandards.md b/doc/HACKING/CodingStandards.md index 4f229348e4..74db2a39a3 100644 --- a/doc/HACKING/CodingStandards.md +++ b/doc/HACKING/CodingStandards.md @@ -110,12 +110,41 @@ it's a bugfix, mention what bug it fixes and when the bug was introduced. To find out which Git tag the change was introduced in, you can use `git describe --contains `. -If at all possible, try to create this file in the same commit where you are -making the change. Please give it a distinctive name that no other branch will -use for the lifetime of your change. To verify the format of the changes file, -you can use `make check-changes`. This is run automatically as part of -`make check` -- if it fails, we must fix it before we release. These -checks are implemented in `scripts/maint/lintChanges.py`. +If you don't know the commit, you can search the git diffs (-S) for the first +instance of the feature (--reverse). + +For example, for #30224, we wanted to know when the bridge-distribution-request +feature was introduced into Tor: + $ git log -S bridge-distribution-request --reverse + commit ebab521525 + Author: Roger Dingledine + Date: Sun Nov 13 02:39:16 2016 -0500 + + Add new BridgeDistribution config option + + $ git describe --contains ebab521525 + tor-0.3.2.3-alpha~15^2~4 + +If you need to know all the Tor versions that contain a commit, use: + $ git tag --contains 9f2efd02a1 | sort -V + tor-0.2.5.16 + tor-0.2.8.17 + tor-0.2.9.14 + tor-0.2.9.15 + ... + tor-0.3.0.13 + tor-0.3.1.9 + tor-0.3.1.10 + ... + +If at all possible, try to create the changes file in the same commit where +you are making the change. Please give it a distinctive name that no other +branch will use for the lifetime of your change. We usually use "ticketNNNNN" +or "bugNNNNN", where NNNNN is the ticket number. To verify the format of the +changes file, you can use `make check-changes`. This is run automatically as +part of `make check` -- if it fails, we must fix it as soon as possible, so +that our CI passes. These checks are implemented in +`scripts/maint/lintChanges.py`. Changes file style guide: * Changes files begin with " o Header (subheading):". The header diff --git a/doc/HACKING/CodingStandardsRust.md b/doc/HACKING/CodingStandardsRust.md index fc562816db..b570e10dc7 100644 --- a/doc/HACKING/CodingStandardsRust.md +++ b/doc/HACKING/CodingStandardsRust.md @@ -256,7 +256,7 @@ Here are some additional bits of advice and rules: or 2) should fail (i.e. in a unittest). You SHOULD NOT use `unwrap()` anywhere in which it is possible to handle the - potential error with either `expect()` or the eel operator, `?`. + potential error with the eel operator, `?` or another non panicking way. For example, consider a function which parses a string into an integer: fn parse_port_number(config_string: &str) -> u16 { @@ -264,12 +264,12 @@ Here are some additional bits of advice and rules: } There are numerous ways this can fail, and the `unwrap()` will cause the - whole program to byte the dust! Instead, either you SHOULD use `expect()` + whole program to byte the dust! Instead, either you SHOULD use `ok()` (or another equivalent function which will return an `Option` or a `Result`) and change the return type to be compatible: fn parse_port_number(config_string: &str) -> Option { - u16::from_str_radix(config_string, 10).expect("Couldn't parse port into a u16") + u16::from_str_radix(config_string, 10).ok() } or you SHOULD use `or()` (or another similar method): diff --git a/doc/HACKING/HelpfulTools.md b/doc/HACKING/HelpfulTools.md index d499238526..cba57e875d 100644 --- a/doc/HACKING/HelpfulTools.md +++ b/doc/HACKING/HelpfulTools.md @@ -371,3 +371,18 @@ source code. Here's how to use it: 6. See the Doxygen manual for more information; this summary just scratches the surface. + +Style and best-pratices checking +-------------------------------- + +We use scripts to check for various problems in the formatting and style +of our source code. The "check-spaces" test detects a bunch of violations +of our coding style on the local level. The "check-best-practices" test +looks for violations of some of our complexity guidelines. + +You can tell the tool about exceptions to the complexity guidelines via its +exceptions file (scripts/maint/practracker/exceptions.txt). But before you +do this, consider whether you shouldn't fix the underlying problem. Maybe +that file really _is_ too big. Maybe that function really _is_ doing too +much. (On the other hand, for stable release series, it is sometimes better +to leave things unrefactored.) diff --git a/doc/HACKING/ReleasingTor.md b/doc/HACKING/ReleasingTor.md index 7334b1b34a..a97ca08ce9 100644 --- a/doc/HACKING/ReleasingTor.md +++ b/doc/HACKING/ReleasingTor.md @@ -20,8 +20,11 @@ new Tor release: === I. Make sure it works -1. Make sure that CI passes: have a look at Travis, Appveyor, and - Jenkins. Make sure you're looking at the right branches. +1. Make sure that CI passes: have a look at Travis + (https://travis-ci.org/torproject/tor/branches), Appveyor + (https://ci.appveyor.com/project/torproject/tor/history), and + Jenkins (https://jenkins.torproject.org/view/tor/). + Make sure you're looking at the right branches. If there are any unexplained failures, try to fix them or figure them out. @@ -40,10 +43,14 @@ new Tor release: * clang scan-build. (See the script in ./scripts/test/scan_build.sh) * make test-network and make test-network-all (with - --enable-expensive-hardening) + --enable-fragile-hardening) * Running Tor yourself and making sure that it actually works for you. + * Running Tor under valgrind. (Our 'fragile hardening' doesn't cover + libevent and openssl, so using valgrind will sometimes find extra + memory leaks.) + === II. Write a changelog @@ -176,7 +183,8 @@ new Tor release: `/srv/dist-master.torproject.org/htdocs/` on dist-master. Run "static-update-component dist.torproject.org" on dist-master. - In the webwml.git repository, `include/versions.wmi` and `Makefile` + In the webwml.git repository, `include/versions.wmi` and `Makefile`. + In the project/web/tpo.git repository, update `databags/versions.ini` to note the new version. Push these changes to master. (NOTE: Due to #17805, there can only be one stable version listed at @@ -243,3 +251,5 @@ new Tor release: master branch. 3. Keep an eye on the blog post, to moderate comments and answer questions. + + diff --git a/doc/asciidoc-helper.sh b/doc/asciidoc-helper.sh index a3ef53f884..765850a125 100755 --- a/doc/asciidoc-helper.sh +++ b/doc/asciidoc-helper.sh @@ -19,7 +19,7 @@ if [ "$1" = "html" ]; then base=${output%%.html.in} if [ "$2" != none ]; then - TZ=UTC "$2" -d manpage -o $output $input; + TZ=UTC "$2" -d manpage -o "$output" "$input"; else echo "=================================="; echo; @@ -44,8 +44,8 @@ elif [ "$1" = "man" ]; then echo "=================================="; exit 1; fi - if "$2" -f manpage $input; then - mv $base.1 $output; + if "$2" -f manpage "$input"; then + mv "$base.1" "$output"; else cat< + } + +// Clean up more printfs that could be writes +// +// For some reason, including this rule, even disabled, causes the +// match rule in ctrl-reply.cocci to fail to match some code that has +// %s in its format strings + +@ cleanup_write2 @ +expression E1, E2; +constant code; +@@ +( +-control_printf_endreply(E1, code, "%s", E2) ++control_write_endreply(E1, code, E2) +| +-control_printf_midreply(E1, code, "%s", E2) ++control_write_midreply(E1, code, E2) +) diff --git a/scripts/coccinelle/ctrl-reply.cocci b/scripts/coccinelle/ctrl-reply.cocci new file mode 100644 index 0000000000..d6e9aeedd7 --- /dev/null +++ b/scripts/coccinelle/ctrl-reply.cocci @@ -0,0 +1,87 @@ +// Script to edit control_*.c for refactored control reply output functions + +@ initialize:python @ +@@ +import re +from coccilib.report import * + +# reply strings "NNN-foo", "NNN+foo", "NNN foo", etc. +r = re.compile(r'^"(\d+)([ +-])(.*)\\r\\n"$') + +# Generate name of function to call based on which separator character +# comes between the numeric code and the text +def idname(sep, base): + if sep == '+': + return base + "datareply" + elif sep == '-': + return base + "midreply" + else: + return base + "endreply" + +# Generate the actual replacements used by the rules +def gen(s, base, p): + pos = p[0] + print_report(pos, "%s %s" % (base, s)) + m = r.match(s) + if m is None: + # String not correct format, so fail match + cocci.include_match(False) + print_report(pos, "BAD STRING %s" % s) + return + + code, sep, s1 = m.groups() + + if r'\r\n' in s1: + # Extra CRLF in string, so fail match + cocci.include_match(False) + print_report(pos, "extra CRLF in string %s" % s) + return + + coccinelle.code = code + # Need a string that is a single C token, because Coccinelle only allows + # "identifiers" to be output from Python scripts? + coccinelle.body = '"%s"' % s1 + coccinelle.id = idname(sep, base) + return + +@ match @ +identifier f; +position p; +expression E; +constant s; +@@ +( + connection_printf_to_buf@f@p(E, s, ...) +| + connection_write_str_to_buf@f@p(s, E) +) + +@ script:python sc1 @ +s << match.s; +p << match.p; +f << match.f; +id; +body; +code; +@@ +if f == 'connection_printf_to_buf': + gen(s, 'control_printf_', p) +elif f == 'connection_write_str_to_buf': + gen(s, 'control_write_', p) +else: + raise(ValueError("%s: %s" % (f, s))) + +@ replace @ +constant match.s; +expression match.E; +identifier match.f; +identifier sc1.body, sc1.id, sc1.code; +@@ +( +-connection_write_str_to_buf@f(s, E) ++id(E, code, body) +| +-connection_printf_to_buf@f(E, s ++id(E, code, body + , ...) +) diff --git a/scripts/coccinelle/tor-coccinelle.h b/scripts/coccinelle/tor-coccinelle.h new file mode 100644 index 0000000000..8f625dcee4 --- /dev/null +++ b/scripts/coccinelle/tor-coccinelle.h @@ -0,0 +1,3 @@ +#define MOCK_IMPL(a, b, c) a b c +#define CHECK_PRINTF(a, b) +#define STATIC static diff --git a/scripts/git/git-merge-forward.sh b/scripts/git/git-merge-forward.sh new file mode 100755 index 0000000000..67af7e98bf --- /dev/null +++ b/scripts/git/git-merge-forward.sh @@ -0,0 +1,236 @@ +#!/bin/bash + +############################## +# Configuration (change me!) # +############################## + +# The general setup that is suggested here is: +# +# GIT_PATH = /home//git/ +# ... where the git repository directories resides. +# TOR_MASTER_NAME = "tor" +# ... which means that tor.git was cloned in /home//git/tor +# TOR_WKT_NAME = "tor-wkt" +# ... which means that the tor worktrees are in /home//git/tor-wkt + +# Where are all those git repositories? +GIT_PATH="FULL_PATH_TO_GIT_REPOSITORY_DIRECTORY" +# The tor master git repository directory from which all the worktree have +# been created. +TOR_MASTER_NAME="tor" +# The worktrees location (directory). +TOR_WKT_NAME="tor-wkt" + +######################### +# End of configuration. # +######################### + +# Configuration of the branches that needs merging. The values are in order: +# (1) Branch name that we merge onto. +# (2) Branch name to merge from. In other words, this is merge into (1) +# (3) Full path of the git worktree. +# +# As an example: +# $ cd (3) +# $ git checkout maint-0.3.5 (1) +# $ git pull +# $ git merge maint-0.3.4 (2) +# +# First set of arrays are the maint-* branch and then the release-* branch. +# New arrays need to be in the WORKTREE= array else they aren't considered. +MAINT_034=( "maint-0.3.4" "maint-0.2.9" "$GIT_PATH/$TOR_WKT_NAME/maint-0.3.4" ) +MAINT_035=( "maint-0.3.5" "maint-0.3.4" "$GIT_PATH/$TOR_WKT_NAME/maint-0.3.5" ) +MAINT_040=( "maint-0.4.0" "maint-0.3.5" "$GIT_PATH/$TOR_WKT_NAME/maint-0.4.0" ) +MAINT_MASTER=( "master" "maint-0.4.0" "$GIT_PATH/$TOR_MASTER_NAME" ) + +RELEASE_029=( "release-0.2.9" "maint-0.2.9" "$GIT_PATH/$TOR_WKT_NAME/release-0.2.9" ) +RELEASE_034=( "release-0.3.4" "maint-0.3.4" "$GIT_PATH/$TOR_WKT_NAME/release-0.3.4" ) +RELEASE_035=( "release-0.3.5" "maint-0.3.5" "$GIT_PATH/$TOR_WKT_NAME/release-0.3.5" ) +RELEASE_040=( "release-0.4.0" "maint-0.4.0" "$GIT_PATH/$TOR_WKT_NAME/release-0.4.0" ) + +# The master branch path has to be the main repository thus contains the +# origin that will be used to fetch the updates. All the worktrees are created +# from that repository. +ORIGIN_PATH="$GIT_PATH/$TOR_MASTER_NAME" + +# SC2034 -- shellcheck thinks that these are unused. We know better. +ACTUALLY_THESE_ARE_USED=<&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +# Pull the given branch name. +function pull_branch +{ + local cmd="git pull" + printf " %s Pulling branch %s..." "$MARKER" "$1" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +# Merge the given branch name ($2) into the current branch ($1). +function merge_branch +{ + local cmd="git merge --no-edit $1" + printf " %s Merging branch %s into %s..." "$MARKER" "$1" "$2" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +# Pull the given branch name. +function merge_branch_origin +{ + local cmd="git merge --ff-only origin/$1" + printf " %s Merging branch origin/%s..." "$MARKER" "$1" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +# Go into the worktree repository. +function goto_repo +{ + if [ ! -d "$1" ]; then + echo " $1: Not found. Stopping." + exit 1 + fi + cd "$1" || exit +} + +# Fetch the origin. No arguments. +function fetch_origin +{ + local cmd="git fetch origin" + printf " %s Fetching origin..." "$MARKER" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +############### +# Entry point # +############### + +while getopts "n" opt; do + case "$opt" in + n) DRY_RUN=1 + echo " *** DRY DRUN MODE ***" + ;; + *) + ;; + esac +done + +# First, fetch the origin. +goto_repo "$ORIGIN_PATH" +fetch_origin + +# Go over all configured worktree. +for ((i=0; i/git/ +# ... where the git repository directories resides. +# TOR_MASTER_NAME = "tor" +# ... which means that tor.git was cloned in /home//git/tor +# TOR_WKT_NAME = "tor-wkt" +# ... which means that the tor worktrees are in /home//git/tor-wkt + +# Where are all those git repositories? +GIT_PATH="FULL_PATH_TO_GIT_REPOSITORY_DIRECTORY" +# The tor master git repository directory from which all the worktree have +# been created. +TOR_MASTER_NAME="tor" +# The worktrees location (directory). +TOR_WKT_NAME="tor-wkt" + +######################### +# End of configuration. # +######################### + +# Configuration of the branches that needs merging. The values are in order: +# (1) Branch name to pull (update). +# (2) Full path of the git worktree. +# +# As an example: +# $ cd (3) +# $ git checkout maint-0.3.5 (1) +# $ git pull +# +# First set of arrays are the maint-* branch and then the release-* branch. +# New arrays need to be in the WORKTREE= array else they aren't considered. +MAINT_029=( "maint-0.2.9" "$GIT_PATH/$TOR_WKT_NAME/maint-0.2.9" ) +MAINT_034=( "maint-0.3.4" "$GIT_PATH/$TOR_WKT_NAME/maint-0.3.4" ) +MAINT_035=( "maint-0.3.5" "$GIT_PATH/$TOR_WKT_NAME/maint-0.3.5" ) +MAINT_040=( "maint-0.4.0" "$GIT_PATH/$TOR_WKT_NAME/maint-0.4.0" ) +MAINT_MASTER=( "master" "$GIT_PATH/$TOR_MASTER_NAME" ) + +RELEASE_029=( "release-0.2.9" "$GIT_PATH/$TOR_WKT_NAME/release-0.2.9" ) +RELEASE_034=( "release-0.3.4" "$GIT_PATH/$TOR_WKT_NAME/release-0.3.4" ) +RELEASE_035=( "release-0.3.5" "$GIT_PATH/$TOR_WKT_NAME/release-0.3.5" ) +RELEASE_040=( "release-0.4.0" "$GIT_PATH/$TOR_WKT_NAME/release-0.4.0" ) + +# The master branch path has to be the main repository thus contains the +# origin that will be used to fetch the updates. All the worktrees are created +# from that repository. +ORIGIN_PATH="$GIT_PATH/$TOR_MASTER_NAME" + +# SC2034 -- shellcheck thinks that these are unused. We know better. +ACTUALLY_THESE_ARE_USED=<&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +# Pull the given branch name. +function merge_branch +{ + local cmd="git merge --ff-only origin/$1" + printf " %s Merging branch origin/%s..." "$MARKER" "$1" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +# Go into the worktree repository. +function goto_repo +{ + if [ ! -d "$1" ]; then + echo " $1: Not found. Stopping." + exit 1 + fi + cd "$1" || exit +} + +# Fetch the origin. No arguments. +function fetch_origin +{ + local cmd="git fetch origin" + printf " %s Fetching origin..." "$MARKER" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +# Fetch tor-github pull requests. No arguments. +function fetch_tor_github +{ + local cmd="git fetch tor-github" + printf " %s Fetching tor-github..." "$MARKER" + if [ $DRY_RUN -eq 0 ]; then + msg=$( eval "$cmd" 2>&1 ) + validate_ret $? "$msg" + else + printf "\\n %s\\n" "${IWTH}$cmd${CNRM}" + fi +} + +############### +# Entry point # +############### + +while getopts "n" opt; do + case "$opt" in + n) DRY_RUN=1 + echo " *** DRY DRUN MODE ***" + ;; + *) + ;; + esac +done + +# First, fetch tor-github. +goto_repo "$ORIGIN_PATH" +fetch_tor_github + +# Then, fetch the origin. +fetch_origin + +# Go over all configured worktree. +for ((i=0; i/dev/null 2>&1 + then + echo "ATTENTION: $1 hook has changed:" + echo "===============================" + diff -u "$installed" "$latest" + fi + fi +} + +check_for_script_update() { + fullpath="$1" + + if ! git diff ORIG_HEAD HEAD --exit-code -- "$fullpath" >/dev/null + then + echo "ATTENTION: $1 has changed:" + git --no-pager diff ORIG_HEAD HEAD -- "$fullpath" + fi +} + +check_for_diffs "pre-push" +check_for_diffs "pre-commit" +check_for_diffs "post-merge" + +for file in "$git_toplevel"/scripts/git/* ; do + check_for_script_update "$file" +done + diff --git a/scripts/git/pre-commit.git-hook b/scripts/git/pre-commit.git-hook new file mode 100755 index 0000000000..b285776c04 --- /dev/null +++ b/scripts/git/pre-commit.git-hook @@ -0,0 +1,45 @@ +#!/bin/bash +# +# To install this script, copy it to .git/hooks/pre-commit in local copy of +# tor git repo and make sure it has permission to execute. +# +# This is pre-commit git hook script that prevents commiting your changeset if +# it fails our code formatting or changelog entry formatting checkers. + +workdir=$(git rev-parse --show-toplevel) + +cd "$workdir" || exit 1 + +set -e + +if [ -n "$(ls ./changes/)" ]; then + python scripts/maint/lintChanges.py ./changes/* +fi + +if [ -d src/lib ]; then + # This is the layout in 0.3.5 + perl scripts/maint/checkSpace.pl -C \ + src/lib/*/*.[ch] \ + src/core/*/*.[ch] \ + src/feature/*/*.[ch] \ + src/app/*/*.[ch] \ + src/test/*.[ch] \ + src/test/*/*.[ch] \ + src/tools/*.[ch] +elif [ -d src/common ]; then + # This was the layout before 0.3.5 + perl scripts/maint/checkSpace.pl -C \ + src/common/*/*.[ch] \ + src/or/*/*.[ch] \ + src/test/*.[ch] \ + src/test/*/*.[ch] \ + src/tools/*.[ch] +fi + +if test -e scripts/maint/checkIncludes.py; then + python scripts/maint/checkIncludes.py +fi + +if [ -e scripts/maint/practracker/practracker.py ]; then + python3 ./scripts/maint/practracker/practracker.py "$workdir" +fi diff --git a/scripts/git/pre-push.git-hook b/scripts/git/pre-push.git-hook new file mode 100755 index 0000000000..c9e72a4d43 --- /dev/null +++ b/scripts/git/pre-push.git-hook @@ -0,0 +1,108 @@ +#!/bin/bash + +# git pre-push hook script to: +# 1) prevent "fixup!" and "squash!" commit from ending up in master, release-* +# or maint-* +# 2) Disallow pushing branches other than master, release-* +# and maint-* to origin (e.g. gitweb.torproject.org). +# +# To install this script, copy it into .git/hooks/pre-push path in your +# local copy of git repository. Make sure it has permission to execute. +# Furthermore, make sure that TOR_UPSTREAM_REMOTE_NAME environment +# variable is set to local name of git remote that corresponds to upstream +# repository on e.g. git.torproject.org. +# +# The following sample script was used as starting point: +# https://github.com/git/git/blob/master/templates/hooks--pre-push.sample + +echo "Running pre-push hook" + +z40=0000000000000000000000000000000000000000 + +upstream_name=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"} + +workdir=$(git rev-parse --show-toplevel) +if [ -x "$workdir/.git/hooks/pre-commit" ]; then + if ! "$workdir"/.git/hooks/pre-commit; then + exit 1 + fi +fi + +if [ -e scripts/maint/practracker/practracker.py ]; then + if ! python3 ./scripts/maint/practracker/practracker.py "$workdir"; then + exit 1 + fi +fi + +remote="$1" +remote_loc="$2" + +remote_name=$(git remote --verbose | grep "$2" | awk '{print $1}' | head -n 1) + +if [[ "$remote_name" != "$upstream_name" ]]; then + echo "Not pushing to upstream - refraining from further checks" + exit 0 +fi + +ref_is_upstream_branch() { + if [ "$1" == "refs/heads/master" ] || + [[ "$1" == refs/heads/release-* ]] || + [[ "$1" == refs/heads/maint-* ]] + then + return 1 + fi +} + +# shellcheck disable=SC2034 +while read -r local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # Handle delete + : + else + if [ "$remote_sha" = $z40 ] + then + # New branch, examine all commits + range="$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + if (ref_is_upstream_branch "$local_ref" == 0 || + ref_is_upstream_branch "$remote_ref" == 0) && + [ "$local_ref" != "$remote_ref" ] + then + if [ "$remote" == "origin" ] + then + echo >&2 "Not pushing: $local_ref to $remote_ref" + echo >&2 "If you really want to push this, use --no-verify." + exit 1 + else + continue + fi + fi + + # Check for fixup! commit + commit=$(git rev-list -n 1 --grep '^fixup!' "$range") + if [ -n "$commit" ] + then + echo >&2 "Found fixup! commit in $local_ref, not pushing" + echo >&2 "If you really want to push this, use --no-verify." + exit 1 + fi + + # Check for squash! commit + commit=$(git rev-list -n 1 --grep '^squash!' "$range") + if [ -n "$commit" ] + then + echo >&2 "Found squash! commit in $local_ref, not pushing" + echo >&2 "If you really want to push this, use --no-verify." + exit 1 + fi + fi +done + +exit 0 + diff --git a/scripts/maint/add_c_file.py b/scripts/maint/add_c_file.py new file mode 100755 index 0000000000..499415974f --- /dev/null +++ b/scripts/maint/add_c_file.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python3 + +""" + Add a C file with matching header to the Tor codebase. Creates + both files from templates, and adds them to the right include.am file. + + Example usage: + + % add_c_file.py ./src/feature/dirauth/ocelot.c +""" + +import os +import re +import time + +def topdir_file(name): + """Strip opening "src" from a filename""" + if name.startswith("src/"): + name = name[4:] + return name + +def guard_macro(name): + """Return the guard macro that should be used for the header file 'name'. + """ + td = topdir_file(name).replace(".", "_").replace("/", "_").upper() + return "TOR_{}".format(td) + +def makeext(name, new_extension): + """Replace the extension for the file called 'name' with 'new_extension'. + """ + base = os.path.splitext(name)[0] + return base + "." + new_extension + +def instantiate_template(template, output_fname): + """ + Fill in a template with string using the fields that should be used + for 'output_fname'. + """ + names = { + # The relative location of the header file. + 'header_path' : makeext(topdir_file(output_fname), "h"), + # The relative location of the C file file. + 'c_file_path' : makeext(topdir_file(output_fname), "c"), + # The truncated name of the file. + 'short_name' : os.path.basename(output_fname), + # The current year, for the copyright notice + 'this_year' : time.localtime().tm_year, + # An appropriate guard macro, for the header. + 'guard_macro' : guard_macro(output_fname), + } + + return template.format(**names) + +HEADER_TEMPLATE = """\ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-{this_year}, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file {short_name} + * @brief Header for {c_file_path} + **/ + +#ifndef {guard_macro} +#define {guard_macro} + +#endif /* !defined({guard_macro}) */ +""" + +C_FILE_TEMPLATE = """\ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-{this_year}, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file {short_name} + * @brief DOCDOC + **/ + +#include "orconfig.h" +#include "{header_path}" +""" + +class AutomakeChunk: + """ + Represents part of an automake file. If it is decorated with + an ADD_C_FILE comment, it has a "kind" based on what to add to it. + Otherwise, it only has a bunch of lines in it. + """ + pat = re.compile(r'# ADD_C_FILE: INSERT (\S*) HERE', re.I) + + def __init__(self): + self.lines = [] + self.kind = "" + + def addLine(self, line): + """ + Insert a line into this chunk while parsing the automake file. + """ + m = self.pat.match(line) + if m: + if self.lines: + raise ValueError("control line not preceded by a blank line") + self.kind = m.group(1) + + self.lines.append(line) + if line.strip() == "": + return True + + return False + + def insertMember(self, member): + """ + Add a new member to this chunk. Try to insert it in alphabetical + order with matching indentation, but don't freak out too much if the + source isn't consistent. + + Assumes that this chunk is of the form: + FOOBAR = \ + X \ + Y \ + Z + """ + self.prespace = "\t" + self.postspace = "\t\t" + for lineno, line in enumerate(self.lines): + m = re.match(r'(\s+)(\S+)(\s+)\\', line) + if not m: + continue + prespace, fname, postspace = m.groups() + if fname > member: + self.insert_before(lineno, member, prespace, postspace) + return + self.insert_at_end(member) + + def insert_before(self, lineno, member, prespace, postspace): + self.lines.insert(lineno, + "{}{}{}\\\n".format(prespace, member, postspace)) + + def insert_at_end(self, member, prespace, postspace): + lastline = self.lines[-1] + self.lines[-1] += '{}\\\n'.format(postspace) + self.lines.append("{}{}\n".format(prespace, member)) + + def dump(self, f): + """Write all the lines in this chunk to the file 'f'.""" + for line in self.lines: + f.write(line) + if not line.endswith("\n"): + f.write("\n") + +class ParsedAutomake: + """A sort-of-parsed automake file, with identified chunks into which + headers and c files can be inserted. + """ + def __init__(self): + self.chunks = [] + self.by_type = {} + + def addChunk(self, chunk): + """Add a newly parsed AutomakeChunk to this file.""" + self.chunks.append(chunk) + self.by_type[chunk.kind.lower()] = chunk + + def add_file(self, fname, kind): + """Insert a file of kind 'kind' to the appropriate section of this + file. Return True if we added it. + """ + if kind.lower() in self.by_type: + self.by_type[kind.lower()].insertMember(fname) + return True + else: + return False + + def dump(self, f): + """Write this file into a file 'f'.""" + for chunk in self.chunks: + chunk.dump(f) + +def get_include_am_location(fname): + """Find the right include.am file for introducing a new file. Return None + if we can't guess one. + + Note that this function is imperfect because our include.am layout is + not (yet) consistent. + """ + td = topdir_file(fname) + m = re.match(r'^lib/([a-z0-9_]*)/', td) + if m: + return "src/lib/{}/include.am".format(m.group(1)) + + if re.match(r'^(core|feature|app)/', td): + return "src/core/include.am" + + if re.match(r'^test/', td): + return "src/test/include.am" + + return None + +def run(fn): + """ + Create a new C file and H file corresponding to the filename "fn", and + add them to include.am. + """ + + cf = makeext(fn, "c") + hf = makeext(fn, "h") + + if os.path.exists(cf): + print("{} already exists".format(cf)) + return 1 + if os.path.exists(hf): + print("{} already exists".format(hf)) + return 1 + + with open(cf, 'w') as f: + f.write(instantiate_template(C_FILE_TEMPLATE, cf)) + + with open(hf, 'w') as f: + f.write(instantiate_template(HEADER_TEMPLATE, hf)) + + iam = get_include_am_location(cf) + if iam is None or not os.path.exists(iam): + print("Made files successfully but couldn't identify include.am for {}" + .format(cf)) + return 1 + + amfile = ParsedAutomake() + cur_chunk = AutomakeChunk() + with open(iam) as f: + for line in f: + if cur_chunk.addLine(line): + amfile.addChunk(cur_chunk) + cur_chunk = AutomakeChunk() + amfile.addChunk(cur_chunk) + + amfile.add_file(cf, "sources") + amfile.add_file(hf, "headers") + + with open(iam+".tmp", 'w') as f: + amfile.dump(f) + + os.rename(iam+".tmp", iam) + +if __name__ == '__main__': + import sys + sys.exit(run(sys.argv[1])) diff --git a/scripts/maint/checkIncludes.py b/scripts/maint/checkIncludes.py index 3afd9bbebe..ec9350b9b1 100755 --- a/scripts/maint/checkIncludes.py +++ b/scripts/maint/checkIncludes.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/python # Copyright 2018 The Tor Project, Inc. See LICENSE file for licensing info. """This script looks through all the directories for files matching *.c or diff --git a/scripts/maint/checkSpace.pl b/scripts/maint/checkSpace.pl index 633b47e314..433ae62807 100755 --- a/scripts/maint/checkSpace.pl +++ b/scripts/maint/checkSpace.pl @@ -18,6 +18,8 @@ if ($ARGV[0] =~ /^-/) { our %basenames = (); +our %guardnames = (); + for my $fn (@ARGV) { open(F, "$fn"); my $lastnil = 0; @@ -31,6 +33,10 @@ for my $fn (@ARGV) { } else { $basenames{$basename} = $fn; } + my $isheader = ($fn =~ /\.h/); + my $seenguard = 0; + my $guardname = ""; + while () { ## Warn about windows-style newlines. # (We insist on lines that end with a single LF character, not @@ -112,6 +118,23 @@ for my $fn (@ARGV) { next; } } + + if ($isheader) { + if ($seenguard == 0) { + if (/ifndef\s+(\S+)/) { + ++$seenguard; + $guardname = $1; + } + } elsif ($seenguard == 1) { + if (/^\#define (\S+)/) { + ++$seenguard; + if ($1 ne $guardname) { + msg "GUARD:$fn:$.: Header guard macro mismatch.\n"; + } + } + } + } + if (m!/\*.*?\*/!) { s!\s*/\*.*?\*/!!; } elsif (m!/\*!) { @@ -201,6 +224,15 @@ for my $fn (@ARGV) { } } } + if ($isheader && $C) { + if ($seenguard < 2) { + msg "$fn:No #ifndef/#define header guard pair found.\n"; + } elsif ($guardnames{$guardname}) { + msg "$fn:Guard macro $guardname also used in $guardnames{$guardname}\n"; + } else { + $guardnames{$guardname} = $fn; + } + } close(F); } diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt new file mode 100644 index 0000000000..726dc9c3ef --- /dev/null +++ b/scripts/maint/practracker/exceptions.txt @@ -0,0 +1,289 @@ +# Welcome to the exceptions file for Tor's best-practices tracker! +# +# Each line of this file represents a single violation of Tor's best +# practices -- typically, a violation that we had before practracker.py +# first existed. +# +# There are three kinds of problems that we recognize right now: +# function-size -- a function of more than 100 lines. +# file-size -- a file of more than 3000 lines. +# include-count -- a file with more than 50 #includes. +# +# Each line below represents a single exception that practracker should +# _ignore_. Each line has four parts: +# 1. The word "problem". +# 2. The kind of problem. +# 3. The location of the problem: either a filename, or a +# filename:functionname pair. +# 4. The magnitude of the problem to ignore. +# +# So for example, consider this line: +# problem file-size /src/core/or/connection_or.c 3200 +# +# It tells practracker to allow the mentioned file to be up to 3200 lines +# long, even though ordinarily it would warn about any file with more than +# 3000 lines. +# +# You can either edit this file by hand, or regenerate it completely by +# running `make practracker-regen`. +# +# Remember: It is better to fix the problem than to add a new exception! + +problem file-size /src/app/config/config.c 8518 +problem include-count /src/app/config/config.c 87 +problem function-size /src/app/config/config.c:options_act_reversible() 296 +problem function-size /src/app/config/config.c:options_act() 589 +problem function-size /src/app/config/config.c:resolve_my_address() 192 +problem function-size /src/app/config/config.c:options_validate() 1217 +problem function-size /src/app/config/config.c:options_init_from_torrc() 207 +problem function-size /src/app/config/config.c:options_init_from_string() 173 +problem function-size /src/app/config/config.c:options_init_logs() 146 +problem function-size /src/app/config/config.c:parse_bridge_line() 104 +problem function-size /src/app/config/config.c:parse_transport_line() 191 +problem function-size /src/app/config/config.c:parse_dir_authority_line() 151 +problem function-size /src/app/config/config.c:parse_dir_fallback_line() 102 +problem function-size /src/app/config/config.c:parse_port_config() 452 +problem function-size /src/app/config/config.c:parse_ports() 170 +problem function-size /src/app/config/config.c:getinfo_helper_config() 116 +problem function-size /src/app/config/confparse.c:config_assign_value() 205 +problem function-size /src/app/config/confparse.c:config_get_assigned_option() 129 +problem include-count /src/app/main/main.c 67 +problem function-size /src/app/main/main.c:dumpstats() 102 +problem function-size /src/app/main/main.c:tor_init() 137 +problem function-size /src/app/main/main.c:sandbox_init_filter() 291 +problem function-size /src/app/main/main.c:run_tor_main_loop() 105 +problem function-size /src/app/main/ntmain.c:nt_service_install() 125 +problem file-size /src/core/mainloop/connection.c 5569 +problem include-count /src/core/mainloop/connection.c 62 +problem function-size /src/core/mainloop/connection.c:connection_free_minimal() 185 +problem function-size /src/core/mainloop/connection.c:connection_listener_new() 328 +problem function-size /src/core/mainloop/connection.c:connection_handle_listener_read() 161 +problem function-size /src/core/mainloop/connection.c:connection_connect_sockaddr() 103 +problem function-size /src/core/mainloop/connection.c:connection_proxy_connect() 148 +problem function-size /src/core/mainloop/connection.c:connection_read_proxy_handshake() 153 +problem function-size /src/core/mainloop/connection.c:retry_listener_ports() 116 +problem function-size /src/core/mainloop/connection.c:connection_handle_read_impl() 111 +problem function-size /src/core/mainloop/connection.c:connection_buf_read_from_socket() 181 +problem function-size /src/core/mainloop/connection.c:connection_handle_write_impl() 241 +problem function-size /src/core/mainloop/connection.c:assert_connection_ok() 143 +problem include-count /src/core/mainloop/mainloop.c 63 +problem function-size /src/core/mainloop/mainloop.c:conn_close_if_marked() 108 +problem function-size /src/core/mainloop/mainloop.c:run_connection_housekeeping() 123 +problem file-size /src/core/or/channel.c 3487 +problem function-size /src/core/or/channeltls.c:channel_tls_handle_var_cell() 160 +problem function-size /src/core/or/channeltls.c:channel_tls_process_versions_cell() 170 +problem function-size /src/core/or/channeltls.c:channel_tls_process_netinfo_cell() 214 +problem function-size /src/core/or/channeltls.c:channel_tls_process_certs_cell() 246 +problem function-size /src/core/or/channeltls.c:channel_tls_process_authenticate_cell() 202 +problem include-count /src/core/or/circuitbuild.c 54 +problem function-size /src/core/or/circuitbuild.c:get_unique_circ_id_by_chan() 128 +problem function-size /src/core/or/circuitbuild.c:circuit_extend() 147 +problem function-size /src/core/or/circuitbuild.c:choose_good_exit_server_general() 206 +problem include-count /src/core/or/circuitlist.c 55 +problem function-size /src/core/or/circuitlist.c:HT_PROTOTYPE() 128 +problem function-size /src/core/or/circuitlist.c:circuit_free_() 143 +problem function-size /src/core/or/circuitlist.c:circuit_find_to_cannibalize() 102 +problem function-size /src/core/or/circuitlist.c:circuit_about_to_free() 120 +problem function-size /src/core/or/circuitlist.c:circuits_handle_oom() 117 +problem function-size /src/core/or/circuitmux.c:circuitmux_set_policy() 110 +problem function-size /src/core/or/circuitmux.c:circuitmux_attach_circuit() 114 +problem file-size /src/core/or/circuitpadding.c 3040 +problem function-size /src/core/or/circuitpadding.c:circpad_machine_schedule_padding() 107 +problem function-size /src/core/or/circuitpadding.c:circpad_machine_schedule_padding() 113 +problem function-size /src/core/or/circuitpadding_machines.c:circpad_machine_relay_hide_intro_circuits() 104 +problem function-size /src/core/or/circuitpadding_machines.c:circpad_machine_client_hide_rend_circuits() 112 +problem function-size /src/core/or/circuitstats.c:circuit_build_times_parse_state() 124 +problem file-size /src/core/or/circuituse.c 3162 +problem function-size /src/core/or/circuituse.c:circuit_is_acceptable() 132 +problem function-size /src/core/or/circuituse.c:circuit_expire_building() 394 +problem function-size /src/core/or/circuituse.c:circuit_log_ancient_one_hop_circuits() 126 +problem function-size /src/core/or/circuituse.c:circuit_build_failed() 149 +problem function-size /src/core/or/circuituse.c:circuit_launch_by_extend_info() 110 +problem function-size /src/core/or/circuituse.c:circuit_get_open_circ_or_launch() 354 +problem function-size /src/core/or/circuituse.c:connection_ap_handshake_attach_circuit() 244 +problem function-size /src/core/or/command.c:command_process_create_cell() 156 +problem function-size /src/core/or/command.c:command_process_relay_cell() 132 +problem file-size /src/core/or/connection_edge.c 4595 +problem include-count /src/core/or/connection_edge.c 65 +problem function-size /src/core/or/connection_edge.c:connection_ap_expire_beginning() 117 +problem function-size /src/core/or/connection_edge.c:connection_ap_handshake_rewrite() 192 +problem function-size /src/core/or/connection_edge.c:connection_ap_handle_onion() 188 +problem function-size /src/core/or/connection_edge.c:connection_ap_handshake_rewrite_and_attach() 423 +problem function-size /src/core/or/connection_edge.c:connection_ap_handshake_send_begin() 111 +problem function-size /src/core/or/connection_edge.c:connection_ap_handshake_socks_resolved() 106 +problem function-size /src/core/or/connection_edge.c:connection_exit_begin_conn() 184 +problem function-size /src/core/or/connection_edge.c:connection_exit_connect() 102 +problem file-size /src/core/or/connection_or.c 3124 +problem include-count /src/core/or/connection_or.c 51 +problem function-size /src/core/or/connection_or.c:connection_or_group_set_badness_() 105 +problem function-size /src/core/or/connection_or.c:connection_or_client_learned_peer_id() 144 +problem function-size /src/core/or/connection_or.c:connection_or_compute_authenticate_cell_body() 235 +problem file-size /src/core/or/policies.c 3249 +problem function-size /src/core/or/policies.c:policy_summarize() 107 +problem function-size /src/core/or/protover.c:protover_all_supported() 117 +problem file-size /src/core/or/relay.c 3244 +problem function-size /src/core/or/relay.c:circuit_receive_relay_cell() 127 +problem function-size /src/core/or/relay.c:relay_send_command_from_edge_() 112 +problem function-size /src/core/or/relay.c:connection_ap_process_end_not_open() 194 +problem function-size /src/core/or/relay.c:connection_edge_process_relay_cell_not_open() 139 +problem function-size /src/core/or/relay.c:connection_edge_process_relay_cell() 430 +problem function-size /src/core/or/relay.c:connection_edge_package_raw_inbuf() 129 +problem function-size /src/core/or/relay.c:circuit_resume_edge_reading_helper() 148 +problem function-size /src/core/or/scheduler_kist.c:kist_scheduler_run() 171 +problem function-size /src/core/or/scheduler_vanilla.c:vanilla_scheduler_run() 109 +problem function-size /src/core/or/versions.c:tor_version_parse() 104 +problem function-size /src/core/proto/proto_socks.c:parse_socks_client() 112 +problem function-size /src/feature/client/addressmap.c:addressmap_rewrite() 112 +problem function-size /src/feature/client/bridges.c:rewrite_node_address_for_bridge() 126 +problem function-size /src/feature/client/circpathbias.c:pathbias_measure_close_rate() 108 +problem function-size /src/feature/client/dnsserv.c:evdns_server_callback() 153 +problem file-size /src/feature/client/entrynodes.c 3824 +problem function-size /src/feature/client/entrynodes.c:entry_guards_upgrade_waiting_circuits() 157 +problem function-size /src/feature/client/entrynodes.c:entry_guard_parse_from_state() 246 +problem function-size /src/feature/client/transports.c:handle_proxy_line() 108 +problem function-size /src/feature/client/transports.c:parse_method_line_helper() 112 +problem function-size /src/feature/client/transports.c:create_managed_proxy_environment() 109 +problem function-size /src/feature/control/control.c:connection_control_process_inbuf() 136 +problem function-size /src/feature/control/control_auth.c:handle_control_authchallenge() 103 +problem function-size /src/feature/control/control_auth.c:handle_control_authenticate() 187 +problem function-size /src/feature/control/control_cmd.c:handle_control_extendcircuit() 151 +problem function-size /src/feature/control/control_cmd.c:handle_control_add_onion() 269 +problem function-size /src/feature/control/control_cmd.c:add_onion_helper_keyarg() 125 +problem function-size /src/feature/control/control_events.c:control_event_stream_status() 119 +problem include-count /src/feature/control/control_getinfo.c 54 +problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_misc() 109 +problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_dir() 304 +problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_events() 236 +problem function-size /src/feature/dirauth/bwauth.c:dirserv_read_measured_bandwidths() 124 +problem file-size /src/feature/dirauth/dirvote.c 4726 +problem include-count /src/feature/dirauth/dirvote.c 53 +problem function-size /src/feature/dirauth/dirvote.c:format_networkstatus_vote() 249 +problem function-size /src/feature/dirauth/dirvote.c:networkstatus_compute_bw_weights_v10() 235 +problem function-size /src/feature/dirauth/dirvote.c:networkstatus_compute_consensus() 962 +problem function-size /src/feature/dirauth/dirvote.c:networkstatus_add_detached_signatures() 123 +problem function-size /src/feature/dirauth/dirvote.c:dirvote_add_vote() 162 +problem function-size /src/feature/dirauth/dirvote.c:dirvote_compute_consensuses() 164 +problem function-size /src/feature/dirauth/dirvote.c:dirserv_generate_networkstatus_vote_obj() 293 +problem function-size /src/feature/dirauth/dsigs_parse.c:networkstatus_parse_detached_signatures() 196 +problem function-size /src/feature/dirauth/guardfraction.c:dirserv_read_guardfraction_file_from_str() 110 +problem function-size /src/feature/dirauth/process_descs.c:dirserv_add_descriptor() 125 +problem function-size /src/feature/dirauth/shared_random.c:should_keep_commit() 110 +problem function-size /src/feature/dirauth/voteflags.c:dirserv_compute_performance_thresholds() 172 +problem function-size /src/feature/dircache/consdiffmgr.c:consdiffmgr_cleanup() 115 +problem function-size /src/feature/dircache/consdiffmgr.c:consdiffmgr_rescan_flavor_() 111 +problem function-size /src/feature/dircache/consdiffmgr.c:consensus_diff_worker_threadfn() 132 +problem function-size /src/feature/dircache/dircache.c:handle_get_current_consensus() 166 +problem function-size /src/feature/dircache/dircache.c:directory_handle_command_post() 120 +problem file-size /src/feature/dirclient/dirclient.c 3215 +problem include-count /src/feature/dirclient/dirclient.c 51 +problem function-size /src/feature/dirclient/dirclient.c:directory_get_from_dirserver() 131 +problem function-size /src/feature/dirclient/dirclient.c:directory_initiate_request() 201 +problem function-size /src/feature/dirclient/dirclient.c:directory_send_command() 241 +problem function-size /src/feature/dirclient/dirclient.c:dir_client_decompress_response_body() 114 +problem function-size /src/feature/dirclient/dirclient.c:connection_dir_client_reached_eof() 189 +problem function-size /src/feature/dirclient/dirclient.c:handle_response_fetch_consensus() 105 +problem function-size /src/feature/dircommon/consdiff.c:gen_ed_diff() 204 +problem function-size /src/feature/dircommon/consdiff.c:apply_ed_diff() 159 +problem function-size /src/feature/dirparse/authcert_parse.c:authority_cert_parse_from_string() 182 +problem function-size /src/feature/dirparse/microdesc_parse.c:microdescs_parse_from_string() 169 +problem function-size /src/feature/dirparse/ns_parse.c:routerstatus_parse_entry_from_string() 286 +problem function-size /src/feature/dirparse/ns_parse.c:networkstatus_verify_bw_weights() 389 +problem function-size /src/feature/dirparse/ns_parse.c:networkstatus_parse_vote_from_string() 638 +problem function-size /src/feature/dirparse/parsecommon.c:tokenize_string() 103 +problem function-size /src/feature/dirparse/parsecommon.c:get_next_token() 159 +problem function-size /src/feature/dirparse/routerparse.c:router_parse_entry_from_string() 557 +problem function-size /src/feature/dirparse/routerparse.c:extrainfo_parse_entry_from_string() 210 +problem function-size /src/feature/hibernate/hibernate.c:accounting_parse_options() 109 +problem function-size /src/feature/hs/hs_cell.c:hs_cell_build_establish_intro() 115 +problem function-size /src/feature/hs/hs_cell.c:hs_cell_parse_introduce2() 154 +problem function-size /src/feature/hs/hs_client.c:send_introduce1() 104 +problem function-size /src/feature/hs/hs_client.c:hs_config_client_authorization() 108 +problem function-size /src/feature/hs/hs_common.c:hs_get_responsible_hsdirs() 104 +problem function-size /src/feature/hs/hs_config.c:config_generic_service() 140 +problem function-size /src/feature/hs/hs_descriptor.c:desc_encode_v3() 104 +problem function-size /src/feature/hs/hs_descriptor.c:decrypt_desc_layer() 110 +problem function-size /src/feature/hs/hs_descriptor.c:decode_introduction_point() 122 +problem function-size /src/feature/hs/hs_descriptor.c:desc_decode_superencrypted_v3() 109 +problem function-size /src/feature/hs/hs_descriptor.c:desc_decode_encrypted_v3() 109 +problem file-size /src/feature/hs/hs_service.c 4109 +problem function-size /src/feature/keymgt/loadkey.c:ed_key_init_from_file() 333 +problem function-size /src/feature/nodelist/authcert.c:trusted_dirs_load_certs_from_string() 124 +problem function-size /src/feature/nodelist/authcert.c:authority_certs_fetch_missing() 296 +problem function-size /src/feature/nodelist/fmt_routerstatus.c:routerstatus_format_entry() 166 +problem function-size /src/feature/nodelist/microdesc.c:microdesc_cache_rebuild() 134 +problem include-count /src/feature/nodelist/networkstatus.c 62 +problem function-size /src/feature/nodelist/networkstatus.c:networkstatus_check_consensus_signature() 176 +problem function-size /src/feature/nodelist/networkstatus.c:networkstatus_set_current_consensus() 293 +problem function-size /src/feature/nodelist/node_select.c:router_pick_directory_server_impl() 123 +problem function-size /src/feature/nodelist/node_select.c:compute_weighted_bandwidths() 206 +problem function-size /src/feature/nodelist/node_select.c:router_pick_trusteddirserver_impl() 114 +problem function-size /src/feature/nodelist/nodelist.c:compute_frac_paths_available() 193 +problem file-size /src/feature/nodelist/routerlist.c 3238 +problem function-size /src/feature/nodelist/routerlist.c:router_rebuild_store() 148 +problem function-size /src/feature/nodelist/routerlist.c:router_add_to_routerlist() 169 +problem function-size /src/feature/nodelist/routerlist.c:routerlist_remove_old_routers() 121 +problem function-size /src/feature/nodelist/routerlist.c:update_consensus_router_descriptor_downloads() 136 +problem function-size /src/feature/nodelist/routerlist.c:update_extrainfo_downloads() 103 +problem function-size /src/feature/relay/dns.c:dns_resolve_impl() 134 +problem function-size /src/feature/relay/dns.c:configure_nameservers() 161 +problem function-size /src/feature/relay/dns.c:evdns_callback() 109 +problem file-size /src/feature/relay/router.c 3407 +problem include-count /src/feature/relay/router.c 56 +problem function-size /src/feature/relay/router.c:init_keys() 252 +problem function-size /src/feature/relay/router.c:get_my_declared_family() 114 +problem function-size /src/feature/relay/router.c:router_build_fresh_unsigned_routerinfo() 136 +problem function-size /src/feature/relay/router.c:router_dump_router_to_string() 371 +problem function-size /src/feature/relay/router.c:extrainfo_dump_to_string() 206 +problem function-size /src/feature/relay/routerkeys.c:load_ed_keys() 294 +problem function-size /src/feature/rend/rendcache.c:rend_cache_store_v2_desc_as_client() 193 +problem function-size /src/feature/rend/rendclient.c:rend_client_send_introduction() 220 +problem function-size /src/feature/rend/rendcommon.c:rend_encode_v2_descriptors() 225 +problem function-size /src/feature/rend/rendmid.c:rend_mid_establish_intro_legacy() 104 +problem function-size /src/feature/rend/rendparse.c:rend_parse_v2_service_descriptor() 187 +problem function-size /src/feature/rend/rendparse.c:rend_decrypt_introduction_points() 104 +problem function-size /src/feature/rend/rendparse.c:rend_parse_introduction_points() 131 +problem file-size /src/feature/rend/rendservice.c 4511 +problem function-size /src/feature/rend/rendservice.c:rend_service_prune_list_impl_() 107 +problem function-size /src/feature/rend/rendservice.c:rend_config_service() 164 +problem function-size /src/feature/rend/rendservice.c:rend_service_load_auth_keys() 178 +problem function-size /src/feature/rend/rendservice.c:rend_service_receive_introduction() 332 +problem function-size /src/feature/rend/rendservice.c:rend_service_parse_intro_for_v3() 115 +problem function-size /src/feature/rend/rendservice.c:rend_service_decrypt_intro() 115 +problem function-size /src/feature/rend/rendservice.c:rend_service_intro_has_opened() 126 +problem function-size /src/feature/rend/rendservice.c:rend_service_rendezvous_has_opened() 117 +problem function-size /src/feature/rend/rendservice.c:directory_post_to_hs_dir() 108 +problem function-size /src/feature/rend/rendservice.c:upload_service_descriptor() 111 +problem function-size /src/feature/rend/rendservice.c:rend_consider_services_intro_points() 170 +problem function-size /src/feature/stats/rephist.c:rep_hist_load_mtbf_data() 185 +problem function-size /src/feature/stats/rephist.c:rep_hist_format_exit_stats() 148 +problem function-size /src/lib/compress/compress.c:tor_compress_impl() 133 +problem function-size /src/lib/compress/compress_zstd.c:tor_zstd_compress_process() 126 +problem function-size /src/lib/container/smartlist.c:smartlist_bsearch_idx() 109 +problem function-size /src/lib/crypt_ops/crypto_rand.c:crypto_strongest_rand_syscall() 102 +problem function-size /src/lib/encoding/binascii.c:base64_encode() 107 +problem function-size /src/lib/encoding/confline.c:parse_config_line_from_str_verbose() 119 +problem function-size /src/lib/encoding/cstring.c:unescape_string() 108 +problem function-size /src/lib/fs/dir.c:check_private_dir() 231 +problem function-size /src/lib/log/log.c:parse_log_severity_config() 101 +problem function-size /src/lib/math/prob_distr.c:sample_uniform_interval() 145 +problem function-size /src/lib/net/address.c:tor_addr_parse_mask_ports() 198 +problem function-size /src/lib/net/address.c:tor_addr_compare_masked() 111 +problem function-size /src/lib/net/inaddr.c:tor_inet_pton() 107 +problem function-size /src/lib/net/resolve.c:tor_addr_lookup() 110 +problem function-size /src/lib/net/socketpair.c:tor_ersatz_socketpair() 102 +problem function-size /src/lib/osinfo/uname.c:get_uname() 116 +problem function-size /src/lib/process/process_unix.c:process_unix_exec() 220 +problem function-size /src/lib/process/process_win32.c:process_win32_exec() 133 +problem function-size /src/lib/process/process_win32.c:process_win32_create_pipe() 112 +problem function-size /src/lib/process/restrict.c:set_max_file_descriptors() 102 +problem function-size /src/lib/process/setuid.c:switch_id() 156 +problem function-size /src/lib/sandbox/sandbox.c:prot_strings() 104 +problem function-size /src/lib/string/scanf.c:tor_vsscanf() 112 +problem function-size /src/lib/tls/tortls_nss.c:tor_tls_context_new() 153 +problem function-size /src/lib/tls/tortls_openssl.c:tor_tls_context_new() 171 +problem function-size /src/lib/tls/x509_nss.c:tor_tls_create_certificate_internal() 126 +problem function-size /src/tools/tor-gencert.c:parse_commandline() 111 +problem function-size /src/tools/tor-resolve.c:build_socks5_resolve_request() 104 +problem function-size /src/tools/tor-resolve.c:do_resolve() 174 +problem function-size /src/tools/tor-resolve.c:main() 112 + diff --git a/scripts/maint/practracker/metrics.py b/scripts/maint/practracker/metrics.py new file mode 100644 index 0000000000..5fa305a868 --- /dev/null +++ b/scripts/maint/practracker/metrics.py @@ -0,0 +1,50 @@ +#!/usr/bin/python + +# Implementation of various source code metrics. +# 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. + +import re + +def get_file_len(f): + """Get file length of file""" + for i, l in enumerate(f): + pass + return i + 1 + +def get_include_count(f): + """Get number of #include statements in the file""" + include_count = 0 + for line in f: + if re.match(r' *# *include', line): + include_count += 1 + return include_count + +def get_function_lines(f): + """ + Return iterator which iterates over functions and returns (function name, function lines) + """ + + # Skip lines that look like they are defining functions with these + # names: they aren't real function definitions. + REGEXP_CONFUSE_TERMS = {"MOCK_IMPL", "ENABLE_GCC_WARNINGS", "ENABLE_GCC_WARNING", "DUMMY_TYPECHECK_INSTANCE", + "DISABLE_GCC_WARNING", "DISABLE_GCC_WARNINGS"} + + in_function = False + for lineno, line in enumerate(f): + if not in_function: + # find the start of a function + m = re.match(r'^([a-zA-Z_][a-zA-Z_0-9]*),?\(', line) + if m: + func_name = m.group(1) + if func_name in REGEXP_CONFUSE_TERMS: + continue + func_start = lineno + in_function = True + + else: + # Find the end of a function + if line.startswith("}"): + n_lines = lineno - func_start + in_function = False + yield (func_name, n_lines) diff --git a/scripts/maint/practracker/practracker.py b/scripts/maint/practracker/practracker.py new file mode 100755 index 0000000000..febb14639d --- /dev/null +++ b/scripts/maint/practracker/practracker.py @@ -0,0 +1,216 @@ +#!/usr/bin/python + +""" +Best-practices tracker for Tor source code. + +Go through the various .c files and collect metrics about them. If the metrics +violate some of our best practices and they are not found in the optional +exceptions file, then log a problem about them. + +We currently do metrics about file size, function size and number of includes. + +practracker.py should be run with its second argument pointing to the Tor +top-level source directory like this: + $ python3 ./scripts/maint/practracker/practracker.py . + +To regenerate the exceptions file so that it allows all current +problems in the Tor source, use the --regen flag: + $ python3 --regen ./scripts/maint/practracker/practracker.py . +""" + +from __future__ import print_function + +import os, sys + +import metrics +import util +import problem + +# The filename of the exceptions file (it should be placed in the practracker directory) +EXCEPTIONS_FNAME = "./exceptions.txt" + +# Recommended file size +MAX_FILE_SIZE = 3000 # lines +# Recommended function size +MAX_FUNCTION_SIZE = 100 # lines +# Recommended number of #includes +MAX_INCLUDE_COUNT = 50 + +####################################################### + +# ProblemVault singleton +ProblemVault = None + +# The Tor source code topdir +TOR_TOPDIR = None + +####################################################### + +if sys.version_info[0] <= 2: + def open_file(fname): + return open(fname, 'r') +else: + def open_file(fname): + return open(fname, 'r', encoding='utf-8') + +def consider_file_size(fname, f): + """Consider file size issues for 'f' and return True if a new issue was found""" + file_size = metrics.get_file_len(f) + if file_size > MAX_FILE_SIZE: + p = problem.FileSizeProblem(fname, file_size) + return ProblemVault.register_problem(p) + return False + +def consider_includes(fname, f): + """Consider #include issues for 'f' and return True if a new issue was found""" + include_count = metrics.get_include_count(f) + + if include_count > MAX_INCLUDE_COUNT: + p = problem.IncludeCountProblem(fname, include_count) + return ProblemVault.register_problem(p) + return False + +def consider_function_size(fname, f): + """Consider the function sizes for 'f' and return True if a new issue was found""" + found_new_issues = False + + for name, lines in metrics.get_function_lines(f): + # Don't worry about functions within our limits + if lines <= MAX_FUNCTION_SIZE: + continue + + # That's a big function! Issue a problem! + canonical_function_name = "%s:%s()" % (fname, name) + p = problem.FunctionSizeProblem(canonical_function_name, lines) + found_new_issues |= ProblemVault.register_problem(p) + + return found_new_issues + +####################################################### + +def consider_all_metrics(files_list): + """Consider metrics for all files, and return True if new issues were found""" + found_new_issues = False + for fname in files_list: + with open_file(fname) as f: + found_new_issues |= consider_metrics_for_file(fname, f) + return found_new_issues + +def consider_metrics_for_file(fname, f): + """ + Consider the various metrics for file with filename 'fname' and file descriptor 'f'. + Return True if we found new issues. + """ + # Strip the useless part of the path + if fname.startswith(TOR_TOPDIR): + fname = fname[len(TOR_TOPDIR):] + + found_new_issues = False + + # Get file length + found_new_issues |= consider_file_size(fname, f) + + # Consider number of #includes + f.seek(0) + found_new_issues |= consider_includes(fname, f) + + # Get function length + f.seek(0) + found_new_issues |= consider_function_size(fname, f) + + return found_new_issues + +HEADER="""\ +# Welcome to the exceptions file for Tor's best-practices tracker! +# +# Each line of this file represents a single violation of Tor's best +# practices -- typically, a violation that we had before practracker.py +# first existed. +# +# There are three kinds of problems that we recognize right now: +# function-size -- a function of more than {MAX_FUNCTION_SIZE} lines. +# file-size -- a file of more than {MAX_FILE_SIZE} lines. +# include-count -- a file with more than {MAX_INCLUDE_COUNT} #includes. +# +# Each line below represents a single exception that practracker should +# _ignore_. Each line has four parts: +# 1. The word "problem". +# 2. The kind of problem. +# 3. The location of the problem: either a filename, or a +# filename:functionname pair. +# 4. The magnitude of the problem to ignore. +# +# So for example, consider this line: +# problem file-size /src/core/or/connection_or.c 3200 +# +# It tells practracker to allow the mentioned file to be up to 3200 lines +# long, even though ordinarily it would warn about any file with more than +# {MAX_FILE_SIZE} lines. +# +# You can either edit this file by hand, or regenerate it completely by +# running `make practracker-regen`. +# +# Remember: It is better to fix the problem than to add a new exception! + +""".format(**globals()) + +def main(argv): + import argparse + + progname = argv[0] + parser = argparse.ArgumentParser(prog=progname) + parser.add_argument("--regen", action="store_true", + help="Regenerate the exceptions file") + parser.add_argument("--exceptions", + help="Override the location for the exceptions file") + parser.add_argument("topdir", default=".", nargs="?", + help="Top-level directory for the tor source") + args = parser.parse_args(argv[1:]) + + global TOR_TOPDIR + TOR_TOPDIR = args.topdir + if args.exceptions: + exceptions_file = args.exceptions + else: + exceptions_file = os.path.join(TOR_TOPDIR, "scripts/maint/practracker", EXCEPTIONS_FNAME) + + # 1) Get all the .c files we care about + files_list = util.get_tor_c_files(TOR_TOPDIR) + + # 2) Initialize problem vault and load an optional exceptions file so that + # we don't warn about the past + global ProblemVault + + if args.regen: + tmpname = exceptions_file + ".tmp" + tmpfile = open(tmpname, "w") + sys.stdout = tmpfile + sys.stdout.write(HEADER) + ProblemVault = problem.ProblemVault() + else: + ProblemVault = problem.ProblemVault(exceptions_file) + + # 3) Go through all the files and report problems if they are not exceptions + found_new_issues = consider_all_metrics(files_list) + + if args.regen: + tmpfile.close() + os.rename(tmpname, exceptions_file) + sys.exit(0) + + # If new issues were found, try to give out some advice to the developer on how to resolve it. + if found_new_issues and not args.regen: + new_issues_str = """\ +FAILURE: practracker found new problems in the code: see warnings above. + +Please fix the problems if you can, and update the exceptions file +({}) if you can't. + +See doc/HACKING/HelpfulTools.md for more information on using practracker.\ +""".format(exceptions_file) + print(new_issues_str) + + sys.exit(found_new_issues) + +if __name__ == '__main__': + main(sys.argv) diff --git a/scripts/maint/practracker/practracker_tests.py b/scripts/maint/practracker/practracker_tests.py new file mode 100755 index 0000000000..cdbab2908e --- /dev/null +++ b/scripts/maint/practracker/practracker_tests.py @@ -0,0 +1,50 @@ +"""Some simple tests for practracker metrics""" + +import unittest + +import StringIO + +import metrics + +function_file = """static void +fun(directory_request_t *req, const char *resource) +{ + time_t if_modified_since = 0; + uint8_t or_diff_from[DIGEST256_LEN]; +} + +static void +fun(directory_request_t *req, + const char *resource) +{ + time_t if_modified_since = 0; + uint8_t or_diff_from[DIGEST256_LEN]; +} + +MOCK_IMPL(void, +fun,( + uint8_t dir_purpose, + uint8_t router_purpose, + const char *resource, + int pds_flags, + download_want_authority_t want_authority)) +{ + const routerstatus_t *rs = NULL; + const or_options_t *options = get_options(); +} +""" + +class TestFunctionLength(unittest.TestCase): + def test_function_length(self): + funcs = StringIO.StringIO(function_file) + # All functions should have length 2 + for name, lines in metrics.function_lines(funcs): + self.assertEqual(name, "fun") + + funcs.seek(0) + + for name, lines in metrics.function_lines(funcs): + self.assertEqual(lines, 2) + +if __name__ == '__main__': + unittest.main() diff --git a/scripts/maint/practracker/problem.py b/scripts/maint/practracker/problem.py new file mode 100644 index 0000000000..c82c5db572 --- /dev/null +++ b/scripts/maint/practracker/problem.py @@ -0,0 +1,158 @@ +""" +In this file we define a ProblemVault class where we store all the +exceptions and all the problems we find with the code. + +The ProblemVault is capable of registering problems and also figuring out if a +problem is worse than a registered exception so that it only warns when things +get worse. +""" + +from __future__ import print_function + +import os.path +import re +import sys + +class ProblemVault(object): + """ + Singleton where we store the various new problems we + found in the code, and also the old problems we read from the exception + file. + """ + def __init__(self, exception_fname=None): + # Exception dictionary: { problem.key() : Problem object } + self.exceptions = {} + + if exception_fname == None: + return + + try: + with open(exception_fname, 'r') as exception_f: + self.register_exceptions(exception_f) + except IOError: + print("No exception file provided", file=sys.stderr) + + def register_exceptions(self, exception_file): + # Register exceptions + for lineno, line in enumerate(exception_file, 1): + try: + problem = get_old_problem_from_exception_str(line) + except ValueError as v: + print("Exception file line {} not recognized: {}" + .format(lineno,v), + file=sys.stderr) + continue + + if problem is None: + continue + + # Fail if we see dup exceptions. There is really no reason to have dup exceptions. + if problem.key() in self.exceptions: + print("Duplicate exceptions lines found in exception file:\n\t{}\n\t{}\nAborting...".format(problem, self.exceptions[problem.key()]), + file=sys.stderr) + sys.exit(1) + + self.exceptions[problem.key()] = problem + #print "Registering exception: %s" % problem + + def register_problem(self, problem): + """ + Register this problem to the problem value. Return True if it was a new + problem or it worsens an already existing problem. + """ + # This is a new problem, print it + if problem.key() not in self.exceptions: + print(problem) + return True + + # If it's an old problem, we don't warn if the situation got better + # (e.g. we went from 4k LoC to 3k LoC), but we do warn if the + # situation worsened (e.g. we went from 60 includes to 80). + if problem.is_worse_than(self.exceptions[problem.key()]): + print(problem) + return True + + return False + +class Problem(object): + """ + A generic problem in our source code. See the subclasses below for the + specific problems we are trying to tackle. + """ + def __init__(self, problem_type, problem_location, metric_value): + self.problem_location = problem_location + self.metric_value = int(metric_value) + self.problem_type = problem_type + + def is_worse_than(self, other_problem): + """Return True if this is a worse problem than other_problem""" + if self.metric_value > other_problem.metric_value: + return True + return False + + def key(self): + """Generate a unique key that describes this problem that can be used as a dictionary key""" + # Problem location is a filesystem path, so we need to normalize this + # across platforms otherwise same paths are not gonna match. + canonical_location = os.path.normcase(self.problem_location) + return "%s:%s" % (canonical_location, self.problem_type) + + def __str__(self): + return "problem %s %s %s" % (self.problem_type, self.problem_location, self.metric_value) + +class FileSizeProblem(Problem): + """ + Denotes a problem with the size of a .c file. + + The 'problem_location' is the filesystem path of the .c file, and the + 'metric_value' is the number of lines in the .c file. + """ + def __init__(self, problem_location, metric_value): + super(FileSizeProblem, self).__init__("file-size", problem_location, metric_value) + +class IncludeCountProblem(Problem): + """ + Denotes a problem with the number of #includes in a .c file. + + The 'problem_location' is the filesystem path of the .c file, and the + 'metric_value' is the number of #includes in the .c file. + """ + def __init__(self, problem_location, metric_value): + super(IncludeCountProblem, self).__init__("include-count", problem_location, metric_value) + +class FunctionSizeProblem(Problem): + """ + Denotes a problem with a size of a function in a .c file. + + The 'problem_location' is ":()" where is the + filesystem path of the .c file and is the name of the offending + function. + + The 'metric_value' is the size of the offending function in lines. + """ + def __init__(self, problem_location, metric_value): + super(FunctionSizeProblem, self).__init__("function-size", problem_location, metric_value) + +comment_re = re.compile(r'#.*$') + +def get_old_problem_from_exception_str(exception_str): + orig_str = exception_str + exception_str = comment_re.sub("", exception_str) + fields = exception_str.split() + if len(fields) == 0: + # empty line or comment + return None + elif len(fields) == 4: + # valid line + _, problem_type, problem_location, metric_value = fields + else: + raise ValueError("Misformatted line {!r}".format(orig_str)) + + if problem_type == "file-size": + return FileSizeProblem(problem_location, metric_value) + elif problem_type == "include-count": + return IncludeCountProblem(problem_location, metric_value) + elif problem_type == "function-size": + return FunctionSizeProblem(problem_location, metric_value) + else: + raise ValueError("Unknown exception type {!r}".format(orig_str)) diff --git a/scripts/maint/practracker/util.py b/scripts/maint/practracker/util.py new file mode 100644 index 0000000000..b0ca73b997 --- /dev/null +++ b/scripts/maint/practracker/util.py @@ -0,0 +1,28 @@ +import os + +# We don't want to run metrics for unittests, automatically-generated C files, +# external libraries or git leftovers. +EXCLUDE_SOURCE_DIRS = {"/src/test/", "/src/trunnel/", "/src/ext/", "/.git/"} + +def get_tor_c_files(tor_topdir): + """ + Return a list with the .c filenames we want to get metrics of. + """ + files_list = [] + + for root, directories, filenames in os.walk(tor_topdir): + directories.sort() + filenames.sort() + for filename in filenames: + # We only care about .c files + if not filename.endswith(".c"): + continue + + # Exclude the excluded paths + full_path = os.path.join(root,filename) + if any(os.path.normcase(exclude_dir) in full_path for exclude_dir in EXCLUDE_SOURCE_DIRS): + continue + + files_list.append(full_path) + + return files_list diff --git a/scripts/maint/pre-commit.git-hook b/scripts/maint/pre-commit.git-hook deleted file mode 100755 index b4c4ce2061..0000000000 --- a/scripts/maint/pre-commit.git-hook +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -# -# To install this script, copy it to .git/hooks/pre-commit in local copy of -# tor git repo and make sure it has permission to execute. -# -# This is pre-commit git hook script that prevents commiting your changeset if -# it fails our code formatting or changelog entry formatting checkers. - -workdir=$(git rev-parse --show-toplevel) - -cd "$workdir" || exit 1 - -python scripts/maint/lintChanges.py ./changes/* - -perl scripts/maint/checkSpace.pl -C \ -src/lib/*/*.[ch] \ -src/core/*/*.[ch] \ -src/feature/*/*.[ch] \ -src/app/*/*.[ch] \ -src/test/*.[ch] \ -src/test/*/*.[ch] \ -src/tools/*.[ch] - -if test -e scripts/maint/checkIncludes.py; then - python scripts/maint/checkIncludes.py -fi diff --git a/scripts/maint/pre-push.git-hook b/scripts/maint/pre-push.git-hook deleted file mode 100755 index 26296023fb..0000000000 --- a/scripts/maint/pre-push.git-hook +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash - -# To install this script, copy it into .git/hooks/pre-push path in your -# local copy of git repository. Make sure it has permission to execute. -# -# This is git pre-push hook script to prevent "fixup!" and "squash!" commits -# from ending up in upstream branches (master, release-* or maint-*). -# -# The following sample script was used as starting point: -# https://github.com/git/git/blob/master/templates/hooks--pre-push.sample - -z40=0000000000000000000000000000000000000000 - -CUR_BRANCH=$(git rev-parse --abbrev-ref HEAD) -if [ "$CUR_BRANCH" != "master" ] && [[ $CUR_BRANCH != release-* ]] && - [[ $CUR_BRANCH != maint-* ]] -then - exit 0 -fi - -echo "Running pre-push hook" - -# shellcheck disable=SC2034 -while read -r local_ref local_sha remote_ref remote_sha -do - if [ "$local_sha" = $z40 ] - then - # Handle delete - : - else - if [ "$remote_sha" = $z40 ] - then - # New branch, examine all commits - range="$local_sha" - else - # Update to existing branch, examine new commits - range="$remote_sha..$local_sha" - fi - - # Check for fixup! commit - commit=$(git rev-list -n 1 --grep '^fixup!' "$range") - if [ -n "$commit" ] - then - echo >&2 "Found fixup! commit in $local_ref, not pushing" - echo >&2 "If you really want to push this, use --no-verify." - exit 1 - fi - - # Check for squash! commit - commit=$(git rev-list -n 1 --grep '^squash!' "$range") - if [ -n "$commit" ] - then - echo >&2 "Found squash! commit in $local_ref, not pushing" - echo >&2 "If you really want to push this, use --no-verify." - exit 1 - fi - fi -done - -exit 0 - diff --git a/scripts/maint/rectify_include_paths.py b/scripts/maint/rectify_include_paths.py index 401fadae6d..1140e8cd22 100755 --- a/scripts/maint/rectify_include_paths.py +++ b/scripts/maint/rectify_include_paths.py @@ -1,8 +1,12 @@ -#!/usr/bin/python3 +#!/usr/bin/python import os import os.path import re +import sys + +def warn(msg): + sys.stderr.write("WARNING: %s\n"%msg) # Find all the include files, map them to their real names. @@ -11,6 +15,8 @@ def exclude(paths, dirnames): if p in dirnames: dirnames.remove(p) +DUPLICATE = object() + def get_include_map(): includes = { } @@ -19,7 +25,10 @@ def get_include_map(): for fname in fnames: if fname.endswith(".h"): - assert fname not in includes + if fname in includes: + warn("Multiple headers named %s"%fname) + includes[fname] = DUPLICATE + continue include = os.path.join(dirpath, fname) assert include.startswith("src/") includes[fname] = include[4:] @@ -37,7 +46,7 @@ def fix_includes(inp, out, mapping): if m: include,hdr,rest = m.groups() basehdr = get_base_header_name(hdr) - if basehdr in mapping: + if basehdr in mapping and mapping[basehdr] is not DUPLICATE: out.write('{}{}{}\n'.format(include,mapping[basehdr],rest)) continue diff --git a/scripts/maint/updateCopyright.pl b/scripts/maint/updateCopyright.pl index 36894b1baf..6800032f87 100755 --- a/scripts/maint/updateCopyright.pl +++ b/scripts/maint/updateCopyright.pl @@ -1,7 +1,9 @@ #!/usr/bin/perl -i -w -p -$NEWYEAR=2019; +@now = gmtime(); -s/Copyright(.*) (201[^9]), The Tor Project/Copyright$1 $2-${NEWYEAR}, The Tor Project/; +$NEWYEAR=$now[5]+1900; + +s/Copyright([^-]*) (20[^-]*), The Tor Project/Copyright$1 $2-${NEWYEAR}, The Tor Project/; s/Copyright(.*)-(20..), The Tor Project/Copyright$1-${NEWYEAR}, The Tor Project/; diff --git a/scripts/test/cov-diff b/scripts/test/cov-diff index f3ca856888..8751800966 100755 --- a/scripts/test/cov-diff +++ b/scripts/test/cov-diff @@ -16,6 +16,5 @@ for B in "$DIRB"/*; do fi perl -pe 's/^\s*\!*\d+(\*?):/ 1$1:/; s/^([^:]+:)[\d\s]+:/$1/; s/^ *-:(Runs|Programs):.*//;' "$B" > "$B.tmp" diff -u "$A.tmp" "$B.tmp" |perl -pe 's/^((?:\+\+\+|---)(?:.*tmp))\s+.*/$1/;' - rm "$A.tmp" "$B.tmp" + rm -f "$A.tmp" "$B.tmp" done - diff --git a/scripts/test/cov-test-determinism.sh b/scripts/test/cov-test-determinism.sh new file mode 100755 index 0000000000..3458f96968 --- /dev/null +++ b/scripts/test/cov-test-determinism.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +# To use this script, build Tor with coverage enabled, and then say: +# ./scripts/test/cov-test-determinism.sh run +# +# Let it run for a long time so it can run the tests over and over. It +# will put their coverage outputs in coverage-raw/coverage-*/. +# +# Then say: +# ./scripts/test/cov-test-determinism.sh check +# +# It will diff the other coverage outputs to the first one, and put their +# diffs in coverage-raw/diff-coverage-*. + +run=0 +check=0 + +if test "$1" = run; then + run=1 +elif test "$1" = check; then + check=1 +else + echo "First use 'run' with this script, then use 'check'." + exit 1 +fi + +if test "$run" = 1; then + # same seed as in travis.yml + TOR_TEST_RNG_SEED="636f766572616765" + export TOR_TEST_RNG_SEED + while true; do + make reset-gcov + CD=coverage-raw/coverage-$(date +%s) + make -j5 check + mkdir -p "$CD" + ./scripts/test/coverage "$CD" + done +fi + +if test "$check" = 1; then + cd coverage-raw || exit 1 + + FIRST="$(find . -name "coverage-*" -type d | head -1)" + rm -f A + ln -sf "$FIRST" A + for dir in coverage-*; do + rm -f B + ln -sf "$dir" B + ../scripts/test/cov-diff A B > "diff-$dir" + done +fi diff --git a/src/app/config/auth_dirs.inc b/src/app/config/auth_dirs.inc index 08a919b053..278f08bfcf 100644 --- a/src/app/config/auth_dirs.inc +++ b/src/app/config/auth_dirs.inc @@ -7,7 +7,7 @@ "86.59.21.38:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D", "dizum orport=443 " "v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 " - "194.109.206.212:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755", + "45.66.33.45:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755", "Serge orport=9001 bridge " "66.111.2.131:9030 BA44 A889 E64B 93FA A2B1 14E0 2C2A 279A 8555 C533", "gabelmoo orport=443 " diff --git a/src/app/config/config.c b/src/app/config/config.c index 0d5cc33956..a061871748 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -86,6 +86,8 @@ #include "feature/client/entrynodes.h" #include "feature/client/transports.h" #include "feature/control/control.h" +#include "feature/control/control_auth.h" +#include "feature/control/control_events.h" #include "feature/dirauth/bwauth.h" #include "feature/dirauth/guardfraction.h" #include "feature/dircache/consdiffmgr.h" @@ -154,6 +156,7 @@ #include "lib/evloop/procmon.h" #include "feature/dirauth/dirvote.h" +#include "feature/dirauth/dirauth_periodic.h" #include "feature/dirauth/recommend_pkg.h" #include "feature/dirauth/authmode.h" @@ -594,6 +597,8 @@ static config_var_t option_vars_[] = { V(ReducedConnectionPadding, BOOL, "0"), V(ConnectionPadding, AUTOBOOL, "auto"), V(RefuseUnknownExits, AUTOBOOL, "auto"), + V(CircuitPadding, BOOL, "1"), + V(ReducedCircuitPadding, BOOL, "0"), V(RejectPlaintextPorts, CSV, ""), V(RelayBandwidthBurst, MEMUNIT, "0"), V(RelayBandwidthRate, MEMUNIT, "0"), @@ -2382,7 +2387,8 @@ options_act(const or_options_t *old_options) if (!bool_eq(directory_fetches_dir_info_early(options), directory_fetches_dir_info_early(old_options)) || !bool_eq(directory_fetches_dir_info_later(options), - directory_fetches_dir_info_later(old_options))) { + directory_fetches_dir_info_later(old_options)) || + !config_lines_eq(old_options->Bridges, options->Bridges)) { /* Make sure update_router_have_minimum_dir_info() gets called. */ router_dir_info_changed(); /* We might need to download a new consensus status later or sooner than @@ -3545,7 +3551,7 @@ options_validate(or_options_t *old_options, or_options_t *options, tor_free(t); t = format_recommended_version_list(options->RecommendedServerVersions, 1); tor_free(t); -#endif +#endif /* defined(HAVE_MODULE_DIRAUTH) */ if (options->UseEntryGuards) { log_info(LD_CONFIG, "Authoritative directory servers can't set " @@ -3561,6 +3567,7 @@ options_validate(or_options_t *old_options, or_options_t *options, options->V3AuthoritativeDir)) REJECT("AuthoritativeDir is set, but none of " "(Bridge/V3)AuthoritativeDir is set."); +#ifdef HAVE_MODULE_DIRAUTH /* If we have a v3bandwidthsfile and it's broken, complain on startup */ if (options->V3BandwidthsFile && !old_options) { dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL, NULL, @@ -3570,6 +3577,7 @@ options_validate(or_options_t *old_options, or_options_t *options, if (options->GuardfractionFile && !old_options) { dirserv_read_guardfraction_file(options->GuardfractionFile, NULL); } +#endif /* defined(HAVE_MODULE_DIRAUTH) */ } if (options->AuthoritativeDir && !options->DirPort_set) @@ -3747,6 +3755,14 @@ options_validate(or_options_t *old_options, or_options_t *options, REJECT("Relays cannot set ReducedConnectionPadding. "); } + if (server_mode(options) && options->CircuitPadding == 0) { + REJECT("Relays cannot set CircuitPadding to 0. "); + } + + if (server_mode(options) && options->ReducedCircuitPadding == 1) { + REJECT("Relays cannot set ReducedCircuitPadding. "); + } + if (options->BridgeDistribution) { if (!options->BridgeRelay) { REJECT("You set BridgeDistribution, but you didn't set BridgeRelay!"); @@ -4197,6 +4213,10 @@ options_validate(or_options_t *old_options, or_options_t *options, "You should also make sure you aren't listing this bridge's " "fingerprint in any other MyFamily."); } + if (options->MyFamily_lines && !options->ContactInfo) { + log_warn(LD_CONFIG, "MyFamily is set but ContactInfo is not configured. " + "ContactInfo should always be set when MyFamily option is too."); + } if (normalize_nickname_list(&options->MyFamily, options->MyFamily_lines, "MyFamily", msg)) return -1; @@ -4585,7 +4605,7 @@ compute_real_max_mem_in_queues(const uint64_t val, int log_guess) #else /* On a 32-bit platform, we can't have 8GB of ram. */ #define RAM_IS_VERY_LARGE(x) (0) -#endif +#endif /* SIZEOF_SIZE_T > 4 */ if (RAM_IS_VERY_LARGE(ram)) { /* If we have 8 GB, or more, RAM available, we set the MaxMemInQueues @@ -5757,7 +5777,7 @@ options_init_logs(const or_options_t *old_options, or_options_t *options, #else log_warn(LD_CONFIG, "Android logging is not supported" " on this system. Sorry."); -#endif // HAVE_ANDROID_LOG_H. +#endif /* defined(HAVE_ANDROID_LOG_H) */ goto cleanup; } } @@ -7071,7 +7091,7 @@ parse_port_config(smartlist_t *out, if (!strcasecmpstart(elt, "SessionGroup=")) { int group = (int)tor_parse_long(elt+strlen("SessionGroup="), 10, 0, INT_MAX, &ok, NULL); - if (!ok || !allow_no_stream_options) { + if (!ok || allow_no_stream_options) { log_warn(LD_CONFIG, "Invalid %sPort option '%s'", portname, escaped(elt)); goto err; diff --git a/src/app/config/confparse.c b/src/app/config/confparse.c index 8681f648da..729e7a4478 100644 --- a/src/app/config/confparse.c +++ b/src/app/config/confparse.c @@ -225,6 +225,7 @@ config_assign_value(const config_format_t *fmt, void *options, tor_asprintf(msg, "Interval '%s %s' is malformed or out of bounds.", c->key, c->value); + tor_free(tmp); return -1; } *(int *)lvalue = i; diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h index bd707fd193..2ee2d15674 100644 --- a/src/app/config/or_options_st.h +++ b/src/app/config/or_options_st.h @@ -248,6 +248,17 @@ struct or_options_t { * pad to the server regardless of server support. */ int ConnectionPadding; + /** Boolean: if true, then circuit padding will be negotiated by client + * and server, subject to consenus limits (default). If 0, it will be fully + * disabled. */ + int CircuitPadding; + + /** Boolean: if true, then this client will only use circuit padding + * algorithms that are known to use a low amount of overhead. If false, + * we will use all available circuit padding algorithms. + */ + int ReducedCircuitPadding; + /** To what authority types do we publish our descriptor? Choices are * "v1", "v2", "v3", "bridge", or "". */ struct smartlist_t *PublishServerDescriptor; @@ -1099,4 +1110,4 @@ struct or_options_t { int DormantCanceledByStartup; }; -#endif +#endif /* !defined(TOR_OR_OPTIONS_ST_H) */ diff --git a/src/app/config/or_state_st.h b/src/app/config/or_state_st.h index cdb9b38287..f45c6196cc 100644 --- a/src/app/config/or_state_st.h +++ b/src/app/config/or_state_st.h @@ -96,4 +96,4 @@ struct or_state_t { int Dormant; }; -#endif +#endif /* !defined(TOR_OR_STATE_ST_H) */ diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c index 9681f6f8b3..fdfd68b244 100644 --- a/src/app/config/statefile.c +++ b/src/app/config/statefile.c @@ -36,7 +36,7 @@ #include "core/mainloop/mainloop.h" #include "core/mainloop/netstatus.h" #include "core/mainloop/connection.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/client/entrynodes.h" #include "feature/hibernate/hibernate.h" #include "feature/stats/rephist.h" diff --git a/src/app/config/statefile.h b/src/app/config/statefile.h index 1950078450..515c90a52f 100644 --- a/src/app/config/statefile.h +++ b/src/app/config/statefile.h @@ -31,6 +31,6 @@ STATIC struct config_line_t *get_transport_in_state_by_name( STATIC void or_state_free_(or_state_t *state); #define or_state_free(st) FREE_AND_NULL(or_state_t, or_state_free_, (st)) STATIC or_state_t *or_state_new(void); -#endif +#endif /* defined(STATEFILE_PRIVATE) */ #endif /* !defined(TOR_STATEFILE_H) */ diff --git a/src/app/main/main.c b/src/app/main/main.c index 4b60763f75..6e325f0b10 100644 --- a/src/app/main/main.c +++ b/src/app/main/main.c @@ -15,66 +15,51 @@ #include "app/config/statefile.h" #include "app/main/main.h" #include "app/main/ntmain.h" +#include "app/main/shutdown.h" #include "app/main/subsysmgr.h" #include "core/mainloop/connection.h" #include "core/mainloop/cpuworker.h" #include "core/mainloop/mainloop.h" +#include "core/mainloop/mainloop_pubsub.h" #include "core/mainloop/netstatus.h" #include "core/or/channel.h" #include "core/or/channelpadding.h" #include "core/or/circuitpadding.h" -#include "core/or/channeltls.h" #include "core/or/circuitlist.h" -#include "core/or/circuitmux_ewma.h" #include "core/or/command.h" -#include "core/or/connection_edge.h" #include "core/or/connection_or.h" -#include "core/or/dos.h" -#include "core/or/policies.h" -#include "core/or/protover.h" #include "core/or/relay.h" -#include "core/or/scheduler.h" #include "core/or/status.h" -#include "core/or/versions.h" #include "feature/api/tor_api.h" #include "feature/api/tor_api_internal.h" #include "feature/client/addressmap.h" -#include "feature/client/bridges.h" -#include "feature/client/entrynodes.h" -#include "feature/client/transports.h" #include "feature/control/control.h" -#include "feature/dirauth/bwauth.h" +#include "feature/control/control_auth.h" +#include "feature/control/control_events.h" #include "feature/dirauth/keypin.h" #include "feature/dirauth/process_descs.h" #include "feature/dircache/consdiffmgr.h" -#include "feature/dircache/dirserv.h" #include "feature/dirparse/routerparse.h" #include "feature/hibernate/hibernate.h" -#include "feature/hs/hs_cache.h" #include "feature/nodelist/authcert.h" -#include "feature/nodelist/microdesc.h" #include "feature/nodelist/networkstatus.h" -#include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerlist.h" #include "feature/relay/dns.h" #include "feature/relay/ext_orport.h" -#include "feature/relay/onion_queue.h" #include "feature/relay/routerkeys.h" #include "feature/relay/routermode.h" #include "feature/rend/rendcache.h" -#include "feature/rend/rendclient.h" #include "feature/rend/rendservice.h" -#include "feature/stats/geoip_stats.h" #include "feature/stats/predict_ports.h" #include "feature/stats/rephist.h" #include "lib/compress/compress.h" #include "lib/buf/buffers.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_s2k.h" -#include "lib/geoip/geoip.h" #include "lib/net/resolve.h" #include "lib/process/waitpid.h" +#include "lib/pubsub/pubsub_build.h" #include "lib/meminfo/meminfo.h" #include "lib/osinfo/uname.h" @@ -90,7 +75,6 @@ #include -#include "feature/dirauth/dirvote.h" #include "feature/dirauth/authmode.h" #include "feature/dirauth/shared_random.h" @@ -111,8 +95,6 @@ #include #endif /* defined(HAVE_SYSTEMD) */ -void evdns_shutdown(int); - #ifdef HAVE_RUST // helper function defined in Rust to output a log message indicating if tor is // running with Rust enabled. See src/rust/tor_util @@ -670,7 +652,7 @@ tor_init(int argc, char *argv[]) log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting."); return -1; } - stream_choice_seed_weak_rng(); + if (tor_init_libevent_rng() < 0) { log_warn(LD_NET, "Problem initializing libevent RNG."); } @@ -743,86 +725,6 @@ release_lockfile(void) } } -/** Free all memory that we might have allocated somewhere. - * If postfork, we are a worker process and we want to free - * only the parts of memory that we won't touch. If !postfork, - * Tor is shutting down and we should free everything. - * - * Helps us find the real leaks with sanitizers and the like. Also valgrind - * should then report 0 reachable in its leak report (in an ideal world -- - * in practice libevent, SSL, libc etc never quite free everything). */ -void -tor_free_all(int postfork) -{ - if (!postfork) { - evdns_shutdown(1); - } - geoip_free_all(); - geoip_stats_free_all(); - dirvote_free_all(); - routerlist_free_all(); - networkstatus_free_all(); - addressmap_free_all(); - dirserv_free_fingerprint_list(); - dirserv_free_all(); - dirserv_clear_measured_bw_cache(); - rend_cache_free_all(); - rend_service_authorization_free_all(); - rep_hist_free_all(); - dns_free_all(); - clear_pending_onions(); - circuit_free_all(); - circpad_machines_free(); - entry_guards_free_all(); - pt_free_all(); - channel_tls_free_all(); - channel_free_all(); - connection_free_all(); - connection_edge_free_all(); - scheduler_free_all(); - nodelist_free_all(); - microdesc_free_all(); - routerparse_free_all(); - ext_orport_free_all(); - control_free_all(); - protover_free_all(); - bridges_free_all(); - consdiffmgr_free_all(); - hs_free_all(); - dos_free_all(); - circuitmux_ewma_free_all(); - accounting_free_all(); - protover_summary_cache_free_all(); - - if (!postfork) { - config_free_all(); - or_state_free_all(); - router_free_all(); - routerkeys_free_all(); - policies_free_all(); - } - if (!postfork) { -#ifndef _WIN32 - tor_getpwnam(NULL); -#endif - } - /* stuff in main.c */ - - tor_mainloop_free_all(); - - if (!postfork) { - release_lockfile(); - } - tor_libevent_free_all(); - - subsystems_shutdown(); - - /* Stuff in util.c and address.c*/ - if (!postfork) { - esc_router_info(NULL); - } -} - /** * Remove the specified file, and log a warning if the operation fails for * any reason other than the file not existing. Ignores NULL filenames. @@ -836,50 +738,6 @@ tor_remove_file(const char *filename) } } -/** Do whatever cleanup is necessary before shutting Tor down. */ -void -tor_cleanup(void) -{ - const or_options_t *options = get_options(); - if (options->command == CMD_RUN_TOR) { - time_t now = time(NULL); - /* Remove our pid file. We don't care if there was an error when we - * unlink, nothing we could do about it anyways. */ - tor_remove_file(options->PidFile); - /* Remove control port file */ - tor_remove_file(options->ControlPortWriteToFile); - /* Remove cookie authentication file */ - { - char *cookie_fname = get_controller_cookie_file_name(); - tor_remove_file(cookie_fname); - tor_free(cookie_fname); - } - /* Remove Extended ORPort cookie authentication file */ - { - char *cookie_fname = get_ext_or_auth_cookie_file_name(); - tor_remove_file(cookie_fname); - tor_free(cookie_fname); - } - if (accounting_is_enabled(options)) - accounting_record_bandwidth_usage(now, get_or_state()); - or_state_mark_dirty(get_or_state(), 0); /* force an immediate save. */ - or_state_save(now); - if (authdir_mode(options)) { - sr_save_and_cleanup(); - } - if (authdir_mode_tests_reachability(options)) - rep_hist_record_mtbf_data(now, 0); - keypin_close_journal(); - } - - timers_shutdown(); - - tor_free_all(0); /* We could move tor_free_all back into the ifdef below - later, if it makes shutdown unacceptably slow. But for - now, leave it here: it's helped us catch bugs in the - past. */ -} - /** Read/create keys as needed, and echo our fingerprint to stdout. */ static int do_list_fingerprint(void) @@ -1377,6 +1235,30 @@ run_tor_main_loop(void) return do_main_loop(); } +/** Install the publish/subscribe relationships for all the subsystems. */ +static void +pubsub_install(void) +{ + pubsub_builder_t *builder = pubsub_builder_new(); + int r = subsystems_add_pubsub(builder); + tor_assert(r == 0); + r = tor_mainloop_connect_pubsub(builder); // consumes builder + tor_assert(r == 0); +} + +/** Connect the mainloop to its publish/subscribe message delivery events if + * appropriate, and configure the global channels appropriately. */ +static void +pubsub_connect(void) +{ + if (get_options()->command == CMD_RUN_TOR) { + tor_mainloop_connect_pubsub_events(); + /* XXXX For each pubsub channel, its delivery strategy should be set at + * this XXXX point, using tor_mainloop_set_delivery_strategy(). + */ + } +} + /* Main entry point for the Tor process. Called from tor_main(), and by * anybody embedding Tor. */ int @@ -1408,6 +1290,9 @@ tor_run_main(const tor_main_configuration_t *tor_cfg) } } #endif /* defined(NT_SERVICE) */ + + pubsub_install(); + { int init_rv = tor_init(argc, argv); if (init_rv) { @@ -1417,6 +1302,8 @@ tor_run_main(const tor_main_configuration_t *tor_cfg) } } + pubsub_connect(); + if (get_options()->Sandbox && get_options()->command == CMD_RUN_TOR) { sandbox_cfg_t* cfg = sandbox_init_filter(); diff --git a/src/app/main/main.h b/src/app/main/main.h index bbbbf984fb..9dfaf4b8ef 100644 --- a/src/app/main/main.h +++ b/src/app/main/main.h @@ -21,9 +21,6 @@ void release_lockfile(void); void tor_remove_file(const char *filename); -void tor_cleanup(void); -void tor_free_all(int postfork); - int tor_init(int argc, char **argv); int run_tor_main_loop(void); diff --git a/src/app/main/ntmain.c b/src/app/main/ntmain.c index 05d203b0be..f00b712702 100644 --- a/src/app/main/ntmain.c +++ b/src/app/main/ntmain.c @@ -24,6 +24,7 @@ #include "app/config/config.h" #include "app/main/main.h" #include "app/main/ntmain.h" +#include "app/main/shutdown.h" #include "core/mainloop/mainloop.h" #include "lib/evloop/compat_libevent.h" #include "lib/fs/winlib.h" diff --git a/src/app/main/shutdown.c b/src/app/main/shutdown.c new file mode 100644 index 0000000000..cc0091a9ab --- /dev/null +++ b/src/app/main/shutdown.c @@ -0,0 +1,169 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file shutdown.c + * @brief Code to free global resources used by Tor. + * + * In the future, this should all be handled by the subsystem manager. */ + +#include "core/or/or.h" + +#include "app/config/config.h" +#include "app/config/statefile.h" +#include "app/main/main.h" +#include "app/main/shutdown.h" +#include "app/main/subsysmgr.h" +#include "core/mainloop/connection.h" +#include "core/mainloop/mainloop_pubsub.h" +#include "core/or/channeltls.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitmux_ewma.h" +#include "core/or/circuitpadding.h" +#include "core/or/connection_edge.h" +#include "core/or/dos.h" +#include "core/or/scheduler.h" +#include "feature/client/addressmap.h" +#include "feature/client/bridges.h" +#include "feature/client/entrynodes.h" +#include "feature/client/transports.h" +#include "feature/control/control.h" +#include "feature/control/control_auth.h" +#include "feature/dirauth/authmode.h" +#include "feature/dirauth/shared_random.h" +#include "feature/dircache/consdiffmgr.h" +#include "feature/dircache/dirserv.h" +#include "feature/dirparse/routerparse.h" +#include "feature/hibernate/hibernate.h" +#include "feature/hs/hs_common.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerlist.h" +#include "feature/relay/ext_orport.h" +#include "feature/rend/rendcache.h" +#include "feature/rend/rendclient.h" +#include "feature/stats/geoip_stats.h" +#include "feature/stats/rephist.h" +#include "lib/evloop/compat_libevent.h" +#include "lib/geoip/geoip.h" + +void evdns_shutdown(int); + +/** Do whatever cleanup is necessary before shutting Tor down. */ +void +tor_cleanup(void) +{ + const or_options_t *options = get_options(); + if (options->command == CMD_RUN_TOR) { + time_t now = time(NULL); + /* Remove our pid file. We don't care if there was an error when we + * unlink, nothing we could do about it anyways. */ + tor_remove_file(options->PidFile); + /* Remove control port file */ + tor_remove_file(options->ControlPortWriteToFile); + /* Remove cookie authentication file */ + { + char *cookie_fname = get_controller_cookie_file_name(); + tor_remove_file(cookie_fname); + tor_free(cookie_fname); + } + /* Remove Extended ORPort cookie authentication file */ + { + char *cookie_fname = get_ext_or_auth_cookie_file_name(); + tor_remove_file(cookie_fname); + tor_free(cookie_fname); + } + if (accounting_is_enabled(options)) + accounting_record_bandwidth_usage(now, get_or_state()); + or_state_mark_dirty(get_or_state(), 0); /* force an immediate save. */ + or_state_save(now); + if (authdir_mode(options)) { + sr_save_and_cleanup(); + } + if (authdir_mode_tests_reachability(options)) + rep_hist_record_mtbf_data(now, 0); + } + + timers_shutdown(); + + tor_free_all(0); /* We could move tor_free_all back into the ifdef below + later, if it makes shutdown unacceptably slow. But for + now, leave it here: it's helped us catch bugs in the + past. */ +} + +/** Free all memory that we might have allocated somewhere. + * If postfork, we are a worker process and we want to free + * only the parts of memory that we won't touch. If !postfork, + * Tor is shutting down and we should free everything. + * + * Helps us find the real leaks with sanitizers and the like. Also valgrind + * should then report 0 reachable in its leak report (in an ideal world -- + * in practice libevent, SSL, libc etc never quite free everything). */ +void +tor_free_all(int postfork) +{ + if (!postfork) { + evdns_shutdown(1); + } + geoip_free_all(); + geoip_stats_free_all(); + routerlist_free_all(); + networkstatus_free_all(); + addressmap_free_all(); + dirserv_free_all(); + rend_cache_free_all(); + rend_service_authorization_free_all(); + rep_hist_free_all(); + circuit_free_all(); + circpad_machines_free(); + entry_guards_free_all(); + pt_free_all(); + channel_tls_free_all(); + channel_free_all(); + connection_free_all(); + connection_edge_free_all(); + scheduler_free_all(); + nodelist_free_all(); + microdesc_free_all(); + routerparse_free_all(); + control_free_all(); + bridges_free_all(); + consdiffmgr_free_all(); + hs_free_all(); + dos_free_all(); + circuitmux_ewma_free_all(); + accounting_free_all(); + circpad_free_all(); + + if (!postfork) { + config_free_all(); + or_state_free_all(); + } + if (!postfork) { +#ifndef _WIN32 + tor_getpwnam(NULL); +#endif + } + /* stuff in main.c */ + + tor_mainloop_disconnect_pubsub(); + + if (!postfork) { + release_lockfile(); + } + + subsystems_shutdown(); + + tor_libevent_free_all(); + + /* Stuff in util.c and address.c*/ + if (!postfork) { + esc_router_info(NULL); + } +} diff --git a/src/app/main/shutdown.h b/src/app/main/shutdown.h new file mode 100644 index 0000000000..1bca96a0aa --- /dev/null +++ b/src/app/main/shutdown.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file shutdown.h + * \brief Header file for shutdown.c. + **/ + +#ifndef TOR_SHUTDOWN_H +#define TOR_SHUTDOWN_H + +void tor_cleanup(void); +void tor_free_all(int postfork); + +#endif /* !defined(TOR_SHUTDOWN_H) */ diff --git a/src/app/main/subsysmgr.c b/src/app/main/subsysmgr.c index e0ca3ce4df..5aa4fd76c9 100644 --- a/src/app/main/subsysmgr.c +++ b/src/app/main/subsysmgr.c @@ -5,9 +5,14 @@ #include "orconfig.h" #include "app/main/subsysmgr.h" -#include "lib/err/torerr.h" +#include "lib/dispatch/dispatch_naming.h" +#include "lib/dispatch/msgtypes.h" +#include "lib/err/torerr.h" #include "lib/log/log.h" +#include "lib/malloc/malloc.h" +#include "lib/pubsub/pubsub_build.h" +#include "lib/pubsub/pubsub_connect.h" #include #include @@ -105,6 +110,51 @@ subsystems_init_upto(int target_level) return 0; } +/** + * Add publish/subscribe relationships to builder for all + * initialized subsystems of level no more than target_level. + **/ +int +subsystems_add_pubsub_upto(pubsub_builder_t *builder, + int target_level) +{ + for (unsigned i = 0; i < n_tor_subsystems; ++i) { + const subsys_fns_t *sys = tor_subsystems[i]; + if (!sys->supported) + continue; + if (sys->level > target_level) + break; + if (! sys_initialized[i]) + continue; + int r = 0; + if (sys->add_pubsub) { + subsys_id_t sysid = get_subsys_id(sys->name); + raw_assert(sysid != ERROR_ID); + pubsub_connector_t *connector; + connector = pubsub_connector_for_subsystem(builder, sysid); + r = sys->add_pubsub(connector); + pubsub_connector_free(connector); + } + if (r < 0) { + fprintf(stderr, "BUG: subsystem %s (at %u) could not connect to " + "publish/subscribe system.", sys->name, sys->level); + raw_assert_unreached_msg("A subsystem couldn't be connected."); + } + } + + return 0; +} + +/** + * Add publish/subscribe relationships to builder for all + * initialized subsystems. + **/ +int +subsystems_add_pubsub(pubsub_builder_t *builder) +{ + return subsystems_add_pubsub_upto(builder, MAX_SUBSYS_LEVEL); +} + /** * Shut down all the subsystems. **/ diff --git a/src/app/main/subsysmgr.h b/src/app/main/subsysmgr.h index a5e62f71d9..d4426614e3 100644 --- a/src/app/main/subsysmgr.h +++ b/src/app/main/subsysmgr.h @@ -14,6 +14,11 @@ extern const unsigned n_tor_subsystems; int subsystems_init(void); int subsystems_init_upto(int level); +struct pubsub_builder_t; +int subsystems_add_pubsub_upto(struct pubsub_builder_t *builder, + int target_level); +int subsystems_add_pubsub(struct pubsub_builder_t *builder); + void subsystems_shutdown(void); void subsystems_shutdown_downto(int level); @@ -21,4 +26,4 @@ void subsystems_prefork(void); void subsystems_postfork(void); void subsystems_thread_cleanup(void); -#endif +#endif /* !defined(TOR_SUBSYSMGR_T) */ diff --git a/src/app/main/subsystem_list.c b/src/app/main/subsystem_list.c index 3834176182..f595796232 100644 --- a/src/app/main/subsystem_list.c +++ b/src/app/main/subsystem_list.c @@ -8,20 +8,25 @@ #include "lib/cc/compat_compiler.h" #include "lib/cc/torint.h" +#include "core/mainloop/mainloop_sys.h" #include "core/or/ocirc_event_sys.h" +#include "core/or/or_sys.h" #include "core/or/orconn_event_sys.h" #include "feature/control/btrack_sys.h" +#include "feature/relay/relay_sys.h" #include "lib/compress/compress_sys.h" #include "lib/crypt_ops/crypto_sys.h" #include "lib/err/torerr_sys.h" #include "lib/log/log_sys.h" #include "lib/net/network_sys.h" +#include "lib/process/process_sys.h" #include "lib/process/winprocess_sys.h" #include "lib/thread/thread_sys.h" #include "lib/time/time_sys.h" #include "lib/tls/tortls_sys.h" #include "lib/wallclock/wallclock_sys.h" -#include "lib/process/process_sys.h" + +#include "feature/dirauth/dirauth_sys.h" #include @@ -44,6 +49,15 @@ const subsys_fns_t *tor_subsystems[] = { &sys_orconn_event, /* -33 */ &sys_ocirc_event, /* -32 */ &sys_btrack, /* -30 */ + + &sys_mainloop, /* 5 */ + &sys_or, /* 20 */ + + &sys_relay, /* 50 */ + +#ifdef HAVE_MODULE_DIRAUTH + &sys_dirauth, /* 70 */ +#endif }; const unsigned n_tor_subsystems = ARRAY_LENGTH(tor_subsystems); diff --git a/src/config/mmdb-convert.py b/src/config/mmdb-convert.py index 706a8b03cc..b861e9433e 100644 --- a/src/config/mmdb-convert.py +++ b/src/config/mmdb-convert.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/python # This software has been dedicated to the public domain under the CC0 # public domain dedication. diff --git a/src/config/torrc.sample.in b/src/config/torrc.sample.in index c2ae707e93..9d514e6bda 100644 --- a/src/config/torrc.sample.in +++ b/src/config/torrc.sample.in @@ -174,13 +174,11 @@ ## Uncomment this if you want your relay to be an exit, with the default ## exit policy (or whatever exit policy you set below). -## (If ReducedExitPolicy or ExitPolicy are set, relays are exits. -## If neither exit policy option is set, relays are non-exits.) +## (If ReducedExitPolicy, ExitPolicy, or IPv6Exit are set, relays are exits. +## If none of these options are set, relays are non-exits.) #ExitRelay 1 ## Uncomment this if you want your relay to allow IPv6 exit traffic. -## You must also set ExitRelay, ReducedExitPolicy, or ExitPolicy to make your -## relay into an exit. ## (Relays do not allow any exit traffic by default.) #IPv6Exit 1 diff --git a/src/core/crypto/hs_ntor.c b/src/core/crypto/hs_ntor.c index c34073690e..add8a2b8f2 100644 --- a/src/core/crypto/hs_ntor.c +++ b/src/core/crypto/hs_ntor.c @@ -176,7 +176,6 @@ get_introduce1_key_material(const uint8_t *secret_input, uint8_t keystream[CIPHER256_KEY_LEN + DIGEST256_LEN]; uint8_t info_blob[INFO_BLOB_LEN]; uint8_t kdf_input[KDF_INPUT_LEN]; - crypto_xof_t *xof; uint8_t *ptr; /* Let's build info */ @@ -193,10 +192,8 @@ get_introduce1_key_material(const uint8_t *secret_input, tor_assert(ptr == kdf_input + sizeof(kdf_input)); /* Now we need to run kdf_input over SHAKE-256 */ - xof = crypto_xof_new(); - crypto_xof_add_bytes(xof, kdf_input, sizeof(kdf_input)); - crypto_xof_squeeze_bytes(xof, keystream, sizeof(keystream)) ; - crypto_xof_free(xof); + crypto_xof(keystream, sizeof(keystream), + kdf_input, sizeof(kdf_input)); { /* Get the keys */ memcpy(&hs_ntor_intro_cell_keys_out->enc_key, keystream,CIPHER256_KEY_LEN); @@ -594,7 +591,6 @@ hs_ntor_circuit_key_expansion(const uint8_t *ntor_key_seed, size_t seed_len, { uint8_t *ptr; uint8_t kdf_input[NTOR_KEY_EXPANSION_KDF_INPUT_LEN]; - crypto_xof_t *xof; /* Sanity checks on lengths to make sure we are good */ if (BUG(seed_len != DIGEST256_LEN)) { @@ -611,10 +607,8 @@ hs_ntor_circuit_key_expansion(const uint8_t *ntor_key_seed, size_t seed_len, tor_assert(ptr == kdf_input + sizeof(kdf_input)); /* Generate the keys */ - xof = crypto_xof_new(); - crypto_xof_add_bytes(xof, kdf_input, sizeof(kdf_input)); - crypto_xof_squeeze_bytes(xof, keys_out, HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN); - crypto_xof_free(xof); + crypto_xof(keys_out, HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN, + kdf_input, sizeof(kdf_input)); return 0; } diff --git a/src/core/crypto/onion_crypto.h b/src/core/crypto/onion_crypto.h index 1cddde3610..7abdd6538e 100644 --- a/src/core/crypto/onion_crypto.h +++ b/src/core/crypto/onion_crypto.h @@ -44,4 +44,4 @@ void server_onion_keys_free_(server_onion_keys_t *keys); #define server_onion_keys_free(keys) \ FREE_AND_NULL(server_onion_keys_t, server_onion_keys_free_, (keys)) -#endif +#endif /* !defined(TOR_ONION_CRYPTO_H) */ diff --git a/src/core/crypto/relay_crypto.c b/src/core/crypto/relay_crypto.c index 0b83b2d0a5..8a285131a8 100644 --- a/src/core/crypto/relay_crypto.c +++ b/src/core/crypto/relay_crypto.c @@ -6,12 +6,14 @@ #include "core/or/or.h" #include "core/or/circuitlist.h" +#include "core/or/crypt_path.h" #include "app/config/config.h" #include "lib/crypt_ops/crypto_cipher.h" #include "lib/crypt_ops/crypto_util.h" #include "core/crypto/hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN #include "core/or/relay.h" #include "core/crypto/relay_crypto.h" +#include "core/or/sendme.h" #include "core/or/cell_st.h" #include "core/or/or_circuit_st.h" @@ -20,7 +22,7 @@ /** Update digest from the payload of cell. Assign integrity part to * cell. */ -static void +void relay_set_digest(crypto_digest_t *digest, cell_t *cell) { char integrity[4]; @@ -84,12 +86,39 @@ relay_digest_matches(crypto_digest_t *digest, cell_t *cell) * * Note that we use the same operation for encrypting and for decrypting. */ -static void +void relay_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in) { crypto_cipher_crypt_inplace(cipher, (char*) in, CELL_PAYLOAD_SIZE); } +/** Return the sendme_digest within the crypto object. */ +uint8_t * +relay_crypto_get_sendme_digest(relay_crypto_t *crypto) +{ + tor_assert(crypto); + return crypto->sendme_digest; +} + +/** Record the cell digest, indicated by is_foward_digest or not, as the + * SENDME cell digest. */ +void +relay_crypto_record_sendme_digest(relay_crypto_t *crypto, + bool is_foward_digest) +{ + struct crypto_digest_t *digest; + + tor_assert(crypto); + + digest = crypto->b_digest; + if (is_foward_digest) { + digest = crypto->f_digest; + } + + crypto_digest_get_digest(digest, (char *) crypto->sendme_digest, + sizeof(crypto->sendme_digest)); +} + /** Do the appropriate en/decryptions for cell arriving on * circ in direction cell_direction. * @@ -134,12 +163,12 @@ relay_decrypt_cell(circuit_t *circ, cell_t *cell, tor_assert(thishop); /* decrypt one layer */ - relay_crypt_one_payload(thishop->crypto.b_crypto, cell->payload); + cpath_crypt_cell(thishop, cell->payload, true); relay_header_unpack(&rh, cell->payload); if (rh.recognized == 0) { /* it's possibly recognized. have to check digest to be sure. */ - if (relay_digest_matches(thishop->crypto.b_digest, cell)) { + if (relay_digest_matches(cpath_get_incoming_digest(thishop), cell)) { *recognized = 1; *layer_hint = thishop; return 0; @@ -187,14 +216,17 @@ relay_encrypt_cell_outbound(cell_t *cell, crypt_path_t *layer_hint) { crypt_path_t *thishop; /* counter for repeated crypts */ - relay_set_digest(layer_hint->crypto.f_digest, cell); + cpath_set_cell_forward_digest(layer_hint, cell); + + /* Record cell digest as the SENDME digest if need be. */ + sendme_record_sending_cell_digest(TO_CIRCUIT(circ), layer_hint); thishop = layer_hint; /* moving from farthest to nearest hop */ do { tor_assert(thishop); log_debug(LD_OR,"encrypting a layer of the relay cell."); - relay_crypt_one_payload(thishop->crypto.f_crypto, cell->payload); + cpath_crypt_cell(thishop, cell->payload, false); thishop = thishop->prev; } while (thishop != circ->cpath->prev); @@ -212,6 +244,10 @@ relay_encrypt_cell_inbound(cell_t *cell, or_circuit_t *or_circ) { relay_set_digest(or_circ->crypto.b_digest, cell); + + /* Record cell digest as the SENDME digest if need be. */ + sendme_record_sending_cell_digest(TO_CIRCUIT(or_circ), NULL); + /* encrypt one layer */ relay_crypt_one_payload(or_circ->crypto.b_crypto, cell->payload); } diff --git a/src/core/crypto/relay_crypto.h b/src/core/crypto/relay_crypto.h index 45a21d14ab..9478f8d359 100644 --- a/src/core/crypto/relay_crypto.h +++ b/src/core/crypto/relay_crypto.h @@ -27,5 +27,16 @@ void relay_crypto_clear(relay_crypto_t *crypto); void relay_crypto_assert_ok(const relay_crypto_t *crypto); +uint8_t *relay_crypto_get_sendme_digest(relay_crypto_t *crypto); + +void relay_crypto_record_sendme_digest(relay_crypto_t *crypto, + bool is_foward_digest); + +void +relay_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in); + +void +relay_set_digest(crypto_digest_t *digest, cell_t *cell); + #endif /* !defined(TOR_RELAY_CRYPTO_H) */ diff --git a/src/core/include.am b/src/core/include.am index ae47c75e09..1a4b9fb8ab 100644 --- a/src/core/include.am +++ b/src/core/include.am @@ -6,11 +6,13 @@ noinst_LIBRARIES += \ src/core/libtor-app-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. LIBTOR_APP_A_SOURCES = \ src/app/config/config.c \ src/app/config/confparse.c \ src/app/config/statefile.c \ src/app/main/main.c \ + src/app/main/shutdown.c \ src/app/main/subsystem_list.c \ src/app/main/subsysmgr.c \ src/core/crypto/hs_ntor.c \ @@ -22,6 +24,8 @@ LIBTOR_APP_A_SOURCES = \ src/core/mainloop/connection.c \ src/core/mainloop/cpuworker.c \ src/core/mainloop/mainloop.c \ + src/core/mainloop/mainloop_pubsub.c \ + src/core/mainloop/mainloop_sys.c \ src/core/mainloop/netstatus.c \ src/core/mainloop/periodic.c \ src/core/or/address_set.c \ @@ -33,14 +37,18 @@ LIBTOR_APP_A_SOURCES = \ src/core/or/circuitmux.c \ src/core/or/circuitmux_ewma.c \ src/core/or/circuitpadding.c \ + src/core/or/circuitpadding_machines.c \ src/core/or/circuitstats.c \ src/core/or/circuituse.c \ + src/core/or/crypt_path.c \ src/core/or/command.c \ src/core/or/connection_edge.c \ src/core/or/connection_or.c \ src/core/or/dos.c \ src/core/or/onion.c \ src/core/or/ocirc_event.c \ + src/core/or/or_periodic.c \ + src/core/or/or_sys.c \ src/core/or/orconn_event.c \ src/core/or/policies.c \ src/core/or/protover.c \ @@ -50,6 +58,7 @@ LIBTOR_APP_A_SOURCES = \ src/core/or/scheduler.c \ src/core/or/scheduler_kist.c \ src/core/or/scheduler_vanilla.c \ + src/core/or/sendme.c \ src/core/or/status.c \ src/core/or/versions.c \ src/core/proto/proto_cell.c \ @@ -70,10 +79,15 @@ LIBTOR_APP_A_SOURCES = \ src/feature/control/btrack_orconn_cevent.c \ src/feature/control/btrack_orconn_maps.c \ src/feature/control/control.c \ + src/feature/control/control_auth.c \ src/feature/control/control_bootstrap.c \ + src/feature/control/control_cmd.c \ + src/feature/control/control_events.c \ + src/feature/control/control_fmt.c \ + src/feature/control/control_getinfo.c \ + src/feature/control/control_proto.c \ src/feature/control/fmt_serverstatus.c \ src/feature/control/getinfo_geoip.c \ - src/feature/dirauth/keypin.c \ src/feature/dircache/conscache.c \ src/feature/dircache/consdiffmgr.c \ src/feature/dircache/dircache.c \ @@ -110,7 +124,6 @@ LIBTOR_APP_A_SOURCES = \ src/feature/hs_common/replaycache.c \ src/feature/hs_common/shared_random_client.c \ src/feature/keymgt/loadkey.c \ - src/feature/dirauth/keypin.c \ src/feature/nodelist/authcert.c \ src/feature/nodelist/describe.c \ src/feature/nodelist/dirlist.c \ @@ -128,6 +141,8 @@ LIBTOR_APP_A_SOURCES = \ src/feature/relay/dns.c \ src/feature/relay/ext_orport.c \ src/feature/relay/onion_queue.c \ + src/feature/relay/relay_periodic.c \ + src/feature/relay/relay_sys.c \ src/feature/relay/router.c \ src/feature/relay/routerkeys.c \ src/feature/relay/routermode.c \ @@ -142,17 +157,6 @@ LIBTOR_APP_A_SOURCES = \ src/feature/stats/rephist.c \ src/feature/stats/predict_ports.c -# These should eventually move into module_dirauth_sources, but for now -# the separation is only in the code location. -LIBTOR_APP_A_SOURCES += \ - src/feature/dirauth/bwauth.c \ - src/feature/dirauth/dsigs_parse.c \ - src/feature/dirauth/guardfraction.c \ - src/feature/dirauth/reachability.c \ - src/feature/dirauth/recommend_pkg.c \ - src/feature/dirauth/process_descs.c \ - src/feature/dirauth/voteflags.c - if BUILD_NT_SERVICES LIBTOR_APP_A_SOURCES += src/app/main/ntmain.c endif @@ -168,10 +172,21 @@ LIBTOR_APP_TESTING_A_SOURCES = $(LIBTOR_APP_A_SOURCES) # The Directory Authority module. MODULE_DIRAUTH_SOURCES = \ src/feature/dirauth/authmode.c \ + src/feature/dirauth/bridgeauth.c \ + src/feature/dirauth/bwauth.c \ + src/feature/dirauth/dirauth_periodic.c \ + src/feature/dirauth/dirauth_sys.c \ src/feature/dirauth/dircollate.c \ src/feature/dirauth/dirvote.c \ + src/feature/dirauth/dsigs_parse.c \ + src/feature/dirauth/guardfraction.c \ + src/feature/dirauth/keypin.c \ + src/feature/dirauth/process_descs.c \ + src/feature/dirauth/reachability.c \ + src/feature/dirauth/recommend_pkg.c \ src/feature/dirauth/shared_random.c \ - src/feature/dirauth/shared_random_state.c + src/feature/dirauth/shared_random_state.c \ + src/feature/dirauth/voteflags.c if BUILD_MODULE_DIRAUTH LIBTOR_APP_A_SOURCES += $(MODULE_DIRAUTH_SOURCES) @@ -195,6 +210,7 @@ AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \ src_core_libtor_app_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_core_libtor_app_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/app/config/config.h \ src/app/config/confparse.h \ @@ -203,6 +219,7 @@ noinst_HEADERS += \ src/app/config/statefile.h \ src/app/main/main.h \ src/app/main/ntmain.h \ + src/app/main/shutdown.h \ src/app/main/subsysmgr.h \ src/core/crypto/hs_ntor.h \ src/core/crypto/onion_crypto.h \ @@ -213,6 +230,8 @@ noinst_HEADERS += \ src/core/mainloop/connection.h \ src/core/mainloop/cpuworker.h \ src/core/mainloop/mainloop.h \ + src/core/mainloop/mainloop_pubsub.h \ + src/core/mainloop/mainloop_sys.h \ src/core/mainloop/netstatus.h \ src/core/mainloop/periodic.h \ src/core/or/addr_policy_st.h \ @@ -229,24 +248,28 @@ noinst_HEADERS += \ src/core/or/circuitmux_ewma.h \ src/core/or/circuitstats.h \ src/core/or/circuitpadding.h \ + src/core/or/circuitpadding_machines.h \ src/core/or/circuituse.h \ src/core/or/command.h \ src/core/or/connection_edge.h \ src/core/or/connection_or.h \ src/core/or/connection_st.h \ + src/core/or/crypt_path.h \ src/core/or/cpath_build_state_st.h \ src/core/or/crypt_path_reference_st.h \ src/core/or/crypt_path_st.h \ src/core/or/destroy_cell_queue_st.h \ src/core/or/dos.h \ src/core/or/edge_connection_st.h \ - src/core/or/half_edge_st.h \ + src/core/or/half_edge_st.h \ src/core/or/entry_connection_st.h \ src/core/or/entry_port_cfg_st.h \ src/core/or/extend_info_st.h \ src/core/or/listener_connection_st.h \ src/core/or/onion.h \ src/core/or/or.h \ + src/core/or/or_periodic.h \ + src/core/or/or_sys.h \ src/core/or/orconn_event.h \ src/core/or/orconn_event_sys.h \ src/core/or/or_circuit_st.h \ @@ -263,6 +286,7 @@ noinst_HEADERS += \ src/core/or/relay.h \ src/core/or/relay_crypto_st.h \ src/core/or/scheduler.h \ + src/core/or/sendme.h \ src/core/or/server_port_cfg_st.h \ src/core/or/socks_request_st.h \ src/core/or/status.h \ @@ -287,11 +311,21 @@ noinst_HEADERS += \ src/feature/control/btrack_orconn_maps.h \ src/feature/control/btrack_sys.h \ src/feature/control/control.h \ + src/feature/control/control_auth.h \ + src/feature/control/control_cmd.h \ + src/feature/control/control_cmd_args_st.h \ src/feature/control/control_connection_st.h \ + src/feature/control/control_events.h \ + src/feature/control/control_fmt.h \ + src/feature/control/control_getinfo.h \ + src/feature/control/control_proto.h \ src/feature/control/fmt_serverstatus.h \ src/feature/control/getinfo_geoip.h \ src/feature/dirauth/authmode.h \ + src/feature/dirauth/bridgeauth.h \ src/feature/dirauth/bwauth.h \ + src/feature/dirauth/dirauth_periodic.h \ + src/feature/dirauth/dirauth_sys.h \ src/feature/dirauth/dircollate.h \ src/feature/dirauth/dirvote.h \ src/feature/dirauth/dsigs_parse.h \ @@ -363,8 +397,8 @@ noinst_HEADERS += \ src/feature/nodelist/networkstatus_voter_info_st.h \ src/feature/nodelist/nickname.h \ src/feature/nodelist/node_st.h \ - src/feature/nodelist/nodefamily.h \ - src/feature/nodelist/nodefamily_st.h \ + src/feature/nodelist/nodefamily.h \ + src/feature/nodelist/nodefamily_st.h \ src/feature/nodelist/nodelist.h \ src/feature/nodelist/node_select.h \ src/feature/nodelist/routerinfo.h \ @@ -381,6 +415,8 @@ noinst_HEADERS += \ src/feature/relay/dns_structs.h \ src/feature/relay/ext_orport.h \ src/feature/relay/onion_queue.h \ + src/feature/relay/relay_periodic.h \ + src/feature/relay/relay_sys.h \ src/feature/relay/router.h \ src/feature/relay/routerkeys.h \ src/feature/relay/routermode.h \ diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c index df0bb39db5..127f08683f 100644 --- a/src/core/mainloop/connection.c +++ b/src/core/mainloop/connection.c @@ -82,12 +82,14 @@ #include "core/or/policies.h" #include "core/or/reasons.h" #include "core/or/relay.h" +#include "core/or/crypt_path.h" #include "core/proto/proto_http.h" #include "core/proto/proto_socks.h" #include "feature/client/dnsserv.h" #include "feature/client/entrynodes.h" #include "feature/client/transports.h" #include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirauth/authmode.h" #include "feature/dircache/dirserv.h" #include "feature/dircommon/directory.h" @@ -182,7 +184,7 @@ static const char *connection_proxy_state_to_string(int state); static int connection_read_https_proxy_response(connection_t *conn); static void connection_send_socks5_connect(connection_t *conn); static const char *proxy_type_to_string(int proxy_type); -static int get_proxy_type(void); +static int conn_get_proxy_type(const connection_t *conn); const tor_addr_t *conn_get_outbound_address(sa_family_t family, const or_options_t *options, unsigned int conn_type); static void reenable_blocked_connection_init(const or_options_t *options); @@ -696,6 +698,7 @@ connection_free_minimal(connection_t *conn) control_connection_t *control_conn = TO_CONTROL_CONN(conn); tor_free(control_conn->safecookie_client_hash); tor_free(control_conn->incoming_cmd); + tor_free(control_conn->current_cmd); if (control_conn->ephemeral_onion_services) { SMARTLIST_FOREACH(control_conn->ephemeral_onion_services, char *, cp, { memwipe(cp, 0, strlen(cp)); @@ -1473,7 +1476,7 @@ connection_listener_new(const struct sockaddr *listensockaddr, goto err; } } -#endif /* __APPLE__ */ +#endif /* !defined(__APPLE__) */ #endif /* defined(HAVE_SYS_UN_H) */ } else { log_err(LD_BUG, "Got unexpected address family %d.", @@ -1652,7 +1655,7 @@ check_sockaddr(const struct sockaddr *sa, int len, int level) len,(int)sizeof(struct sockaddr_in6)); ok = 0; } - if (tor_mem_is_zero((void*)sin6->sin6_addr.s6_addr, 16) || + if (fast_mem_is_zero((void*)sin6->sin6_addr.s6_addr, 16) || sin6->sin6_port == 0) { log_fn(level, LD_NET, "Address for new connection has address/port equal to zero."); @@ -2282,18 +2285,27 @@ connection_proxy_state_to_string(int state) return states[state]; } -/** Returns the global proxy type used by tor. Use this function for - * logging or high-level purposes, don't use it to fill the +/** Returns the proxy type used by tor for a single connection, for + * logging or high-level purposes. Don't use it to fill the * proxy_type field of or_connection_t; use the actual proxy * protocol instead.*/ static int -get_proxy_type(void) +conn_get_proxy_type(const connection_t *conn) { const or_options_t *options = get_options(); - if (options->ClientTransportPlugin) - return PROXY_PLUGGABLE; - else if (options->HTTPSProxy) + if (options->ClientTransportPlugin) { + /* If we have plugins configured *and* this addr/port is a known bridge + * with a transport, then we should be PROXY_PLUGGABLE. */ + const transport_t *transport = NULL; + int r; + r = get_transport_by_bridge_addrport(&conn->addr, conn->port, &transport); + if (r == 0 && transport) + return PROXY_PLUGGABLE; + } + + /* In all other cases, we're using a global proxy. */ + if (options->HTTPSProxy) return PROXY_CONNECT; else if (options->Socks4Proxy) return PROXY_SOCKS4; @@ -2380,7 +2392,7 @@ connection_proxy_connect(connection_t *conn, int type) arguments to transmit. If we do, compress all arguments to a single string in 'socks_args_string': */ - if (get_proxy_type() == PROXY_PLUGGABLE) { + if (conn_get_proxy_type(conn) == PROXY_PLUGGABLE) { socks_args_string = pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port); if (socks_args_string) @@ -2440,7 +2452,7 @@ connection_proxy_connect(connection_t *conn, int type) Socks5ProxyUsername or if we want to pass arguments to our pluggable transport proxy: */ if ((options->Socks5ProxyUsername) || - (get_proxy_type() == PROXY_PLUGGABLE && + (conn_get_proxy_type(conn) == PROXY_PLUGGABLE && (get_socks_args_by_bridge_addrport(&conn->addr, conn->port)))) { /* number of auth methods */ buf[1] = 2; @@ -2633,16 +2645,16 @@ connection_read_proxy_handshake(connection_t *conn) const char *user, *pass; char *socks_args_string = NULL; - if (get_proxy_type() == PROXY_PLUGGABLE) { + if (conn_get_proxy_type(conn) == PROXY_PLUGGABLE) { socks_args_string = pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port); if (!socks_args_string) { - log_warn(LD_NET, "Could not create SOCKS args string."); + log_warn(LD_NET, "Could not create SOCKS args string for PT."); ret = -1; break; } - log_debug(LD_NET, "SOCKS5 arguments: %s", socks_args_string); + log_debug(LD_NET, "PT SOCKS5 arguments: %s", socks_args_string); tor_assert(strlen(socks_args_string) > 0); tor_assert(strlen(socks_args_string) <= MAX_SOCKS5_AUTH_SIZE_TOTAL); @@ -2844,7 +2856,7 @@ retry_listener_ports(smartlist_t *old_conns, SMARTLIST_DEL_CURRENT(old_conns, conn); break; } -#endif +#endif /* defined(ENABLE_LISTENER_REBIND) */ } } SMARTLIST_FOREACH_END(wanted); @@ -2946,7 +2958,7 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) conn_type_to_string(old_conn->type), old_conn->address, old_conn->port, new_conn->address, new_conn->port); } SMARTLIST_FOREACH_END(r); -#endif +#endif /* defined(ENABLE_LISTENER_REBIND) */ /* Any members that were still in 'listeners' don't correspond to * any configured port. Kill 'em. */ @@ -3945,9 +3957,9 @@ update_send_buffer_size(tor_socket_t sock) &isb, sizeof(isb), &bytesReturned, NULL, NULL)) { setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (const char*)&isb, sizeof(isb)); } -#else +#else /* !(defined(_WIN32)) */ (void) sock; -#endif +#endif /* defined(_WIN32) */ } /** Try to flush more bytes onto conn-\>s. @@ -5328,7 +5340,7 @@ assert_connection_ok(connection_t *conn, time_t now) tor_assert(entry_conn->socks_request->has_finished); if (!conn->marked_for_close) { tor_assert(ENTRY_TO_EDGE_CONN(entry_conn)->cpath_layer); - assert_cpath_layer_ok(ENTRY_TO_EDGE_CONN(entry_conn)->cpath_layer); + cpath_assert_layer_ok(ENTRY_TO_EDGE_CONN(entry_conn)->cpath_layer); } } } diff --git a/src/core/mainloop/cpuworker.c b/src/core/mainloop/cpuworker.c index e704d55642..436fcd28c3 100644 --- a/src/core/mainloop/cpuworker.c +++ b/src/core/mainloop/cpuworker.c @@ -34,7 +34,6 @@ #include "core/crypto/onion_crypto.h" #include "core/or/or_circuit_st.h" -#include "lib/intmath/weakrng.h" static void queue_pending_tasks(void); @@ -74,8 +73,6 @@ worker_state_free_void(void *arg) static replyqueue_t *replyqueue = NULL; static threadpool_t *threadpool = NULL; -static tor_weak_rng_t request_sample_rng = TOR_WEAK_RNG_INIT; - static int total_pending_tasks = 0; static int max_pending_tasks = 128; @@ -109,7 +106,6 @@ cpu_init(void) /* Total voodoo. Can we make this more sensible? */ max_pending_tasks = get_num_cpus(get_options()) * 64; - crypto_seed_weak_rng(&request_sample_rng); } /** Magic numbers to make sure our cpuworker_requests don't grow any @@ -235,9 +231,10 @@ should_time_request(uint16_t onionskin_type) * sample */ if (onionskins_n_processed[onionskin_type] < 4096) return 1; + /** Otherwise, measure with P=1/128. We avoid doing this for every * handshake, since the measurement itself can take a little time. */ - return tor_weak_random_one_in_n(&request_sample_rng, 128); + return crypto_fast_rng_one_in_n(get_thread_fast_rng(), 128); } /** Return an estimate of how many microseconds we will need for a single diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c index 18e87fa87a..c051b11566 100644 --- a/src/core/mainloop/mainloop.c +++ b/src/core/mainloop/mainloop.c @@ -73,8 +73,8 @@ #include "feature/client/entrynodes.h" #include "feature/client/transports.h" #include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirauth/authmode.h" -#include "feature/dirauth/reachability.h" #include "feature/dircache/consdiffmgr.h" #include "feature/dircache/dirserv.h" #include "feature/dircommon/directory.h" @@ -105,9 +105,6 @@ #include -#include "feature/dirauth/dirvote.h" -#include "feature/dirauth/authmode.h" - #include "core/or/cell_st.h" #include "core/or/entry_connection_st.h" #include "feature/nodelist/networkstatus_st.h" @@ -757,7 +754,7 @@ tor_shutdown_event_loop_for_restart_cb( tor_event_free(tor_shutdown_event_loop_for_restart_event); tor_shutdown_event_loop_and_exit(0); } -#endif +#endif /* defined(ENABLE_RESTART_DEBUGGING) */ /** * After finishing the current callback (if any), shut down the main loop, @@ -1345,36 +1342,20 @@ static int periodic_events_initialized = 0; #define CALLBACK(name) \ static int name ## _callback(time_t, const or_options_t *) CALLBACK(add_entropy); -CALLBACK(check_authority_cert); -CALLBACK(check_canonical_channels); -CALLBACK(check_descriptor); -CALLBACK(check_dns_honesty); -CALLBACK(check_ed_keys); CALLBACK(check_expired_networkstatus); -CALLBACK(check_for_reachability_bw); -CALLBACK(check_onion_keys_expiry_time); CALLBACK(clean_caches); CALLBACK(clean_consdiffmgr); -CALLBACK(dirvote); -CALLBACK(downrate_stability); -CALLBACK(expire_old_ciruits_serverside); CALLBACK(fetch_networkstatus); CALLBACK(heartbeat); CALLBACK(hs_service); CALLBACK(launch_descriptor_fetches); -CALLBACK(launch_reachability_tests); CALLBACK(prune_old_routers); -CALLBACK(reachability_warnings); CALLBACK(record_bridge_stats); CALLBACK(rend_cache_failure_clean); CALLBACK(reset_padding_counts); -CALLBACK(retry_dns); CALLBACK(retry_listeners); -CALLBACK(rotate_onion_key); CALLBACK(rotate_x509_certificate); -CALLBACK(save_stability); CALLBACK(save_state); -CALLBACK(write_bridge_ns); CALLBACK(write_stats_file); CALLBACK(control_per_second_events); CALLBACK(second_elapsed); @@ -1386,7 +1367,7 @@ CALLBACK(second_elapsed); PERIODIC_EVENT(name, PERIODIC_EVENT_ROLE_ ## r, f) #define FL(name) (PERIODIC_EVENT_FLAG_ ## name) -STATIC periodic_event_item_t periodic_events[] = { +STATIC periodic_event_item_t mainloop_periodic_events[] = { /* Everyone needs to run these. They need to have very long timeouts for * that to be safe. */ @@ -1417,29 +1398,6 @@ STATIC periodic_event_item_t periodic_events[] = { CALLBACK(write_stats_file, NET_PARTICIPANT, FL(RUN_ON_DISABLE)), CALLBACK(prune_old_routers, NET_PARTICIPANT, FL(RUN_ON_DISABLE)), - /* Routers (bridge and relay) only. */ - CALLBACK(check_descriptor, ROUTER, FL(NEED_NET)), - CALLBACK(check_ed_keys, ROUTER, 0), - CALLBACK(check_for_reachability_bw, ROUTER, FL(NEED_NET)), - CALLBACK(check_onion_keys_expiry_time, ROUTER, 0), - CALLBACK(expire_old_ciruits_serverside, ROUTER, FL(NEED_NET)), - CALLBACK(reachability_warnings, ROUTER, FL(NEED_NET)), - CALLBACK(retry_dns, ROUTER, 0), - CALLBACK(rotate_onion_key, ROUTER, 0), - - /* Authorities (bridge and directory) only. */ - CALLBACK(downrate_stability, AUTHORITIES, 0), - CALLBACK(launch_reachability_tests, AUTHORITIES, FL(NEED_NET)), - CALLBACK(save_stability, AUTHORITIES, 0), - - /* Directory authority only. */ - CALLBACK(check_authority_cert, DIRAUTH, 0), - CALLBACK(dirvote, DIRAUTH, FL(NEED_NET)), - - /* Relay only. */ - CALLBACK(check_canonical_channels, RELAY, FL(NEED_NET)), - CALLBACK(check_dns_honesty, RELAY, FL(NEED_NET)), - /* Hidden Service service only. */ CALLBACK(hs_service, HS_SERVICE, FL(NEED_NET)), // XXXX break this down more @@ -1450,9 +1408,6 @@ STATIC periodic_event_item_t periodic_events[] = { /* XXXX this could be restricted to CLIENT+NET_PARTICIPANT */ CALLBACK(rend_cache_failure_clean, NET_PARTICIPANT, FL(RUN_ON_DISABLE)), - /* Bridge Authority only. */ - CALLBACK(write_bridge_ns, BRIDGEAUTH, 0), - /* Directory server only. */ CALLBACK(clean_consdiffmgr, DIRSERVER, 0), @@ -1468,8 +1423,6 @@ STATIC periodic_event_item_t periodic_events[] = { * implement particular callbacks. We keep them separate here so that we * can access them by name. We also keep them inside periodic_events[] * so that we can implement "reset all timers" in a reasonable way. */ -static periodic_event_item_t *check_descriptor_event=NULL; -static periodic_event_item_t *dirvote_event=NULL; static periodic_event_item_t *fetch_networkstatus_event=NULL; static periodic_event_item_t *launch_descriptor_fetches_event=NULL; static periodic_event_item_t *check_dns_honesty_event=NULL; @@ -1484,24 +1437,7 @@ static periodic_event_item_t *prune_old_routers_event=NULL; void reset_all_main_loop_timers(void) { - int i; - for (i = 0; periodic_events[i].name; ++i) { - periodic_event_reschedule(&periodic_events[i]); - } -} - -/** Return the member of periodic_events[] whose name is name. - * Return NULL if no such event is found. - */ -static periodic_event_item_t * -find_periodic_event(const char *name) -{ - int i; - for (i = 0; periodic_events[i].name; ++i) { - if (strcmp(name, periodic_events[i].name) == 0) - return &periodic_events[i]; - } - return NULL; + periodic_events_reset_all(); } /** Return a bitmask of the roles this tor instance is configured for using @@ -1564,9 +1500,9 @@ initialize_periodic_events_cb(evutil_socket_t fd, short events, void *data) rescan_periodic_events(get_options()); } -/** Set up all the members of periodic_events[], and configure them all to be - * launched from a callback. */ -STATIC void +/** Set up all the members of mainloop_periodic_events[], and configure them + * all to be launched from a callback. */ +void initialize_periodic_events(void) { if (periodic_events_initialized) @@ -1574,37 +1510,31 @@ initialize_periodic_events(void) periodic_events_initialized = 1; - /* Set up all periodic events. We'll launch them by roles. */ - int i; - for (i = 0; periodic_events[i].name; ++i) { - periodic_event_setup(&periodic_events[i]); + for (int i = 0; mainloop_periodic_events[i].name; ++i) { + periodic_events_register(&mainloop_periodic_events[i]); } + /* Set up all periodic events. We'll launch them by roles. */ + #define NAMED_CALLBACK(name) \ - STMT_BEGIN name ## _event = find_periodic_event( #name ); STMT_END + STMT_BEGIN name ## _event = periodic_events_find( #name ); STMT_END - NAMED_CALLBACK(check_descriptor); NAMED_CALLBACK(prune_old_routers); - NAMED_CALLBACK(dirvote); NAMED_CALLBACK(fetch_networkstatus); NAMED_CALLBACK(launch_descriptor_fetches); NAMED_CALLBACK(check_dns_honesty); NAMED_CALLBACK(save_state); - - struct timeval one_second = { 1, 0 }; - initialize_periodic_events_event = tor_evtimer_new( - tor_libevent_get_base(), - initialize_periodic_events_cb, NULL); - event_add(initialize_periodic_events_event, &one_second); } STATIC void teardown_periodic_events(void) { - int i; - for (i = 0; periodic_events[i].name; ++i) { - periodic_event_destroy(&periodic_events[i]); - } + periodic_events_disconnect_all(); + fetch_networkstatus_event = NULL; + launch_descriptor_fetches_event = NULL; + check_dns_honesty_event = NULL; + save_state_event = NULL; + prune_old_routers_event = NULL; periodic_events_initialized = 0; } @@ -1639,40 +1569,7 @@ rescan_periodic_events(const or_options_t *options) { tor_assert(options); - /* Avoid scanning the event list if we haven't initialized it yet. This is - * particularly useful for unit tests in order to avoid initializing main - * loop events everytime. */ - if (!periodic_events_initialized) { - return; - } - - int roles = get_my_roles(options); - - for (int i = 0; periodic_events[i].name; ++i) { - periodic_event_item_t *item = &periodic_events[i]; - - int enable = !!(item->roles & roles); - - /* Handle the event flags. */ - if (net_is_disabled() && - (item->flags & PERIODIC_EVENT_FLAG_NEED_NET)) { - enable = 0; - } - - /* Enable the event if needed. It is safe to enable an event that was - * already enabled. Same goes for disabling it. */ - if (enable) { - log_debug(LD_GENERAL, "Launching periodic event %s", item->name); - periodic_event_enable(item); - } else { - log_debug(LD_GENERAL, "Disabling periodic event %s", item->name); - if (item->flags & PERIODIC_EVENT_FLAG_RUN_ON_DISABLE) { - periodic_event_schedule_and_disable(item); - } else { - periodic_event_disable(item); - } - } - } + periodic_events_rescan_by_roles(get_my_roles(options), net_is_disabled()); } /* We just got new options globally set, see if we need to enabled or disable @@ -1680,26 +1577,7 @@ rescan_periodic_events(const or_options_t *options) void periodic_events_on_new_options(const or_options_t *options) { - /* Only if we've already initialized the events, rescan the list which will - * enable or disable events depending on our roles. This will be called at - * bootup and we don't want this function to initialize the events because - * they aren't set up at this stage. */ - if (periodic_events_initialized) { - rescan_periodic_events(options); - } -} - -/** - * Update our schedule so that we'll check whether we need to update our - * descriptor immediately, rather than after up to CHECK_DESCRIPTOR_INTERVAL - * seconds. - */ -void -reschedule_descriptor_update_check(void) -{ - if (check_descriptor_event) { - periodic_event_reschedule(check_descriptor_event); - } + rescan_periodic_events(options); } /** @@ -1769,29 +1647,6 @@ mainloop_schedule_shutdown(int delay_sec) mainloop_event_schedule(scheduled_shutdown_ev, &delay_tv); } -#define LONGEST_TIMER_PERIOD (30 * 86400) -/** Helper: Return the number of seconds between now and next, - * clipped to the range [1 second, LONGEST_TIMER_PERIOD]. */ -static inline int -safe_timer_diff(time_t now, time_t next) -{ - if (next > now) { - /* There were no computers at signed TIME_MIN (1902 on 32-bit systems), - * and nothing that could run Tor. It's a bug if 'next' is around then. - * On 64-bit systems with signed TIME_MIN, TIME_MIN is before the Big - * Bang. We cannot extrapolate past a singularity, but there was probably - * nothing that could run Tor then, either. - **/ - tor_assert(next > TIME_MIN + LONGEST_TIMER_PERIOD); - - if (next - LONGEST_TIMER_PERIOD > now) - return LONGEST_TIMER_PERIOD; - return (int)(next - now); - } else { - return 1; - } -} - /** Perform regular maintenance tasks. This function gets run once per * second. */ @@ -1867,77 +1722,6 @@ second_elapsed_callback(time_t now, const or_options_t *options) return 1; } -/* Periodic callback: rotate the onion keys after the period defined by the - * "onion-key-rotation-days" consensus parameter, shut down and restart all - * cpuworkers, and update our descriptor if necessary. - */ -static int -rotate_onion_key_callback(time_t now, const or_options_t *options) -{ - if (server_mode(options)) { - int onion_key_lifetime = get_onion_key_lifetime(); - time_t rotation_time = get_onion_key_set_at()+onion_key_lifetime; - if (rotation_time > now) { - return ONION_KEY_CONSENSUS_CHECK_INTERVAL; - } - - log_info(LD_GENERAL,"Rotating onion key."); - rotate_onion_key(); - cpuworkers_rotate_keyinfo(); - if (router_rebuild_descriptor(1)<0) { - log_info(LD_CONFIG, "Couldn't rebuild router descriptor"); - } - if (advertised_server_mode() && !net_is_disabled()) - router_upload_dir_desc_to_dirservers(0); - return ONION_KEY_CONSENSUS_CHECK_INTERVAL; - } - return PERIODIC_EVENT_NO_UPDATE; -} - -/* Period callback: Check if our old onion keys are still valid after the - * period of time defined by the consensus parameter - * "onion-key-grace-period-days", otherwise expire them by setting them to - * NULL. - */ -static int -check_onion_keys_expiry_time_callback(time_t now, const or_options_t *options) -{ - if (server_mode(options)) { - int onion_key_grace_period = get_onion_key_grace_period(); - time_t expiry_time = get_onion_key_set_at()+onion_key_grace_period; - if (expiry_time > now) { - return ONION_KEY_CONSENSUS_CHECK_INTERVAL; - } - - log_info(LD_GENERAL, "Expiring old onion keys."); - expire_old_onion_keys(); - cpuworkers_rotate_keyinfo(); - return ONION_KEY_CONSENSUS_CHECK_INTERVAL; - } - - return PERIODIC_EVENT_NO_UPDATE; -} - -/* Periodic callback: Every 30 seconds, check whether it's time to make new - * Ed25519 subkeys. - */ -static int -check_ed_keys_callback(time_t now, const or_options_t *options) -{ - if (server_mode(options)) { - if (should_make_new_ed_keys(options, now)) { - int new_signing_key = load_ed_keys(options, now); - if (new_signing_key < 0 || - generate_ed_link_cert(options, now, new_signing_key > 0)) { - log_err(LD_OR, "Unable to update Ed25519 keys! Exiting."); - tor_shutdown_event_loop_and_exit(1); - } - } - return 30; - } - return PERIODIC_EVENT_NO_UPDATE; -} - /** * Periodic callback: Every {LAZY,GREEDY}_DESCRIPTOR_RETRY_INTERVAL, * see about fetching descriptors, microdescriptors, and extrainfo @@ -2060,102 +1844,6 @@ check_network_participation_callback(time_t now, const or_options_t *options) return CHECK_PARTICIPATION_INTERVAL; } -/** - * Periodic callback: if we're an authority, make sure we test - * the routers on the network for reachability. - */ -static int -launch_reachability_tests_callback(time_t now, const or_options_t *options) -{ - if (authdir_mode_tests_reachability(options) && - !net_is_disabled()) { - /* try to determine reachability of the other Tor relays */ - dirserv_test_reachability(now); - } - return REACHABILITY_TEST_INTERVAL; -} - -/** - * Periodic callback: if we're an authority, discount the stability - * information (and other rephist information) that's older. - */ -static int -downrate_stability_callback(time_t now, const or_options_t *options) -{ - (void)options; - /* 1d. Periodically, we discount older stability information so that new - * stability info counts more, and save the stability information to disk as - * appropriate. */ - time_t next = rep_hist_downrate_old_runs(now); - return safe_timer_diff(now, next); -} - -/** - * Periodic callback: if we're an authority, record our measured stability - * information from rephist in an mtbf file. - */ -static int -save_stability_callback(time_t now, const or_options_t *options) -{ - if (authdir_mode_tests_reachability(options)) { - if (rep_hist_record_mtbf_data(now, 1)<0) { - log_warn(LD_GENERAL, "Couldn't store mtbf data."); - } - } -#define SAVE_STABILITY_INTERVAL (30*60) - return SAVE_STABILITY_INTERVAL; -} - -/** - * Periodic callback: if we're an authority, check on our authority - * certificate (the one that authenticates our authority signing key). - */ -static int -check_authority_cert_callback(time_t now, const or_options_t *options) -{ - (void)now; - (void)options; - /* 1e. Periodically, if we're a v3 authority, we check whether our cert is - * close to expiring and warn the admin if it is. */ - v3_authority_check_key_expiry(); -#define CHECK_V3_CERTIFICATE_INTERVAL (5*60) - return CHECK_V3_CERTIFICATE_INTERVAL; -} - -/** - * Scheduled callback: Run directory-authority voting functionality. - * - * The schedule is a bit complicated here, so dirvote_act() manages the - * schedule itself. - **/ -static int -dirvote_callback(time_t now, const or_options_t *options) -{ - if (!authdir_mode_v3(options)) { - tor_assert_nonfatal_unreached(); - return 3600; - } - - time_t next = dirvote_act(options, now); - if (BUG(next == TIME_MAX)) { - /* This shouldn't be returned unless we called dirvote_act() without - * being an authority. If it happens, maybe our configuration will - * fix itself in an hour or so? */ - return 3600; - } - return safe_timer_diff(now, next); -} - -/** Reschedule the directory-authority voting event. Run this whenever the - * schedule has changed. */ -void -reschedule_dirvote(const or_options_t *options) -{ - if (periodic_events_initialized && authdir_mode_v3(options)) { - periodic_event_reschedule(dirvote_event); - } -} - /** * Periodic callback: If our consensus is too old, recalculate whether * we can actually use it. @@ -2254,17 +1942,6 @@ write_stats_file_callback(time_t now, const or_options_t *options) return safe_timer_diff(now, next_time_to_write_stats_files); } -#define CHANNEL_CHECK_INTERVAL (60*60) -static int -check_canonical_channels_callback(time_t now, const or_options_t *options) -{ - (void)now; - if (public_server_mode(options)) - channel_check_for_duplicates(); - - return CHANNEL_CHECK_INTERVAL; -} - static int reset_padding_counts_callback(time_t now, const or_options_t *options) { @@ -2338,19 +2015,6 @@ rend_cache_failure_clean_callback(time_t now, const or_options_t *options) return 30; } -/** - * Periodic callback: If we're a server and initializing dns failed, retry. - */ -static int -retry_dns_callback(time_t now, const or_options_t *options) -{ - (void)now; -#define RETRY_DNS_INTERVAL (10*60) - if (server_mode(options) && has_dns_init_failed()) - dns_init(); - return RETRY_DNS_INTERVAL; -} - /** * Periodic callback: prune routerlist of old information about Tor network. */ @@ -2372,71 +2036,6 @@ prune_old_routers_callback(time_t now, const or_options_t *options) return ROUTERLIST_PRUNING_INTERVAL; } -/** Periodic callback: consider rebuilding or and re-uploading our descriptor - * (if we've passed our internal checks). */ -static int -check_descriptor_callback(time_t now, const or_options_t *options) -{ -/** How often do we check whether part of our router info has changed in a - * way that would require an upload? That includes checking whether our IP - * address has changed. */ -#define CHECK_DESCRIPTOR_INTERVAL (60) - - (void)options; - - /* 2b. Once per minute, regenerate and upload the descriptor if the old - * one is inaccurate. */ - if (!net_is_disabled()) { - check_descriptor_bandwidth_changed(now); - check_descriptor_ipaddress_changed(now); - mark_my_descriptor_dirty_if_too_old(now); - consider_publishable_server(0); - } - - return CHECK_DESCRIPTOR_INTERVAL; -} - -/** - * Periodic callback: check whether we're reachable (as a relay), and - * whether our bandwidth has changed enough that we need to - * publish a new descriptor. - */ -static int -check_for_reachability_bw_callback(time_t now, const or_options_t *options) -{ - /* XXXX This whole thing was stuck in the middle of what is now - * XXXX check_descriptor_callback. I'm not sure it's right. */ - - static int dirport_reachability_count = 0; - /* also, check religiously for reachability, if it's within the first - * 20 minutes of our uptime. */ - if (server_mode(options) && - (have_completed_a_circuit() || !any_predicted_circuits(now)) && - !net_is_disabled()) { - if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { - router_do_reachability_checks(1, dirport_reachability_count==0); - if (++dirport_reachability_count > 5) - dirport_reachability_count = 0; - return 1; - } else { - /* If we haven't checked for 12 hours and our bandwidth estimate is - * low, do another bandwidth test. This is especially important for - * bridges, since they might go long periods without much use. */ - const routerinfo_t *me = router_get_my_routerinfo(); - static int first_time = 1; - if (!first_time && me && - me->bandwidthcapacity < me->bandwidthrate && - me->bandwidthcapacity < 51200) { - reset_bandwidth_test(); - } - first_time = 0; -#define BANDWIDTH_RECHECK_INTERVAL (12*60*60) - return BANDWIDTH_RECHECK_INTERVAL; - } - } - return CHECK_DESCRIPTOR_INTERVAL; -} - /** * Periodic event: once a minute, (or every second if TestingTorNetwork, or * during client bootstrap), check whether we want to download any @@ -2479,109 +2078,6 @@ retry_listeners_callback(time_t now, const or_options_t *options) return PERIODIC_EVENT_NO_UPDATE; } -/** - * Periodic callback: as a server, see if we have any old unused circuits - * that should be expired */ -static int -expire_old_ciruits_serverside_callback(time_t now, const or_options_t *options) -{ - (void)options; - /* every 11 seconds, so not usually the same second as other such events */ - circuit_expire_old_circuits_serverside(now); - return 11; -} - -/** - * Callback: Send warnings if Tor doesn't find its ports reachable. - */ -static int -reachability_warnings_callback(time_t now, const or_options_t *options) -{ - (void) now; - - if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { - return (int)(TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT - get_uptime()); - } - - if (server_mode(options) && - !net_is_disabled() && - have_completed_a_circuit()) { - /* every 20 minutes, check and complain if necessary */ - const routerinfo_t *me = router_get_my_routerinfo(); - if (me && !check_whether_orport_reachable(options)) { - char *address = tor_dup_ip(me->addr); - log_warn(LD_CONFIG,"Your server (%s:%d) has not managed to confirm that " - "its ORPort is reachable. Relays do not publish descriptors " - "until their ORPort and DirPort are reachable. Please check " - "your firewalls, ports, address, /etc/hosts file, etc.", - address, me->or_port); - control_event_server_status(LOG_WARN, - "REACHABILITY_FAILED ORADDRESS=%s:%d", - address, me->or_port); - tor_free(address); - } - - if (me && !check_whether_dirport_reachable(options)) { - char *address = tor_dup_ip(me->addr); - log_warn(LD_CONFIG, - "Your server (%s:%d) has not managed to confirm that its " - "DirPort is reachable. Relays do not publish descriptors " - "until their ORPort and DirPort are reachable. Please check " - "your firewalls, ports, address, /etc/hosts file, etc.", - address, me->dir_port); - control_event_server_status(LOG_WARN, - "REACHABILITY_FAILED DIRADDRESS=%s:%d", - address, me->dir_port); - tor_free(address); - } - } - - return TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT; -} - -static int dns_honesty_first_time = 1; - -/** - * Periodic event: if we're an exit, see if our DNS server is telling us - * obvious lies. - */ -static int -check_dns_honesty_callback(time_t now, const or_options_t *options) -{ - (void)now; - /* 9. and if we're an exit node, check whether our DNS is telling stories - * to us. */ - if (net_is_disabled() || - ! public_server_mode(options) || - router_my_exit_policy_is_reject_star()) - return PERIODIC_EVENT_NO_UPDATE; - - if (dns_honesty_first_time) { - /* Don't launch right when we start */ - dns_honesty_first_time = 0; - return crypto_rand_int_range(60, 180); - } - - dns_launch_correctness_checks(); - return 12*3600 + crypto_rand_int(12*3600); -} - -/** - * Periodic callback: if we're the bridge authority, write a networkstatus - * file to disk. - */ -static int -write_bridge_ns_callback(time_t now, const or_options_t *options) -{ - /* 10. write bridge networkstatus file to disk */ - if (options->BridgeAuthoritativeDir) { - networkstatus_dump_bridge_status_to_file(now); -#define BRIDGE_STATUSFILE_INTERVAL (30*60) - return BRIDGE_STATUSFILE_INTERVAL; - } - return PERIODIC_EVENT_NO_UPDATE; -} - static int heartbeat_callback_first_time = 1; /** @@ -2797,8 +2293,7 @@ dns_servers_relaunch_checks(void) { if (server_mode(get_options())) { dns_reset_correctness_checks(); - if (periodic_events_initialized) { - tor_assert(check_dns_honesty_event); + if (check_dns_honesty_event) { periodic_event_reschedule(check_dns_honesty_event); } } @@ -2808,8 +2303,6 @@ dns_servers_relaunch_checks(void) void initialize_mainloop_events(void) { - initialize_periodic_events(); - if (!schedule_active_linked_connections_event) { schedule_active_linked_connections_event = mainloop_event_postloop_new(schedule_active_linked_connections_cb, NULL); @@ -2827,9 +2320,17 @@ do_main_loop(void) /* initialize the periodic events first, so that code that depends on the * events being present does not assert. */ - initialize_periodic_events(); + tor_assert(periodic_events_initialized); initialize_mainloop_events(); + periodic_events_connect_all(); + + struct timeval one_second = { 1, 0 }; + initialize_periodic_events_event = tor_evtimer_new( + tor_libevent_get_base(), + initialize_periodic_events_cb, NULL); + event_add(initialize_periodic_events_event, &one_second); + #ifdef HAVE_SYSTEMD_209 uint64_t watchdog_delay; /* set up systemd watchdog notification. */ @@ -2874,7 +2375,7 @@ do_main_loop(void) event_add(tor_shutdown_event_loop_for_restart_event, &restart_after); } } -#endif +#endif /* defined(ENABLE_RESTART_DEBUGGING) */ return run_main_loop_until_done(); } @@ -3042,7 +2543,6 @@ tor_mainloop_free_all(void) can_complete_circuits = 0; quiet_level = 0; should_init_bridge_stats = 1; - dns_honesty_first_time = 1; heartbeat_callback_first_time = 1; current_second = 0; memset(¤t_second_last_changed, 0, diff --git a/src/core/mainloop/mainloop.h b/src/core/mainloop/mainloop.h index 6ed93fa900..caef736c15 100644 --- a/src/core/mainloop/mainloop.h +++ b/src/core/mainloop/mainloop.h @@ -59,10 +59,8 @@ void directory_info_has_arrived(time_t now, int from_cache, int suppress_logs); void ip_address_changed(int at_interface); void dns_servers_relaunch_checks(void); void reset_all_main_loop_timers(void); -void reschedule_descriptor_update_check(void); void reschedule_directory_downloads(void); void reschedule_or_state_save(void); -void reschedule_dirvote(const or_options_t *options); void mainloop_schedule_postloop_cleanup(void); void rescan_periodic_events(const or_options_t *options); MOCK_DECL(void, schedule_rescan_periodic_events,(void)); @@ -90,6 +88,7 @@ void mainloop_schedule_shutdown(int delay_sec); void tor_init_connection_lists(void); void initialize_mainloop_events(void); +void initialize_periodic_events(void); void tor_mainloop_free_all(void); struct token_bucket_rw_t; @@ -102,7 +101,6 @@ extern struct token_bucket_rw_t global_relayed_bucket; #ifdef MAINLOOP_PRIVATE STATIC int run_main_loop_until_done(void); STATIC void close_closeable_connections(void); -STATIC void initialize_periodic_events(void); STATIC void teardown_periodic_events(void); STATIC int get_my_roles(const or_options_t *); STATIC int check_network_participation_callback(time_t now, @@ -113,8 +111,8 @@ extern smartlist_t *connection_array; /* We need the periodic_event_item_t definition. */ #include "core/mainloop/periodic.h" -extern periodic_event_item_t periodic_events[]; -#endif -#endif /* defined(MAIN_PRIVATE) */ +extern periodic_event_item_t mainloop_periodic_events[]; +#endif /* defined(TOR_UNIT_TESTS) */ +#endif /* defined(MAINLOOP_PRIVATE) */ -#endif +#endif /* !defined(TOR_MAINLOOP_H) */ diff --git a/src/core/mainloop/mainloop_pubsub.c b/src/core/mainloop/mainloop_pubsub.c new file mode 100644 index 0000000000..53275d8119 --- /dev/null +++ b/src/core/mainloop/mainloop_pubsub.c @@ -0,0 +1,170 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" + +#include "core/or/or.h" +#include "core/mainloop/mainloop.h" +#include "core/mainloop/mainloop_pubsub.h" + +#include "lib/container/smartlist.h" +#include "lib/dispatch/dispatch.h" +#include "lib/dispatch/dispatch_naming.h" +#include "lib/evloop/compat_libevent.h" +#include "lib/pubsub/pubsub.h" +#include "lib/pubsub/pubsub_build.h" + +/** + * Dispatcher to use for delivering messages. + **/ +static dispatch_t *the_dispatcher = NULL; +static pubsub_items_t *the_pubsub_items = NULL; +/** + * A list of mainloop_event_t, indexed by channel ID, to flush the messages + * on a channel. + **/ +static smartlist_t *alert_events = NULL; + +/** + * Mainloop event callback: flush all the messages in a channel. + * + * The channel is encoded as a pointer, and passed via arg. + **/ +static void +flush_channel_event(mainloop_event_t *ev, void *arg) +{ + (void)ev; + if (!the_dispatcher) + return; + + channel_id_t chan = (channel_id_t)(uintptr_t)(arg); + dispatch_flush(the_dispatcher, chan, INT_MAX); +} + +/** + * Construct our global pubsub object from builder. Return 0 on + * success, -1 on failure. */ +int +tor_mainloop_connect_pubsub(struct pubsub_builder_t *builder) +{ + int rv = -1; + tor_mainloop_disconnect_pubsub(); + + the_dispatcher = pubsub_builder_finalize(builder, &the_pubsub_items); + if (! the_dispatcher) + goto err; + + rv = 0; + goto done; + err: + tor_mainloop_disconnect_pubsub(); + done: + return rv; +} + +/** + * Install libevent events for all of the pubsub channels. + * + * Invoke this after tor_mainloop_connect_pubsub, and after libevent has been + * initialized. + */ +void +tor_mainloop_connect_pubsub_events(void) +{ + tor_assert(the_dispatcher); + tor_assert(! alert_events); + + const size_t num_channels = get_num_channel_ids(); + alert_events = smartlist_new(); + for (size_t i = 0; i < num_channels; ++i) { + smartlist_add(alert_events, + mainloop_event_postloop_new(flush_channel_event, + (void*)(uintptr_t)(i))); + } +} + +/** + * Dispatch alertfn callback: do nothing. Implements DELIV_NEVER. + **/ +static void +alertfn_never(dispatch_t *d, channel_id_t chan, void *arg) +{ + (void)d; + (void)chan; + (void)arg; +} + +/** + * Dispatch alertfn callback: activate a mainloop event. Implements + * DELIV_PROMPT. + **/ +static void +alertfn_prompt(dispatch_t *d, channel_id_t chan, void *arg) +{ + (void)d; + (void)chan; + mainloop_event_t *event = arg; + mainloop_event_activate(event); +} + +/** + * Dispatch alertfn callback: flush all messages right now. Implements + * DELIV_IMMEDIATE. + **/ +static void +alertfn_immediate(dispatch_t *d, channel_id_t chan, void *arg) +{ + (void) arg; + dispatch_flush(d, chan, INT_MAX); +} + +/** + * Set the strategy to be used for delivering messages on the named channel. + * + * This function needs to be called once globally for each channel, to + * set up how messages are delivered. + **/ +int +tor_mainloop_set_delivery_strategy(const char *msg_channel_name, + deliv_strategy_t strategy) +{ + channel_id_t chan = get_channel_id(msg_channel_name); + if (BUG(chan == ERROR_ID) || + BUG(chan >= smartlist_len(alert_events))) + return -1; + + switch (strategy) { + case DELIV_NEVER: + dispatch_set_alert_fn(the_dispatcher, chan, alertfn_never, NULL); + break; + case DELIV_PROMPT: + dispatch_set_alert_fn(the_dispatcher, chan, alertfn_prompt, + smartlist_get(alert_events, chan)); + break; + case DELIV_IMMEDIATE: + dispatch_set_alert_fn(the_dispatcher, chan, alertfn_immediate, NULL); + break; + } + return 0; +} + +/** + * Remove all pubsub dispatchers and events from the mainloop. + **/ +void +tor_mainloop_disconnect_pubsub(void) +{ + if (the_pubsub_items) { + pubsub_items_clear_bindings(the_pubsub_items); + pubsub_items_free(the_pubsub_items); + } + if (alert_events) { + SMARTLIST_FOREACH(alert_events, mainloop_event_t *, ev, + mainloop_event_free(ev)); + smartlist_free(alert_events); + } + dispatch_free(the_dispatcher); +} diff --git a/src/core/mainloop/mainloop_pubsub.h b/src/core/mainloop/mainloop_pubsub.h new file mode 100644 index 0000000000..365a3dd565 --- /dev/null +++ b/src/core/mainloop/mainloop_pubsub.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_MAINLOOP_PUBSUB_H +#define TOR_MAINLOOP_PUBSUB_H + +struct pubsub_builder_t; + +typedef enum { + DELIV_NEVER=0, + DELIV_PROMPT, + DELIV_IMMEDIATE, +} deliv_strategy_t; + +int tor_mainloop_connect_pubsub(struct pubsub_builder_t *builder); +void tor_mainloop_connect_pubsub_events(void); +int tor_mainloop_set_delivery_strategy(const char *msg_channel_name, + deliv_strategy_t strategy); +void tor_mainloop_disconnect_pubsub(void); + +#endif /* !defined(TOR_MAINLOOP_PUBSUB_H) */ diff --git a/src/core/mainloop/mainloop_sys.c b/src/core/mainloop/mainloop_sys.c new file mode 100644 index 0000000000..fbd5a40327 --- /dev/null +++ b/src/core/mainloop/mainloop_sys.c @@ -0,0 +1,32 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "core/or/or.h" +#include "core/mainloop/mainloop_sys.h" +#include "core/mainloop/mainloop.h" + +#include "lib/subsys/subsys.h" + +static int +subsys_mainloop_initialize(void) +{ + initialize_periodic_events(); + return 0; +} + +static void +subsys_mainloop_shutdown(void) +{ + tor_mainloop_free_all(); +} + +const struct subsys_fns_t sys_mainloop = { + .name = "mainloop", + .supported = true, + .level = 5, + .initialize = subsys_mainloop_initialize, + .shutdown = subsys_mainloop_shutdown, +}; diff --git a/src/core/mainloop/mainloop_sys.h b/src/core/mainloop/mainloop_sys.h new file mode 100644 index 0000000000..fa74fe5d4b --- /dev/null +++ b/src/core/mainloop/mainloop_sys.h @@ -0,0 +1,12 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef MAINLOOP_SYS_H +#define MAINLOOP_SYS_H + +extern const struct subsys_fns_t sys_mainloop; + +#endif /* !defined(MAINLOOP_SYS_H) */ diff --git a/src/core/mainloop/netstatus.h b/src/core/mainloop/netstatus.h index aba631e2fb..e8469ff558 100644 --- a/src/core/mainloop/netstatus.h +++ b/src/core/mainloop/netstatus.h @@ -21,4 +21,4 @@ void netstatus_flush_to_state(or_state_t *state, time_t now); void netstatus_load_from_state(const or_state_t *state, time_t now); void netstatus_note_clock_jumped(time_t seconds_diff); -#endif +#endif /* !defined(TOR_NETSTATUS_H) */ diff --git a/src/core/mainloop/periodic.c b/src/core/mainloop/periodic.c index c0363b15ea..dbc4553a73 100644 --- a/src/core/mainloop/periodic.c +++ b/src/core/mainloop/periodic.c @@ -6,9 +6,22 @@ * * \brief Generic backend for handling periodic events. * - * The events in this module are used by main.c to track items that need + * The events in this module are used to track items that need * to fire once every N seconds, possibly picking a new interval each time - * that they fire. See periodic_events[] in main.c for examples. + * that they fire. See periodic_events[] in mainloop.c for examples. + * + * This module manages a global list of periodic_event_item_t objects, + * each corresponding to a single event. To register an event, pass it to + * periodic_events_register() when initializing your subsystem. + * + * Registering an event makes the periodic event subsystem know about it, but + * doesn't cause the event to get created immediately. Before the event can + * be started, periodic_event_connect_all() must be called by mainloop.c to + * connect all the events to Libevent. + * + * We expect that periodic_event_item_t objects will be statically allocated; + * we set them up and tear them down here, but we don't take ownership of + * them. */ #include "core/or/or.h" @@ -24,6 +37,12 @@ */ static const int MAX_INTERVAL = 10 * 365 * 86400; +/** + * Global list of periodic events that have been registered with + * periodic_event_register. + **/ +static smartlist_t *the_periodic_events = NULL; + /** Set the event event to run in next_interval seconds from * now. */ static void @@ -87,15 +106,16 @@ periodic_event_dispatch(mainloop_event_t *ev, void *data) void periodic_event_reschedule(periodic_event_item_t *event) { - /* Don't reschedule a disabled event. */ - if (periodic_event_is_enabled(event)) { + /* Don't reschedule a disabled or uninitialized event. */ + if (event->ev && periodic_event_is_enabled(event)) { periodic_event_set_interval(event, 1); } } -/** Initializes the libevent backend for a periodic event. */ +/** Connects a periodic event to the Libevent backend. Does not launch the + * event immediately. */ void -periodic_event_setup(periodic_event_item_t *event) +periodic_event_connect(periodic_event_item_t *event) { if (event->ev) { /* Already setup? This is a bug */ log_err(LD_BUG, "Initial dispatch should only be done once."); @@ -113,7 +133,7 @@ void periodic_event_launch(periodic_event_item_t *event) { if (! event->ev) { /* Not setup? This is a bug */ - log_err(LD_BUG, "periodic_event_launch without periodic_event_setup"); + log_err(LD_BUG, "periodic_event_launch without periodic_event_connect"); tor_assert(0); } /* Event already enabled? This is a bug */ @@ -127,9 +147,9 @@ periodic_event_launch(periodic_event_item_t *event) periodic_event_dispatch(event->ev, event); } -/** Release all storage associated with event */ -void -periodic_event_destroy(periodic_event_item_t *event) +/** Disconnect and unregister the periodic event in event */ +static void +periodic_event_disconnect(periodic_event_item_t *event) { if (!event) return; @@ -184,3 +204,161 @@ periodic_event_schedule_and_disable(periodic_event_item_t *event) mainloop_event_activate(event->ev); } + +/** + * Add item to the list of periodic events. + * + * Note that item should be statically allocated: we do not + * take ownership of it. + **/ +void +periodic_events_register(periodic_event_item_t *item) +{ + if (!the_periodic_events) + the_periodic_events = smartlist_new(); + + if (BUG(smartlist_contains(the_periodic_events, item))) + return; + + smartlist_add(the_periodic_events, item); +} + +/** + * Make all registered periodic events connect to the libevent backend. + */ +void +periodic_events_connect_all(void) +{ + if (! the_periodic_events) + return; + + SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) { + if (item->ev) + continue; + periodic_event_connect(item); + } SMARTLIST_FOREACH_END(item); +} + +/** + * Reset all the registered periodic events so we'll do all our actions again + * as if we just started up. + * + * Useful if our clock just moved back a long time from the future, + * so we don't wait until that future arrives again before acting. + */ +void +periodic_events_reset_all(void) +{ + if (! the_periodic_events) + return; + + SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) { + if (!item->ev) + continue; + + periodic_event_reschedule(item); + } SMARTLIST_FOREACH_END(item); +} + +/** + * Return the registered periodic event whose name is name. + * Return NULL if no such event is found. + */ +periodic_event_item_t * +periodic_events_find(const char *name) +{ + if (! the_periodic_events) + return NULL; + + SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) { + if (strcmp(name, item->name) == 0) + return item; + } SMARTLIST_FOREACH_END(item); + return NULL; +} + +/** + * Start or stop registered periodic events, depending on our current set of + * roles. + * + * Invoked when our list of roles, or the net_disabled flag has changed. + **/ +void +periodic_events_rescan_by_roles(int roles, bool net_disabled) +{ + if (! the_periodic_events) + return; + + SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) { + if (!item->ev) + continue; + + int enable = !!(item->roles & roles); + + /* Handle the event flags. */ + if (net_disabled && + (item->flags & PERIODIC_EVENT_FLAG_NEED_NET)) { + enable = 0; + } + + /* Enable the event if needed. It is safe to enable an event that was + * already enabled. Same goes for disabling it. */ + if (enable) { + log_debug(LD_GENERAL, "Launching periodic event %s", item->name); + periodic_event_enable(item); + } else { + log_debug(LD_GENERAL, "Disabling periodic event %s", item->name); + if (item->flags & PERIODIC_EVENT_FLAG_RUN_ON_DISABLE) { + periodic_event_schedule_and_disable(item); + } else { + periodic_event_disable(item); + } + } + } SMARTLIST_FOREACH_END(item); +} + +/** + * Invoked at shutdown: disconnect and unregister all periodic events. + * + * Does not free the periodic_event_item_t object themselves, because we do + * not own them. + */ +void +periodic_events_disconnect_all(void) +{ + if (! the_periodic_events) + return; + + SMARTLIST_FOREACH_BEGIN(the_periodic_events, periodic_event_item_t *, item) { + periodic_event_disconnect(item); + } SMARTLIST_FOREACH_END(item); + + smartlist_free(the_periodic_events); +} + +#define LONGEST_TIMER_PERIOD (30 * 86400) +/** Helper: Return the number of seconds between now and next, + * clipped to the range [1 second, LONGEST_TIMER_PERIOD]. + * + * We use this to answer the question, "how many seconds is it from now until + * next" in periodic timer callbacks. Don't use it for other purposes + **/ +int +safe_timer_diff(time_t now, time_t next) +{ + if (next > now) { + /* There were no computers at signed TIME_MIN (1902 on 32-bit systems), + * and nothing that could run Tor. It's a bug if 'next' is around then. + * On 64-bit systems with signed TIME_MIN, TIME_MIN is before the Big + * Bang. We cannot extrapolate past a singularity, but there was probably + * nothing that could run Tor then, either. + **/ + tor_assert(next > TIME_MIN + LONGEST_TIMER_PERIOD); + + if (next - LONGEST_TIMER_PERIOD > now) + return LONGEST_TIMER_PERIOD; + return (int)(next - now); + } else { + return 1; + } +} diff --git a/src/core/mainloop/periodic.h b/src/core/mainloop/periodic.h index 344fc9ad25..a9aa461969 100644 --- a/src/core/mainloop/periodic.h +++ b/src/core/mainloop/periodic.h @@ -83,11 +83,20 @@ periodic_event_is_enabled(const periodic_event_item_t *item) } void periodic_event_launch(periodic_event_item_t *event); -void periodic_event_setup(periodic_event_item_t *event); -void periodic_event_destroy(periodic_event_item_t *event); +void periodic_event_connect(periodic_event_item_t *event); +//void periodic_event_disconnect(periodic_event_item_t *event); void periodic_event_reschedule(periodic_event_item_t *event); void periodic_event_enable(periodic_event_item_t *event); void periodic_event_disable(periodic_event_item_t *event); void periodic_event_schedule_and_disable(periodic_event_item_t *event); +void periodic_events_register(periodic_event_item_t *item); +void periodic_events_connect_all(void); +void periodic_events_reset_all(void); +periodic_event_item_t *periodic_events_find(const char *name); +void periodic_events_rescan_by_roles(int roles, bool net_disabled); +void periodic_events_disconnect_all(void); + +int safe_timer_diff(time_t now, time_t next); + #endif /* !defined(TOR_PERIODIC_H) */ diff --git a/src/core/or/addr_policy_st.h b/src/core/or/addr_policy_st.h index a75f1a731d..11442d29b4 100644 --- a/src/core/or/addr_policy_st.h +++ b/src/core/or/addr_policy_st.h @@ -43,4 +43,4 @@ struct addr_policy_t { uint16_t prt_max; /**< Highest port number to accept/reject. */ }; -#endif +#endif /* !defined(TOR_ADDR_POLICY_ST_H) */ diff --git a/src/core/or/address_set.h b/src/core/or/address_set.h index 7a9e71628e..95608a9a53 100644 --- a/src/core/or/address_set.h +++ b/src/core/or/address_set.h @@ -28,4 +28,4 @@ void address_set_add_ipv4h(address_set_t *set, uint32_t addr); int address_set_probably_contains(const address_set_t *set, const struct tor_addr_t *addr); -#endif +#endif /* !defined(TOR_ADDRESS_SET_H) */ diff --git a/src/core/or/cell_queue_st.h b/src/core/or/cell_queue_st.h index 130b95a011..7ba339b965 100644 --- a/src/core/or/cell_queue_st.h +++ b/src/core/or/cell_queue_st.h @@ -26,4 +26,4 @@ struct cell_queue_t { int n; /**< The number of cells in the queue. */ }; -#endif +#endif /* !defined(PACKED_CELL_ST_H) */ diff --git a/src/core/or/cell_st.h b/src/core/or/cell_st.h index 7ab7eceb50..c4eec4f4b5 100644 --- a/src/core/or/cell_st.h +++ b/src/core/or/cell_st.h @@ -16,5 +16,5 @@ struct cell_t { uint8_t payload[CELL_PAYLOAD_SIZE]; /**< Cell body. */ }; -#endif +#endif /* !defined(CELL_ST_H) */ diff --git a/src/core/or/channel.c b/src/core/or/channel.c index fd7bf62789..0e190809ba 100644 --- a/src/core/or/channel.c +++ b/src/core/or/channel.c @@ -1418,6 +1418,7 @@ write_packed_cell(channel_t *chan, packed_cell_t *cell) { int ret = -1; size_t cell_bytes; + uint8_t command = packed_cell_get_command(cell, chan->wide_circ_ids); tor_assert(chan); tor_assert(cell); @@ -1452,6 +1453,16 @@ write_packed_cell(channel_t *chan, packed_cell_t *cell) /* Successfully sent the cell. */ ret = 0; + /* Update padding statistics for the packed codepath.. */ + rep_hist_padding_count_write(PADDING_TYPE_TOTAL); + if (command == CELL_PADDING) + rep_hist_padding_count_write(PADDING_TYPE_CELL); + if (chan->padding_enabled) { + rep_hist_padding_count_write(PADDING_TYPE_ENABLED_TOTAL); + if (command == CELL_PADDING) + rep_hist_padding_count_write(PADDING_TYPE_ENABLED_CELL); + } + done: return ret; } diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c index f552b20770..2a6edc951c 100644 --- a/src/core/or/channeltls.c +++ b/src/core/or/channeltls.c @@ -1094,13 +1094,13 @@ channel_tls_handle_cell(cell_t *cell, or_connection_t *conn) entry_guards_note_internet_connectivity(get_guard_selection_info()); rep_hist_padding_count_read(PADDING_TYPE_TOTAL); - if (TLS_CHAN_TO_BASE(chan)->currently_padding) + if (TLS_CHAN_TO_BASE(chan)->padding_enabled) rep_hist_padding_count_read(PADDING_TYPE_ENABLED_TOTAL); switch (cell->command) { case CELL_PADDING: rep_hist_padding_count_read(PADDING_TYPE_CELL); - if (TLS_CHAN_TO_BASE(chan)->currently_padding) + if (TLS_CHAN_TO_BASE(chan)->padding_enabled) rep_hist_padding_count_read(PADDING_TYPE_ENABLED_CELL); ++stats_n_padding_cells_processed; /* do nothing */ @@ -1664,7 +1664,19 @@ tor_addr_from_netinfo_addr(tor_addr_t *tor_addr, } /** - * Process a 'netinfo' cell. + * Helper: compute the absolute value of a time_t. + * + * (we need this because labs() doesn't always work for time_t, since + * long can be shorter than time_t.) + */ +static inline time_t +time_abs(time_t val) +{ + return (val < 0) ? -val : val; +} + +/** + * Process a 'netinfo' cell * * This function is called to handle an incoming NETINFO cell; read and act * on its contents, and set the connection state to "open". @@ -1679,7 +1691,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) time_t now = time(NULL); const routerinfo_t *me = router_get_my_routerinfo(); - long apparent_skew = 0; + time_t apparent_skew = 0; tor_addr_t my_apparent_addr = TOR_ADDR_NULL; int started_here = 0; const char *identity_digest = NULL; @@ -1722,7 +1734,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) tor_assert(tor_digest_is_zero( (const char*)(chan->conn->handshake_state-> authenticated_rsa_peer_id))); - tor_assert(tor_mem_is_zero( + tor_assert(fast_mem_is_zero( (const char*)(chan->conn->handshake_state-> authenticated_ed25519_peer_id.pubkey), 32)); /* If the client never authenticated, it's a tor client or bridge @@ -1765,7 +1777,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) my_addr_type = netinfo_addr_get_addr_type(my_addr); my_addr_len = netinfo_addr_get_len(my_addr); - if (labs(now - chan->conn->handshake_state->sent_versions_at) < 180) { + if ((now - chan->conn->handshake_state->sent_versions_at) < 180) { apparent_skew = now - timestamp; } /* We used to check: @@ -1842,7 +1854,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) /* Act on apparent skew. */ /** Warn when we get a netinfo skew with at least this value. */ #define NETINFO_NOTICE_SKEW 3600 - if (labs(apparent_skew) > NETINFO_NOTICE_SKEW && + if (time_abs(apparent_skew) > NETINFO_NOTICE_SKEW && (started_here || connection_or_digest_is_known_relay(chan->conn->identity_digest))) { int trusted = router_digest_is_trusted_dir(chan->conn->identity_digest); diff --git a/src/core/or/circuit_st.h b/src/core/or/circuit_st.h index af343f082e..eae3c908d5 100644 --- a/src/core/or/circuit_st.h +++ b/src/core/or/circuit_st.h @@ -13,7 +13,7 @@ struct hs_token_t; struct circpad_machine_spec_t; -struct circpad_machine_state_t; +struct circpad_machine_runtime_t; /** Number of padding state machines on a circuit. */ #define CIRCPAD_MAX_MACHINES (2) @@ -66,12 +66,6 @@ struct circuit_t { */ circid_t n_circ_id; - /** - * Circuit mux associated with n_chan to which this circuit is attached; - * NULL if we have no n_chan. - */ - circuitmux_t *n_mux; - /** Queue of cells waiting to be transmitted on n_chan */ cell_queue_t n_chan_cells; @@ -98,6 +92,10 @@ struct circuit_t { /** True iff this circuit has received a DESTROY cell in either direction */ unsigned int received_destroy : 1; + /** True iff we have sent a sufficiently random data cell since last + * we reset send_randomness_after_n_cells. */ + unsigned int have_sent_sufficiently_random_cell : 1; + uint8_t state; /**< Current status of this circuit. */ uint8_t purpose; /**< Why are we creating this circuit? */ @@ -110,6 +108,32 @@ struct circuit_t { * circuit-level sendme cells to indicate that we're willing to accept * more. */ int deliver_window; + /** + * How many cells do we have until we need to send one that contains + * sufficient randomness? Used to ensure that authenticated SENDME cells + * will reflect some unpredictable information. + **/ + uint16_t send_randomness_after_n_cells; + + /** FIFO containing the digest of the cells that are just before a SENDME is + * sent by the client. It is done at the last cell before our package_window + * goes down to 0 which is when we expect a SENDME. + * + * Our current circuit package window is capped to 1000 + * (CIRCWINDOW_START_MAX) which is also the start value. The increment is + * set to 100 (CIRCWINDOW_INCREMENT) which means we don't allow more than + * 1000/100 = 10 outstanding SENDME cells worth of data. Meaning that this + * list can not contain more than 10 digests of DIGEST_LEN bytes (20). + * + * At position i in the list, the digest corresponds to the + * (CIRCWINDOW_INCREMENT * i)-nth cell received since we expect a SENDME to + * be received containing that cell digest. + * + * For example, position 2 (starting at 0) means that we've received 300 + * cells so the 300th cell digest is kept at index 2. + * + * At maximum, this list contains 200 bytes plus the smartlist overhead. */ + smartlist_t *sendme_last_digests; /** Temporary field used during circuits_handle_oom. */ uint32_t age_tmp; @@ -193,8 +217,8 @@ struct circuit_t { * and we can have up to CIRCPAD_MAX_MACHINES such machines. */ const struct circpad_machine_spec_t *padding_machine[CIRCPAD_MAX_MACHINES]; - /** Adaptive Padding machine info for above machines. This is the - * per-circuit mutable information, such as the current state and + /** Adaptive Padding machine runtime info for above machines. This is + * the per-circuit mutable information, such as the current state and * histogram token counts. Some of it is optional (aka NULL). * If a machine is being shut down, these indexes can be NULL * without the corresponding padding_machine being NULL, while we @@ -202,7 +226,7 @@ struct circuit_t { * * Each element of this array corresponds to a different padding machine, * and we can have up to CIRCPAD_MAX_MACHINES such machines. */ - struct circpad_machine_state_t *padding_info[CIRCPAD_MAX_MACHINES]; + struct circpad_machine_runtime_t *padding_info[CIRCPAD_MAX_MACHINES]; }; -#endif +#endif /* !defined(CIRCUIT_ST_H) */ diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c index 3ec1e01f11..3a4e729429 100644 --- a/src/core/or/circuitbuild.c +++ b/src/core/or/circuitbuild.c @@ -51,11 +51,12 @@ #include "core/or/ocirc_event.h" #include "core/or/policies.h" #include "core/or/relay.h" +#include "core/or/crypt_path.h" #include "feature/client/bridges.h" #include "feature/client/circpathbias.h" #include "feature/client/entrynodes.h" #include "feature/client/transports.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dircommon/directory.h" #include "feature/nodelist/describe.h" #include "feature/nodelist/microdesc.h" @@ -90,8 +91,6 @@ static channel_t * channel_connect_for_circuit(const tor_addr_t *addr, static int circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell, int relayed); -static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath); -STATIC int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); static int circuit_send_first_onion_skin(origin_circuit_t *circ); static int circuit_build_no_more_hops(origin_circuit_t *circ); static int circuit_send_intermediate_onion_skin(origin_circuit_t *circ, @@ -547,7 +546,7 @@ circuit_handle_first_hop(origin_circuit_t *circ) int should_launch = 0; const or_options_t *options = get_options(); - firsthop = onion_next_hop_in_cpath(circ->cpath); + firsthop = cpath_get_next_non_open_hop(circ->cpath); tor_assert(firsthop); tor_assert(firsthop->extend_info); @@ -948,7 +947,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) tor_assert(circ->cpath->state == CPATH_STATE_OPEN); tor_assert(circ->base_.state == CIRCUIT_STATE_BUILDING); - crypt_path_t *hop = onion_next_hop_in_cpath(circ->cpath); + crypt_path_t *hop = cpath_get_next_non_open_hop(circ->cpath); circuit_build_times_handle_completed_hop(circ); circpad_machine_event_circ_added_hop(circ); @@ -1360,34 +1359,6 @@ circuit_extend(cell_t *cell, circuit_t *circ) return 0; } -/** Initialize cpath-\>{f|b}_{crypto|digest} from the key material in key_data. - * - * If is_hs_v3 is set, this cpath will be used for next gen hidden - * service circuits and key_data must be at least - * HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN bytes in length. - * - * If is_hs_v3 is not set, key_data must contain CPATH_KEY_MATERIAL_LEN - * bytes, which are used as follows: - * - 20 to initialize f_digest - * - 20 to initialize b_digest - * - 16 to key f_crypto - * - 16 to key b_crypto - * - * (If 'reverse' is true, then f_XX and b_XX are swapped.) - * - * Return 0 if init was successful, else -1 if it failed. - */ -int -circuit_init_cpath_crypto(crypt_path_t *cpath, - const char *key_data, size_t key_data_len, - int reverse, int is_hs_v3) -{ - - tor_assert(cpath); - return relay_crypto_init(&cpath->crypto, key_data, key_data_len, reverse, - is_hs_v3); -} - /** A "created" cell reply came back to us on circuit circ. * (The body of reply varies depending on what sort of handshake * this is.) @@ -1413,7 +1384,7 @@ circuit_finish_handshake(origin_circuit_t *circ, if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS) { hop = circ->cpath; } else { - hop = onion_next_hop_in_cpath(circ->cpath); + hop = cpath_get_next_non_open_hop(circ->cpath); if (!hop) { /* got an extended when we're all done? */ log_warn(LD_PROTOCOL,"got extended when circ already built? Closing."); return - END_CIRC_REASON_TORPROTOCOL; @@ -1437,7 +1408,7 @@ circuit_finish_handshake(origin_circuit_t *circ, onion_handshake_state_release(&hop->handshake_state); - if (circuit_init_cpath_crypto(hop, keys, sizeof(keys), 0, 0)<0) { + if (cpath_init_circuit_crypto(hop, keys, sizeof(keys), 0, 0)<0) { return -END_CIRC_REASON_TORPROTOCOL; } @@ -1489,7 +1460,7 @@ circuit_truncated(origin_circuit_t *circ, int reason) } layer->next = victim->next; - circuit_free_cpath_node(victim); + cpath_free(victim); } log_info(LD_CIRC, "finished"); @@ -1683,7 +1654,8 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei) * to handle the desired path length, return -1. */ STATIC int -new_route_len(uint8_t purpose, extend_info_t *exit_ei, smartlist_t *nodes) +new_route_len(uint8_t purpose, extend_info_t *exit_ei, + const smartlist_t *nodes) { int routelen; @@ -2307,7 +2279,7 @@ circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *exit_ei) state->chosen_exit = extend_info_dup(exit_ei); ++circ->build_state->desired_path_len; - onion_append_hop(&circ->cpath, exit_ei); + cpath_append_hop(&circ->cpath, exit_ei); return 0; } @@ -2345,7 +2317,7 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit_ei) * particular router. See bug #25885.) */ MOCK_IMPL(STATIC int, -count_acceptable_nodes, (smartlist_t *nodes, int direct)) +count_acceptable_nodes, (const smartlist_t *nodes, int direct)) { int num=0; @@ -2372,47 +2344,6 @@ count_acceptable_nodes, (smartlist_t *nodes, int direct)) return num; } -/** Add new_hop to the end of the doubly-linked-list head_ptr. - * This function is used to extend cpath by another hop. - */ -void -onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop) -{ - if (*head_ptr) { - new_hop->next = (*head_ptr); - new_hop->prev = (*head_ptr)->prev; - (*head_ptr)->prev->next = new_hop; - (*head_ptr)->prev = new_hop; - } else { - *head_ptr = new_hop; - new_hop->prev = new_hop->next = new_hop; - } -} - -#ifdef TOR_UNIT_TESTS - -/** Unittest helper function: Count number of hops in cpath linked list. */ -unsigned int -cpath_get_n_hops(crypt_path_t **head_ptr) -{ - unsigned int n_hops = 0; - crypt_path_t *tmp; - - if (!*head_ptr) { - return 0; - } - - tmp = *head_ptr; - do { - n_hops++; - tmp = tmp->next; - } while (tmp != *head_ptr); - - return n_hops; -} - -#endif /* defined(TOR_UNIT_TESTS) */ - /** * Build the exclude list for vanguard circuits. * @@ -2687,20 +2618,6 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state, return choice; } -/** Return the first non-open hop in cpath, or return NULL if all - * hops are open. */ -static crypt_path_t * -onion_next_hop_in_cpath(crypt_path_t *cpath) -{ - crypt_path_t *hop = cpath; - do { - if (hop->state != CPATH_STATE_OPEN) - return hop; - hop = hop->next; - } while (hop != cpath); - return NULL; -} - /** Choose a suitable next hop for the circuit circ. * Append the hop info to circ->cpath. * @@ -2757,33 +2674,11 @@ onion_extend_cpath(origin_circuit_t *circ) extend_info_describe(info), cur_len+1, build_state_get_exit_nickname(state)); - onion_append_hop(&circ->cpath, info); + cpath_append_hop(&circ->cpath, info); extend_info_free(info); return 0; } -/** Create a new hop, annotate it with information about its - * corresponding router choice, and append it to the - * end of the cpath head_ptr. */ -STATIC int -onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice) -{ - crypt_path_t *hop = tor_malloc_zero(sizeof(crypt_path_t)); - - /* link hop into the cpath, at the end. */ - onion_append_to_cpath(head_ptr, hop); - - hop->magic = CRYPT_PATH_MAGIC; - hop->state = CPATH_STATE_CLOSED; - - hop->extend_info = extend_info_dup(choice); - - hop->package_window = circuit_initial_package_window(); - hop->deliver_window = CIRCWINDOW_START; - - return 0; -} - /** Allocate a new extend_info object based on the various arguments. */ extend_info_t * extend_info_new(const char *nickname, @@ -2988,7 +2883,7 @@ extend_info_supports_ntor(const extend_info_t* ei) { tor_assert(ei); /* Valid ntor keys have at least one non-zero byte */ - return !tor_mem_is_zero( + return !fast_mem_is_zero( (const char*)ei->curve25519_onion_key.public_key, CURVE25519_PUBKEY_LEN); } diff --git a/src/core/or/circuitbuild.h b/src/core/or/circuitbuild.h index b19bc41235..ad7d032cd4 100644 --- a/src/core/or/circuitbuild.h +++ b/src/core/or/circuitbuild.h @@ -34,9 +34,6 @@ int circuit_timeout_want_to_count_circ(const origin_circuit_t *circ); int circuit_send_next_onion_skin(origin_circuit_t *circ); void circuit_note_clock_jumped(int64_t seconds_elapsed, bool was_idle); int circuit_extend(cell_t *cell, circuit_t *circ); -int circuit_init_cpath_crypto(crypt_path_t *cpath, - const char *key_data, size_t key_data_len, - int reverse, int is_hs_v3); struct created_cell_t; int circuit_finish_handshake(origin_circuit_t *circ, const struct created_cell_t *created_cell); @@ -51,7 +48,6 @@ MOCK_DECL(int, circuit_all_predicted_ports_handled, (time_t now, int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info); int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info); -void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop); extend_info_t *extend_info_new(const char *nickname, const char *rsa_id_digest, const struct ed25519_public_key_t *ed_id, @@ -83,8 +79,8 @@ void circuit_upgrade_circuits_from_guard_wait(void); #ifdef CIRCUITBUILD_PRIVATE STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan); STATIC int new_route_len(uint8_t purpose, extend_info_t *exit_ei, - smartlist_t *nodes); -MOCK_DECL(STATIC int, count_acceptable_nodes, (smartlist_t *nodes, + const smartlist_t *nodes); +MOCK_DECL(STATIC int, count_acceptable_nodes, (const smartlist_t *nodes, int direct)); STATIC int onion_extend_cpath(origin_circuit_t *circ); @@ -93,11 +89,6 @@ STATIC int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei, int is_hs_v3_rp_circuit); -#if defined(TOR_UNIT_TESTS) -unsigned int cpath_get_n_hops(crypt_path_t **head_ptr); - -#endif /* defined(TOR_UNIT_TESTS) */ - #endif /* defined(CIRCUITBUILD_PRIVATE) */ #endif /* !defined(TOR_CIRCUITBUILD_H) */ diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c index 6b5f30e418..ebbe7f0824 100644 --- a/src/core/or/circuitlist.c +++ b/src/core/or/circuitlist.c @@ -63,11 +63,12 @@ #include "core/or/circuituse.h" #include "core/or/circuitstats.h" #include "core/or/circuitpadding.h" +#include "core/or/crypt_path.h" #include "core/mainloop/connection.h" #include "app/config/config.h" #include "core/or/connection_edge.h" #include "core/or/connection_or.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" #include "lib/crypt_ops/crypto_dh.h" @@ -132,7 +133,6 @@ static smartlist_t *circuits_pending_other_guards = NULL; * circuit_mark_for_close and which are waiting for circuit_about_to_free. */ static smartlist_t *circuits_pending_close = NULL; -static void circuit_free_cpath_node(crypt_path_t *victim); static void cpath_ref_decref(crypt_path_reference_t *cpath_ref); static void circuit_about_to_free_atexit(circuit_t *circ); static void circuit_about_to_free(circuit_t *circ); @@ -823,6 +823,8 @@ circuit_purpose_to_controller_string(uint8_t purpose) return "PATH_BIAS_TESTING"; case CIRCUIT_PURPOSE_HS_VANGUARDS: return "HS_VANGUARDS"; + case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: + return "CIRCUIT_PADDING"; default: tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); @@ -852,6 +854,7 @@ circuit_purpose_to_controller_hs_state_string(uint8_t purpose) case CIRCUIT_PURPOSE_CONTROLLER: case CIRCUIT_PURPOSE_PATH_BIAS_TESTING: case CIRCUIT_PURPOSE_HS_VANGUARDS: + case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: return NULL; case CIRCUIT_PURPOSE_INTRO_POINT: @@ -952,6 +955,9 @@ circuit_purpose_to_string(uint8_t purpose) case CIRCUIT_PURPOSE_HS_VANGUARDS: return "Hidden service: Pre-built vanguard circuit"; + case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: + return "Circuit kept open for padding"; + default: tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); return buf; @@ -987,6 +993,7 @@ init_circuit_base(circuit_t *circ) circ->package_window = circuit_initial_package_window(); circ->deliver_window = CIRCWINDOW_START; + circuit_reset_sendme_randomness(circ); cell_queue_init(&circ->n_chan_cells); smartlist_add(circuit_get_global_list(), circ); @@ -1148,7 +1155,7 @@ circuit_free_(circuit_t *circ) if (ocirc->build_state) { extend_info_free(ocirc->build_state->chosen_exit); - circuit_free_cpath_node(ocirc->build_state->pending_final_cpath); + cpath_free(ocirc->build_state->pending_final_cpath); cpath_ref_decref(ocirc->build_state->service_pending_final_cpath_ref); } tor_free(ocirc->build_state); @@ -1227,6 +1234,12 @@ circuit_free_(circuit_t *circ) * "active" checks will be violated. */ cell_queue_clear(&circ->n_chan_cells); + /* Cleanup possible SENDME state. */ + if (circ->sendme_last_digests) { + SMARTLIST_FOREACH(circ->sendme_last_digests, uint8_t *, d, tor_free(d)); + smartlist_free(circ->sendme_last_digests); + } + log_info(LD_CIRC, "Circuit %u (id: %" PRIu32 ") has been freed.", n_circ_id, CIRCUIT_IS_ORIGIN(circ) ? @@ -1266,10 +1279,10 @@ circuit_clear_cpath(origin_circuit_t *circ) while (cpath->next && cpath->next != head) { victim = cpath; cpath = victim->next; - circuit_free_cpath_node(victim); + cpath_free(victim); } - circuit_free_cpath_node(cpath); + cpath_free(cpath); circ->cpath = NULL; } @@ -1326,29 +1339,13 @@ circuit_free_all(void) HT_CLEAR(chan_circid_map, &chan_circid_map); } -/** Deallocate space associated with the cpath node victim. */ -static void -circuit_free_cpath_node(crypt_path_t *victim) -{ - if (!victim) - return; - - relay_crypto_clear(&victim->crypto); - onion_handshake_state_release(&victim->handshake_state); - crypto_dh_free(victim->rend_dh_handshake_state); - extend_info_free(victim->extend_info); - - memwipe(victim, 0xBB, sizeof(crypt_path_t)); /* poison memory */ - tor_free(victim); -} - /** Release a crypt_path_reference_t*, which may be NULL. */ static void cpath_ref_decref(crypt_path_reference_t *cpath_ref) { if (cpath_ref != NULL) { if (--(cpath_ref->refcount) == 0) { - circuit_free_cpath_node(cpath_ref->cpath); + cpath_free(cpath_ref->cpath); tor_free(cpath_ref); } } @@ -2199,6 +2196,11 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line, tor_assert(line); tor_assert(file); + /* Check whether the circuitpadding subsystem wants to block this close */ + if (circpad_marked_circuit_for_padding(circ, reason)) { + return; + } + if (circ->marked_for_close) { log_warn(LD_BUG, "Duplicate call to circuit_mark_for_close at %s:%d" @@ -2433,13 +2435,9 @@ marked_circuit_free_cells(circuit_t *circ) return; } cell_queue_clear(&circ->n_chan_cells); - if (circ->n_mux) - circuitmux_clear_num_cells(circ->n_mux, circ); if (! CIRCUIT_IS_ORIGIN(circ)) { or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); cell_queue_clear(&orcirc->p_chan_cells); - if (orcirc->p_mux) - circuitmux_clear_num_cells(orcirc->p_mux, circ); } } @@ -2783,59 +2781,6 @@ circuits_handle_oom(size_t current_allocation) n_dirconns_killed); } -/** Verify that cpath layer cp has all of its invariants - * correct. Trigger an assert if anything is invalid. - */ -void -assert_cpath_layer_ok(const crypt_path_t *cp) -{ -// tor_assert(cp->addr); /* these are zero for rendezvous extra-hops */ -// tor_assert(cp->port); - tor_assert(cp); - tor_assert(cp->magic == CRYPT_PATH_MAGIC); - switch (cp->state) - { - case CPATH_STATE_OPEN: - relay_crypto_assert_ok(&cp->crypto); - /* fall through */ - case CPATH_STATE_CLOSED: - /*XXXX Assert that there's no handshake_state either. */ - tor_assert(!cp->rend_dh_handshake_state); - break; - case CPATH_STATE_AWAITING_KEYS: - /* tor_assert(cp->dh_handshake_state); */ - break; - default: - log_fn(LOG_ERR, LD_BUG, "Unexpected state %d", cp->state); - tor_assert(0); - } - tor_assert(cp->package_window >= 0); - tor_assert(cp->deliver_window >= 0); -} - -/** Verify that cpath cp has all of its invariants - * correct. Trigger an assert if anything is invalid. - */ -static void -assert_cpath_ok(const crypt_path_t *cp) -{ - const crypt_path_t *start = cp; - - do { - assert_cpath_layer_ok(cp); - /* layers must be in sequence of: "open* awaiting? closed*" */ - if (cp != start) { - if (cp->state == CPATH_STATE_AWAITING_KEYS) { - tor_assert(cp->prev->state == CPATH_STATE_OPEN); - } else if (cp->state == CPATH_STATE_OPEN) { - tor_assert(cp->prev->state == CPATH_STATE_OPEN); - } - } - cp = cp->next; - tor_assert(cp); - } while (cp != start); -} - /** Verify that circuit c has all of its invariants * correct. Trigger an assert if anything is invalid. */ @@ -2897,7 +2842,7 @@ assert_circuit_ok,(const circuit_t *c)) !smartlist_contains(circuits_pending_chans, c)); } if (origin_circ && origin_circ->cpath) { - assert_cpath_ok(origin_circ->cpath); + cpath_assert_ok(origin_circ->cpath); } if (c->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED) { tor_assert(or_circ); diff --git a/src/core/or/circuitlist.h b/src/core/or/circuitlist.h index f34f4ed6b7..80c1f7ac4e 100644 --- a/src/core/or/circuitlist.h +++ b/src/core/or/circuitlist.h @@ -92,31 +92,33 @@ #define CIRCUIT_PURPOSE_C_HS_MAX_ 13 /** This circuit is used for build time measurement only */ #define CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT 14 -#define CIRCUIT_PURPOSE_C_MAX_ 14 +/** This circuit is being held open by circuit padding */ +#define CIRCUIT_PURPOSE_C_CIRCUIT_PADDING 15 +#define CIRCUIT_PURPOSE_C_MAX_ 15 -#define CIRCUIT_PURPOSE_S_HS_MIN_ 15 +#define CIRCUIT_PURPOSE_S_HS_MIN_ 16 /** Hidden-service-side circuit purpose: at the service, waiting for * introductions. */ -#define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 15 +#define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 16 /** Hidden-service-side circuit purpose: at the service, successfully * established intro. */ -#define CIRCUIT_PURPOSE_S_INTRO 16 +#define CIRCUIT_PURPOSE_S_INTRO 17 /** Hidden-service-side circuit purpose: at the service, connecting to rend * point. */ -#define CIRCUIT_PURPOSE_S_CONNECT_REND 17 +#define CIRCUIT_PURPOSE_S_CONNECT_REND 18 /** Hidden-service-side circuit purpose: at the service, rendezvous * established. */ -#define CIRCUIT_PURPOSE_S_REND_JOINED 18 +#define CIRCUIT_PURPOSE_S_REND_JOINED 19 /** This circuit is used for uploading hsdirs */ -#define CIRCUIT_PURPOSE_S_HSDIR_POST 19 -#define CIRCUIT_PURPOSE_S_HS_MAX_ 19 +#define CIRCUIT_PURPOSE_S_HSDIR_POST 20 +#define CIRCUIT_PURPOSE_S_HS_MAX_ 20 /** A testing circuit; not meant to be used for actual traffic. */ -#define CIRCUIT_PURPOSE_TESTING 20 +#define CIRCUIT_PURPOSE_TESTING 21 /** A controller made this circuit and Tor should not use it. */ -#define CIRCUIT_PURPOSE_CONTROLLER 21 +#define CIRCUIT_PURPOSE_CONTROLLER 22 /** This circuit is used for path bias probing only */ -#define CIRCUIT_PURPOSE_PATH_BIAS_TESTING 22 +#define CIRCUIT_PURPOSE_PATH_BIAS_TESTING 23 /** This circuit is used for vanguards/restricted paths. * @@ -124,9 +126,9 @@ * on-demand. When an HS operation needs to take place (e.g. connect to an * intro point), these circuits are then cannibalized and repurposed to the * actual needed HS purpose. */ -#define CIRCUIT_PURPOSE_HS_VANGUARDS 23 +#define CIRCUIT_PURPOSE_HS_VANGUARDS 24 -#define CIRCUIT_PURPOSE_MAX_ 23 +#define CIRCUIT_PURPOSE_MAX_ 24 /** A catch-all for unrecognized purposes. Currently we don't expect * to make or see any circuits with this purpose. */ #define CIRCUIT_PURPOSE_UNKNOWN 255 @@ -216,7 +218,7 @@ void circuit_mark_all_dirty_circs_as_unusable(void); void circuit_synchronize_written_or_bandwidth(const circuit_t *c, circuit_channel_direction_t dir); MOCK_DECL(void, circuit_mark_for_close_, (circuit_t *circ, int reason, - int line, const char *file)); + int line, const char *cfile)); int circuit_get_cpath_len(origin_circuit_t *circ); int circuit_get_cpath_opened_len(const origin_circuit_t *); void circuit_clear_cpath(origin_circuit_t *circ); @@ -228,7 +230,6 @@ int circuit_count_pending_on_channel(channel_t *chan); #define circuit_mark_for_close(c, reason) \ circuit_mark_for_close_((c), (reason), __LINE__, SHORT_FILE__) -void assert_cpath_layer_ok(const crypt_path_t *cp); MOCK_DECL(void, assert_circuit_ok,(const circuit_t *c)); void circuit_free_all(void); void circuits_handle_oom(size_t current_allocation); diff --git a/src/core/or/circuitmux.c b/src/core/or/circuitmux.c index 88f9ac7923..b2628bec3f 100644 --- a/src/core/or/circuitmux.c +++ b/src/core/or/circuitmux.c @@ -294,9 +294,6 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out) circuitmux_make_circuit_inactive(cmux, circ); } - /* Clear n_mux */ - circ->n_mux = NULL; - if (detached_out) smartlist_add(detached_out, circ); } else if (circ->magic == OR_CIRCUIT_MAGIC) { @@ -309,12 +306,6 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out) circuitmux_make_circuit_inactive(cmux, circ); } - /* - * It has a sensible p_chan and direction == CELL_DIRECTION_IN, - * so clear p_mux. - */ - TO_OR_CIRCUIT(circ)->p_mux = NULL; - if (detached_out) smartlist_add(detached_out, circ); } else { @@ -836,18 +827,14 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ, */ log_info(LD_CIRC, "Circuit %u on channel %"PRIu64 " was already attached to " - "cmux %p (trying to attach to %p)", + "(trying to attach to %p)", (unsigned)circ_id, (channel_id), - ((direction == CELL_DIRECTION_OUT) ? - circ->n_mux : TO_OR_CIRCUIT(circ)->p_mux), cmux); /* * The mux pointer on this circuit and the direction in result should * match; otherwise assert. */ - if (direction == CELL_DIRECTION_OUT) tor_assert(circ->n_mux == cmux); - else tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux); tor_assert(hashent->muxinfo.direction == direction); /* @@ -872,13 +859,6 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ, "Attaching circuit %u on channel %"PRIu64 " to cmux %p", (unsigned)circ_id, (channel_id), cmux); - /* - * Assert that the circuit doesn't already have a mux for this - * direction. - */ - if (direction == CELL_DIRECTION_OUT) tor_assert(circ->n_mux == NULL); - else tor_assert(TO_OR_CIRCUIT(circ)->p_mux == NULL); - /* Insert it in the map */ hashent = tor_malloc_zero(sizeof(*hashent)); hashent->chan_id = channel_id; @@ -902,10 +882,6 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ, HT_INSERT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, hashent); - /* Set the circuit's mux for this direction */ - if (direction == CELL_DIRECTION_OUT) circ->n_mux = cmux; - else TO_OR_CIRCUIT(circ)->p_mux = cmux; - /* Update counters */ ++(cmux->n_circuits); if (cell_count > 0) { @@ -993,9 +969,6 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ)) /* Consistency check: the direction must match the direction searched */ tor_assert(last_searched_direction == hashent->muxinfo.direction); - /* Clear the circuit's mux for this direction */ - if (last_searched_direction == CELL_DIRECTION_OUT) circ->n_mux = NULL; - else TO_OR_CIRCUIT(circ)->p_mux = NULL; /* Now remove it from the map */ HT_REMOVE(chanid_circid_muxinfo_map, cmux->chanid_circid_map, hashent); diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c index aa38b0ffc3..a62cdcf9e6 100644 --- a/src/core/or/circuitpadding.c +++ b/src/core/or/circuitpadding.c @@ -23,7 +23,7 @@ * As specified by prop#254, clients can negotiate padding with relays by using * PADDING_NEGOTIATE cells. After successful padding negotiation, padding * machines are assigned to the circuit in their mutable form as a - * circpad_machine_state_t. + * circpad_machine_runtime_t. * * Each state of a padding state machine can be either: * - A histogram that specifies inter-arrival padding delays. @@ -37,6 +37,13 @@ * When a padding machine reaches the END state, it gets wiped from the circuit * so that other padding machines can take over if needed (see * circpad_machine_spec_transitioned_to_end()). + * + **************************** + * General notes: + * + * All used machines should be heap allocated and placed into + * origin_padding_machines/relay_padding_machines so that they get correctly + * cleaned up by the circpad_free_all() function. **/ #define CIRCUITPADDING_PRIVATE @@ -46,8 +53,10 @@ #include "lib/math/prob_distr.h" #include "core/or/or.h" #include "core/or/circuitpadding.h" +#include "core/or/circuitpadding_machines.h" #include "core/or/circuitlist.h" #include "core/or/circuituse.h" +#include "core/mainloop/netstatus.h" #include "core/or/relay.h" #include "feature/stats/rephist.h" #include "feature/nodelist/networkstatus.h" @@ -71,15 +80,18 @@ #include "app/config/config.h" -static inline circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t - circ_purpose); static inline circpad_circuit_state_t circpad_circuit_state( origin_circuit_t *circ); static void circpad_setup_machine_on_circ(circuit_t *on_circ, const circpad_machine_spec_t *machine); static double circpad_distribution_sample(circpad_distribution_t dist); +static inline void circpad_machine_update_state_length_for_nonpadding( + circpad_machine_runtime_t *mi); + /** Cached consensus params */ +static uint8_t circpad_padding_disabled; +static uint8_t circpad_padding_reduced; static uint8_t circpad_global_max_padding_percent; static uint16_t circpad_global_allowed_cells; static uint16_t circpad_max_circ_queued_cells; @@ -119,34 +131,6 @@ STATIC smartlist_t *relay_padding_machines = NULL; continue; #define FOR_EACH_ACTIVE_CIRCUIT_MACHINE_END } STMT_END ; -/** - * Return a human-readable description for a circuit padding state. - */ -static const char * -circpad_state_to_string(circpad_statenum_t state) -{ - const char *descr; - - switch (state) { - case CIRCPAD_STATE_START: - descr = "START"; - break; - case CIRCPAD_STATE_BURST: - descr = "BURST"; - break; - case CIRCPAD_STATE_GAP: - descr = "GAP"; - break; - case CIRCPAD_STATE_END: - descr = "END"; - break; - default: - descr = "CUSTOM"; // XXX: Just return # in static char buf? - } - - return descr; -} - /** * Free the machineinfo at an index */ @@ -154,12 +138,129 @@ static void circpad_circuit_machineinfo_free_idx(circuit_t *circ, int idx) { if (circ->padding_info[idx]) { + log_fn(LOG_INFO,LD_CIRC, "Freeing padding info idx %d on circuit %u (%d)", + idx, CIRCUIT_IS_ORIGIN(circ) ? + TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0, + circ->purpose); + tor_free(circ->padding_info[idx]->histogram); timer_free(circ->padding_info[idx]->padding_timer); tor_free(circ->padding_info[idx]); } } +/** + * Return true if circpad has decided to hold the circuit open for additional + * padding. This function is used to take and retain ownership of certain + * types of circuits that have padding machines on them, that have been passed + * to circuit_mark_for_close(). + * + * circuit_mark_for_close() calls this function to ask circpad if any padding + * machines want to keep the circuit open longer to pad. + * + * Any non-measurement circuit that was closed for a normal, non-error reason + * code may be held open for up to CIRCPAD_DELAY_INFINITE microseconds between + * network-driven cell events. + * + * After CIRCPAD_DELAY_INFINITE microseconds of silence on a circuit, this + * function will no longer hold it open (it will return 0 regardless of + * what the machines ask for, and thus circuit_expire_old_circuits_clientside() + * will close the circuit after roughly 1.25hr of idle time, maximum, + * regardless of the padding machine state. + */ +int +circpad_marked_circuit_for_padding(circuit_t *circ, int reason) +{ + /* If the circuit purpose is measurement or path bias, don't + * hold it open */ + if (circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING || + circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { + return 0; + } + + /* If the circuit is closed for any reason other than these three valid, + * client-side close reasons, do not try to keep it open. It is probably + * damaged or unusable. Note this is OK with vanguards because + * controller-closed circuits have REASON=REQUESTED, so vanguards-closed + * circuits will not be held open (we want them to close ASAP). */ + if (!(reason == END_CIRC_REASON_NONE || + reason == END_CIRC_REASON_FINISHED || + reason == END_CIRC_REASON_IP_NOW_REDUNDANT)) { + return 0; + } + + FOR_EACH_ACTIVE_CIRCUIT_MACHINE_BEGIN(i, circ) { + circpad_machine_runtime_t *mi = circ->padding_info[i]; + if (!mi) { + continue; // No padding runtime info; check next machine + } + + const circpad_state_t *state = circpad_machine_current_state(mi); + + /* If we're in END state (NULL here), then check next machine */ + if (!state) { + continue; // check next machine + } + + /* If the machine does not want to control the circuit close itself, then + * check the next machine */ + if (!circ->padding_machine[i]->manage_circ_lifetime) { + continue; // check next machine + } + + /* If the machine has reached the END state, we can close. Check next + * machine. */ + if (mi->current_state == CIRCPAD_STATE_END) { + continue; // check next machine + } + + log_info(LD_CIRC, "Circuit %d is not marked for close because of a " + "pending padding machine in index %d.", + CIRCUIT_IS_ORIGIN(circ) ? + TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0, i); + + /* If the machine has had no network events at all within the + * last circpad_delay_t timespan, it's in some deadlock state. + * Tell circuit_mark_for_close() that we don't own it anymore. + * This will allow circuit_expire_old_circuits_clientside() to + * close it. + */ + if (circ->padding_info[i]->last_cell_time_sec + + (time_t)CIRCPAD_DELAY_MAX_SECS < approx_time()) { + log_notice(LD_BUG, "Circuit %d was not marked for close because of a " + "pending padding machine in index %d for over an hour. " + "Circuit is a %s", + CIRCUIT_IS_ORIGIN(circ) ? + TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0, + i, circuit_purpose_to_string(circ->purpose)); + + return 0; // abort timer reached; mark the circuit for close now + } + + /* If we weren't marked dirty yet, let's pretend we're dirty now. + * ("Dirty" means that a circuit has been used for application traffic + * by Tor.. Dirty circuits have different expiry times, and are not + * considered in counts of built circuits, etc. By claiming that we're + * dirty, the rest of Tor will make decisions as if we were actually + * used by application data. + * + * This is most important for circuit_expire_old_circuits_clientside(), + * where we want that function to expire us after the padding machine + * has shut down, but using the MaxCircuitDirtiness timer instead of + * the idle circuit timer (again, we want this because we're not + * supposed to look idle to Guard nodes that can see our lifespan). */ + if (!circ->timestamp_dirty) + circ->timestamp_dirty = approx_time(); + + /* Take ownership of the circuit */ + circuit_change_purpose(circ, CIRCUIT_PURPOSE_C_CIRCUIT_PADDING); + + return 1; + } FOR_EACH_ACTIVE_CIRCUIT_MACHINE_END; + + return 0; // No machine wanted to keep the circuit open; mark for close +} + /** * Free all the machineinfos in circ that match machine_num. * @@ -195,13 +296,14 @@ circpad_circuit_free_all_machineinfos(circuit_t *circ) /** * Allocate a new mutable machineinfo structure. */ -STATIC circpad_machine_state_t * +STATIC circpad_machine_runtime_t * circpad_circuit_machineinfo_new(circuit_t *on_circ, int machine_index) { - circpad_machine_state_t *mi = - tor_malloc_zero(sizeof(circpad_machine_state_t)); + circpad_machine_runtime_t *mi = + tor_malloc_zero(sizeof(circpad_machine_runtime_t)); mi->machine_index = machine_index; mi->on_circ = on_circ; + mi->last_cell_time_sec = approx_time(); return mi; } @@ -214,7 +316,7 @@ circpad_circuit_machineinfo_new(circuit_t *on_circ, int machine_index) * invalid state. */ STATIC const circpad_state_t * -circpad_machine_current_state(const circpad_machine_state_t *mi) +circpad_machine_current_state(const circpad_machine_runtime_t *mi) { const circpad_machine_spec_t *machine = CIRCPAD_GET_MACHINE(mi); @@ -232,25 +334,20 @@ circpad_machine_current_state(const circpad_machine_state_t *mi) } /** - * Calculate the lower bound of a histogram bin. The upper bound - * is obtained by calling this function with bin+1, and subtracting 1. + * Get the lower bound of a histogram bin. * - * The 0th bin has a special value -- it only represents start_usec. - * This is so we can specify a probability on 0-delay values. + * You can obtain the upper bound using histogram_get_bin_upper_bound(). * - * After bin 0, bins are exponentially spaced, so that each subsequent - * bin is twice as large as the previous. This is done so that higher - * time resolution is given to lower time values. - * - * The infinity bin is a the last bin in the array (histogram_len-1). - * It has a usec value of CIRCPAD_DELAY_INFINITE (UINT32_MAX). + * This function can also be called with 'bin' set to a value equal or greater + * than histogram_len in which case the infinity bin is chosen and + * CIRCPAD_DELAY_INFINITE is returned. */ STATIC circpad_delay_t -circpad_histogram_bin_to_usec(const circpad_machine_state_t *mi, +circpad_histogram_bin_to_usec(const circpad_machine_runtime_t *mi, circpad_hist_index_t bin) { const circpad_state_t *state = circpad_machine_current_state(mi); - circpad_delay_t start_usec; + circpad_delay_t rtt_add_usec = 0; /* Our state should have been checked to be non-null by the caller * (circpad_machine_remove_token()) */ @@ -258,37 +355,38 @@ circpad_histogram_bin_to_usec(const circpad_machine_state_t *mi, return CIRCPAD_DELAY_INFINITE; } - if (state->use_rtt_estimate) - start_usec = mi->rtt_estimate_usec+state->start_usec; - else - start_usec = state->start_usec; - - if (bin >= CIRCPAD_INFINITY_BIN(state)) + /* The infinity bin has an upper bound of infinity, so make sure we return + * that if they ask for it. */ + if (bin > CIRCPAD_INFINITY_BIN(state)) { return CIRCPAD_DELAY_INFINITE; + } - if (bin == 0) - return start_usec; + /* If we are using an RTT estimate, consider it as well. */ + if (state->use_rtt_estimate) { + rtt_add_usec = mi->rtt_estimate_usec; + } - if (bin == 1) - return start_usec+1; + return state->histogram_edges[bin] + rtt_add_usec; +} - /* The bin widths double every index, so that we can have more resolution - * for lower time values in the histogram. */ - const circpad_time_t bin_width_exponent = - 1 << (CIRCPAD_INFINITY_BIN(state) - bin); - return (circpad_delay_t)MIN(start_usec + - state->range_usec/bin_width_exponent, - CIRCPAD_DELAY_INFINITE); +/** + * Like circpad_histogram_bin_to_usec() but return the upper bound of bin. + * (The upper bound is included in the bin.) + */ +STATIC circpad_delay_t +histogram_get_bin_upper_bound(const circpad_machine_runtime_t *mi, + circpad_hist_index_t bin) +{ + return circpad_histogram_bin_to_usec(mi, bin+1) - 1; } /** Return the midpoint of the histogram bin bin_index. */ static circpad_delay_t -circpad_get_histogram_bin_midpoint(const circpad_machine_state_t *mi, +circpad_get_histogram_bin_midpoint(const circpad_machine_runtime_t *mi, int bin_index) { circpad_delay_t left_bound = circpad_histogram_bin_to_usec(mi, bin_index); - circpad_delay_t right_bound = - circpad_histogram_bin_to_usec(mi, bin_index+1)-1; + circpad_delay_t right_bound = histogram_get_bin_upper_bound(mi, bin_index); return left_bound + (right_bound - left_bound)/2; } @@ -297,19 +395,17 @@ circpad_get_histogram_bin_midpoint(const circpad_machine_state_t *mi, * Return the bin that contains the usec argument. * "Contains" is defined as us in [lower, upper). * - * This function will never return the infinity bin (histogram_len-1), - * in order to simplify the rest of the code. - * - * This means that technically the last bin (histogram_len-2) - * has range [start_usec+range_usec, CIRCPAD_DELAY_INFINITE]. + * This function will never return the infinity bin (histogram_len-1), in order + * to simplify the rest of the code, so if a usec is provided that falls above + * the highest non-infinity bin, that bin index will be returned. */ STATIC circpad_hist_index_t -circpad_histogram_usec_to_bin(const circpad_machine_state_t *mi, +circpad_histogram_usec_to_bin(const circpad_machine_runtime_t *mi, circpad_delay_t usec) { const circpad_state_t *state = circpad_machine_current_state(mi); - circpad_delay_t start_usec; - int32_t bin; /* Larger than return type to properly clamp overflow */ + circpad_delay_t rtt_add_usec = 0; + circpad_hist_index_t bin; /* Our state should have been checked to be non-null by the caller * (circpad_machine_remove_token()) */ @@ -317,34 +413,61 @@ circpad_histogram_usec_to_bin(const circpad_machine_state_t *mi, return 0; } - if (state->use_rtt_estimate) - start_usec = mi->rtt_estimate_usec+state->start_usec; - else - start_usec = state->start_usec; + /* If we are using an RTT estimate, consider it as well. */ + if (state->use_rtt_estimate) { + rtt_add_usec = mi->rtt_estimate_usec; + } - /* The first bin (#0) has zero width and starts (and ends) at start_usec. */ - if (usec <= start_usec) - return 0; + /* Walk through the bins and check the upper bound of each bin, if 'usec' is + * less-or-equal to that, return that bin. If rtt_estimate is enabled then + * add that to the upper bound of each bin. + * + * We don't want to return the infinity bin here, so don't go there. */ + for (bin = 0 ; bin < CIRCPAD_INFINITY_BIN(state) ; bin++) { + if (usec <= histogram_get_bin_upper_bound(mi, bin) + rtt_add_usec) { + return bin; + } + } - if (usec == start_usec+1) - return 1; + /* We don't want to return the infinity bin here, so if we still didn't find + * the right bin, return the highest non-infinity bin */ + return CIRCPAD_INFINITY_BIN(state)-1; +} - const circpad_time_t histogram_range_usec = state->range_usec; - /* We need to find the bin corresponding to our position in the range. - * Since bins are exponentially spaced in powers of two, we need to - * take the log2 of our position in histogram_range_usec. However, - * since tor_log2() returns the floor(log2(u64)), we have to adjust - * it to behave like ceil(log2(u64)). This is verified in our tests - * to properly invert the operation done in - * circpad_histogram_bin_to_usec(). */ - bin = CIRCPAD_INFINITY_BIN(state) - - tor_log2(2*histogram_range_usec/(usec-start_usec+1)); +/** + * Return true if the machine supports token removal. + * + * Token removal is equivalent to having a mutable histogram in the + * circpad_machine_runtime_t mutable info. So while we're at it, + * let's assert that everything is consistent between the mutable + * runtime and the readonly machine spec. + */ +static inline int +circpad_is_token_removal_supported(circpad_machine_runtime_t *mi) +{ + /* No runtime histogram == no token removal */ + if (mi->histogram == NULL) { + /* Machines that don't want token removal are trying to avoid + * potentially expensive mallocs, extra memory accesses, and/or + * potentially expensive monotime calls. Let's minimize checks + * and keep this path fast. */ + tor_assert_nonfatal(mi->histogram_len == 0); + return 0; + } else { + /* Machines that do want token removal are less sensitive to performance. + * Let's spend some time to check that our state is consistent and sane */ + const circpad_state_t *state = circpad_machine_current_state(mi); + if (BUG(!state)) { + return 1; + } + tor_assert_nonfatal(state->token_removal != CIRCPAD_TOKEN_REMOVAL_NONE); + tor_assert_nonfatal(state->histogram_len == mi->histogram_len); + tor_assert_nonfatal(mi->histogram_len != 0); + return 1; + } - /* Clamp the return value to account for timevals before the start - * of bin 0, or after the last bin. Don't return the infinity bin - * index. */ - bin = MIN(MAX(bin, 1), CIRCPAD_INFINITY_BIN(state)-1); - return bin; + tor_assert_nonfatal_unreached(); + return 0; } /** @@ -353,12 +476,15 @@ circpad_histogram_usec_to_bin(const circpad_machine_state_t *mi, * Called after a state transition, or if the bins are empty. */ STATIC void -circpad_machine_setup_tokens(circpad_machine_state_t *mi) +circpad_machine_setup_tokens(circpad_machine_runtime_t *mi) { const circpad_state_t *state = circpad_machine_current_state(mi); /* If this state doesn't exist, or doesn't have token removal, - * free any previous state's histogram, and bail */ + * free any previous state's runtime histogram, and bail. + * + * If we don't have a token removal strategy, we also don't need a runtime + * histogram and we rely on the immutable one in machine_spec_t. */ if (!state || state->token_removal == CIRCPAD_TOKEN_REMOVAL_NONE) { if (mi->histogram) { tor_free(mi->histogram); @@ -385,7 +511,7 @@ circpad_machine_setup_tokens(circpad_machine_state_t *mi) * Choose a length for this state (in cells), if specified. */ static void -circpad_choose_state_length(circpad_machine_state_t *mi) +circpad_choose_state_length(circpad_machine_runtime_t *mi) { const circpad_state_t *state = circpad_machine_current_state(mi); double length; @@ -398,28 +524,40 @@ circpad_choose_state_length(circpad_machine_state_t *mi) length = circpad_distribution_sample(state->length_dist); length = MAX(0, length); length += state->start_length; - length = MIN(length, state->max_length); + + if (state->max_length) { + length = MIN(length, state->max_length); + } mi->state_length = clamp_double_to_int64(length); + + log_info(LD_CIRC, "State length sampled to %"PRIu64" for circuit %u", + mi->state_length, CIRCUIT_IS_ORIGIN(mi->on_circ) ? + TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier : 0); } /** * Sample a value from our iat_dist, and clamp it safely * to circpad_delay_t. + * + * Before returning, add delay_shift (can be zero) to the sampled value. */ static circpad_delay_t circpad_distribution_sample_iat_delay(const circpad_state_t *state, - circpad_delay_t start_usec) + circpad_delay_t delay_shift) { double val = circpad_distribution_sample(state->iat_dist); /* These comparisons are safe, because the output is in the range * [0, 2**32), and double has a precision of 53 bits. */ + /* We want a positive sample value */ val = MAX(0, val); - val = MIN(val, state->range_usec); + /* Respect the maximum sample setting */ + val = MIN(val, state->dist_max_sample_usec); - /* This addition is exact: val is at most 2**32-1, start_usec - * is at most 2**32-1, and doubles have a precision of 53 bits. */ - val += start_usec; + /* Now apply the shift: + * This addition is exact: val is at most 2**32-1, delay_shift is at most + * 2**32-1, and doubles have a precision of 53 bits. */ + val += delay_shift; /* Clamp the distribution at infinite delay val */ return (circpad_delay_t)MIN(tor_llround(val), CIRCPAD_DELAY_INFINITE); @@ -433,13 +571,12 @@ circpad_distribution_sample_iat_delay(const circpad_state_t *state, * that bin's [start,end) time range. */ STATIC circpad_delay_t -circpad_machine_sample_delay(circpad_machine_state_t *mi) +circpad_machine_sample_delay(circpad_machine_runtime_t *mi) { const circpad_state_t *state = circpad_machine_current_state(mi); const circpad_hist_token_t *histogram = NULL; circpad_hist_index_t curr_bin = 0; circpad_delay_t bin_start, bin_end; - circpad_delay_t start_usec; /* These three must all be larger than circpad_hist_token_t, because * we sum several circpad_hist_token_t values across the histogram */ uint64_t curr_weight = 0; @@ -448,21 +585,13 @@ circpad_machine_sample_delay(circpad_machine_state_t *mi) tor_assert(state); - if (state->use_rtt_estimate) - start_usec = mi->rtt_estimate_usec+state->start_usec; - else - start_usec = state->start_usec; - if (state->iat_dist.type != CIRCPAD_DIST_NONE) { /* Sample from a fixed IAT distribution and return */ - return circpad_distribution_sample_iat_delay(state, start_usec); - } else if (state->token_removal != CIRCPAD_TOKEN_REMOVAL_NONE) { - /* We have a mutable histogram. Do basic sanity check and apply: */ - if (BUG(!mi->histogram) || - BUG(mi->histogram_len != state->histogram_len)) { - return CIRCPAD_DELAY_INFINITE; - } - + circpad_delay_t iat_delay_shift = state->use_rtt_estimate ? + mi->rtt_estimate_usec + state->dist_added_shift_usec : + state->dist_added_shift_usec; + return circpad_distribution_sample_iat_delay(state, iat_delay_shift); + } else if (circpad_is_token_removal_supported(mi)) { histogram = mi->histogram; for (circpad_hist_index_t b = 0; b < state->histogram_len; b++) histogram_total_tokens += histogram[b]; @@ -472,7 +601,13 @@ circpad_machine_sample_delay(circpad_machine_state_t *mi) histogram_total_tokens = state->histogram_total_tokens; } - bin_choice = crypto_rand_uint64(histogram_total_tokens); + /* If we are out of tokens, don't schedule padding. */ + if (!histogram_total_tokens) { + return CIRCPAD_DELAY_INFINITE; + } + + bin_choice = crypto_fast_rng_get_uint64(get_thread_fast_rng(), + histogram_total_tokens); /* Skip all the initial zero bins */ while (!histogram[curr_bin]) { @@ -520,16 +655,13 @@ circpad_machine_sample_delay(circpad_machine_state_t *mi) * function below samples from [bin_start, bin_end) */ bin_end = circpad_histogram_bin_to_usec(mi, curr_bin+1); - /* Truncate the high bin in case it's the infinity bin: - * Don't actually schedule an "infinite"-1 delay */ - bin_end = MIN(bin_end, start_usec+state->range_usec); - - // Sample uniformly between histogram[i] to histogram[i+1]-1, - // but no need to sample if they are the same timeval (aka bin 0 or bin 1). - if (bin_end <= bin_start+1) + /* Bin edges are monotonically increasing so this is a bug. Handle it. */ + if (BUG(bin_start >= bin_end)) { return bin_start; - else - return (circpad_delay_t)crypto_rand_uint64_range(bin_start, bin_end); + } + + return (circpad_delay_t)crypto_fast_rng_uint64_range(get_thread_fast_rng(), + bin_start, bin_end); } /** @@ -626,7 +758,7 @@ circpad_distribution_sample(circpad_distribution_t dist) * greater than the target, and that has tokens remaining. */ static circpad_hist_index_t -circpad_machine_first_higher_index(const circpad_machine_state_t *mi, +circpad_machine_first_higher_index(const circpad_machine_runtime_t *mi, circpad_delay_t target_bin_usec) { circpad_hist_index_t bin = circpad_histogram_usec_to_bin(mi, @@ -635,7 +767,7 @@ circpad_machine_first_higher_index(const circpad_machine_state_t *mi, /* Don't remove from the infinity bin */ for (; bin < CIRCPAD_INFINITY_BIN(mi); bin++) { if (mi->histogram[bin] && - circpad_histogram_bin_to_usec(mi, bin+1) > target_bin_usec) { + histogram_get_bin_upper_bound(mi, bin) >= target_bin_usec) { return bin; } } @@ -648,7 +780,7 @@ circpad_machine_first_higher_index(const circpad_machine_state_t *mi, * target_bin_usec, and that still has tokens remaining. */ static circpad_hist_index_t -circpad_machine_first_lower_index(const circpad_machine_state_t *mi, +circpad_machine_first_lower_index(const circpad_machine_runtime_t *mi, circpad_delay_t target_bin_usec) { circpad_hist_index_t bin = circpad_histogram_usec_to_bin(mi, @@ -669,7 +801,7 @@ circpad_machine_first_lower_index(const circpad_machine_state_t *mi, * greater than the target. */ STATIC void -circpad_machine_remove_higher_token(circpad_machine_state_t *mi, +circpad_machine_remove_higher_token(circpad_machine_runtime_t *mi, circpad_delay_t target_bin_usec) { /* We need to remove the token from the first bin @@ -690,7 +822,7 @@ circpad_machine_remove_higher_token(circpad_machine_state_t *mi, * lower than the target. */ STATIC void -circpad_machine_remove_lower_token(circpad_machine_state_t *mi, +circpad_machine_remove_lower_token(circpad_machine_runtime_t *mi, circpad_delay_t target_bin_usec) { circpad_hist_index_t bin = circpad_machine_first_lower_index(mi, @@ -719,7 +851,7 @@ circpad_machine_remove_lower_token(circpad_machine_state_t *mi, * If it is false, use bin index distance only. */ STATIC void -circpad_machine_remove_closest_token(circpad_machine_state_t *mi, +circpad_machine_remove_closest_token(circpad_machine_runtime_t *mi, circpad_delay_t target_bin_usec, bool use_usec) { @@ -776,7 +908,7 @@ circpad_machine_remove_closest_token(circpad_machine_state_t *mi, bin_to_remove = lower; } mi->histogram[bin_to_remove]--; - log_debug(LD_GENERAL, "Removing token from bin %d", bin_to_remove); + log_debug(LD_CIRC, "Removing token from bin %d", bin_to_remove); return; } else { if (current - lower > higher - current) { @@ -801,7 +933,7 @@ circpad_machine_remove_closest_token(circpad_machine_state_t *mi, * If it is empty, do nothing. */ static void -circpad_machine_remove_exact(circpad_machine_state_t *mi, +circpad_machine_remove_exact(circpad_machine_runtime_t *mi, circpad_delay_t target_bin_usec) { circpad_hist_index_t bin = circpad_histogram_usec_to_bin(mi, @@ -818,7 +950,7 @@ circpad_machine_remove_exact(circpad_machine_state_t *mi, * otherwise returns 0. */ static circpad_decision_t -check_machine_token_supply(circpad_machine_state_t *mi) +check_machine_token_supply(circpad_machine_runtime_t *mi) { uint32_t histogram_total_tokens = 0; @@ -829,7 +961,7 @@ check_machine_token_supply(circpad_machine_state_t *mi) * * We also do not count infinity bin in histogram totals. */ - if (mi->histogram_len && mi->histogram) { + if (circpad_is_token_removal_supported(mi)) { for (circpad_hist_index_t b = 0; b < CIRCPAD_INFINITY_BIN(mi); b++) histogram_total_tokens += mi->histogram[b]; @@ -848,22 +980,55 @@ check_machine_token_supply(circpad_machine_state_t *mi) } /** - * Remove a token from the bin corresponding to the delta since - * last packet. If that bin is empty, choose a token based on - * the specified removal strategy in the state machine. + * Count that a padding packet was sent. * - * This function also updates and checks rate limit and state - * limit counters. - * - * Returns 1 if we transition states, 0 otherwise. + * This updates our state length count, our machine rate limit counts, + * and if token removal is used, decrements the histogram. */ -STATIC circpad_decision_t -circpad_machine_remove_token(circpad_machine_state_t *mi) +static inline void +circpad_machine_count_padding_sent(circpad_machine_runtime_t *mi) { - const circpad_state_t *state = NULL; - circpad_time_t current_time; - circpad_delay_t target_bin_usec; + /* If we have a valid state length bound, consider it */ + if (mi->state_length != CIRCPAD_STATE_LENGTH_INFINITE && + !BUG(mi->state_length <= 0)) { + mi->state_length--; + } + + /* + * Update non-padding counts for rate limiting: We scale at UINT16_MAX + * because we only use this for a percentile limit of 2 sig figs, and + * space is scare in the machineinfo struct. + */ + mi->padding_sent++; + if (mi->padding_sent == UINT16_MAX) { + mi->padding_sent /= 2; + mi->nonpadding_sent /= 2; + } + + circpad_global_padding_sent++; + + /* If we have a mutable histogram, reduce the token count from + * the chosen padding bin (this assumes we always send padding + * when we intended to). */ + if (circpad_is_token_removal_supported(mi)) { + /* Check array bounds and token count before removing */ + if (!BUG(mi->chosen_bin >= mi->histogram_len) && + !BUG(mi->histogram[mi->chosen_bin] == 0)) { + mi->histogram[mi->chosen_bin]--; + } + } +} +/** + * Count a nonpadding packet as being sent. + * + * This function updates our overhead accounting variables, as well + * as decrements the state limit packet counter, if the latter was + * flagged as applying to non-padding as well. + */ +static inline void +circpad_machine_count_nonpadding_sent(circpad_machine_runtime_t *mi) +{ /* Update non-padding counts for rate limiting: We scale at UINT16_MAX * because we only use this for a percentile limit of 2 sig figs, and * space is scare in the machineinfo struct. */ @@ -873,12 +1038,70 @@ circpad_machine_remove_token(circpad_machine_state_t *mi) mi->nonpadding_sent /= 2; } + /* Update any state packet length limits that apply */ + circpad_machine_update_state_length_for_nonpadding(mi); + + /* Remove a token from the histogram, if applicable */ + circpad_machine_remove_token(mi); +} + +/** + * Decrement the state length counter for a non-padding packet. + * + * Only updates the state length if we're using that feature, we + * have a state, and the machine wants to count non-padding packets + * towards the state length. + */ +static inline void +circpad_machine_update_state_length_for_nonpadding( + circpad_machine_runtime_t *mi) +{ + const circpad_state_t *state = NULL; + + if (mi->state_length == CIRCPAD_STATE_LENGTH_INFINITE) + return; + + state = circpad_machine_current_state(mi); + + /* If we are not in a padding state (like start or end), we're done */ + if (!state) + return; + + /* If we're enforcing a state length on non-padding packets, + * decrement it */ + if (state->length_includes_nonpadding && + mi->state_length > 0) { + mi->state_length--; + } +} + +/** + * When a non-padding packet arrives, remove a token from the bin + * corresponding to the delta since last sent packet. If that bin + * is empty, choose a token based on the specified removal strategy + * in the state machine. + */ +STATIC void +circpad_machine_remove_token(circpad_machine_runtime_t *mi) +{ + const circpad_state_t *state = NULL; + circpad_time_t current_time; + circpad_delay_t target_bin_usec; + /* Dont remove any tokens if there was no padding scheduled */ if (!mi->padding_scheduled_at_usec) { - return CIRCPAD_STATE_UNCHANGED; + return; } state = circpad_machine_current_state(mi); + + /* If we are not in a padding state (like start or end), we're done */ + if (!state) + return; + /* Don't remove any tokens if we're not doing token removal */ + if (state->token_removal == CIRCPAD_TOKEN_REMOVAL_NONE) + return; + current_time = monotime_absolute_usec(); /* If we have scheduled padding some time in the future, we want to see what @@ -895,22 +1118,8 @@ circpad_machine_remove_token(circpad_machine_state_t *mi) timer_disable(mi->padding_timer); } - /* If we are not in a padding state (like start or end), we're done */ - if (!state) - return CIRCPAD_STATE_UNCHANGED; - - /* If we're enforcing a state length on non-padding packets, - * decrement it */ - if (mi->state_length != CIRCPAD_STATE_LENGTH_INFINITE && - state->length_includes_nonpadding && - mi->state_length > 0) { - mi->state_length--; - } - /* Perform the specified token removal strategy */ switch (state->token_removal) { - case CIRCPAD_TOKEN_REMOVAL_NONE: - break; case CIRCPAD_TOKEN_REMOVAL_CLOSEST_USEC: circpad_machine_remove_closest_token(mi, target_bin_usec, 1); break; @@ -926,10 +1135,13 @@ circpad_machine_remove_token(circpad_machine_state_t *mi) case CIRCPAD_TOKEN_REMOVAL_EXACT: circpad_machine_remove_exact(mi, target_bin_usec); break; + case CIRCPAD_TOKEN_REMOVAL_NONE: + default: + tor_assert_nonfatal_unreached(); + log_warn(LD_BUG, "Circpad: Unknown token removal strategy %d", + state->token_removal); + break; } - - /* Check our token and state length limits */ - return check_machine_token_supply(mi); } /** @@ -985,63 +1197,41 @@ circpad_send_command_to_hop,(origin_circuit_t *circ, uint8_t hopnum, * CIRCPAD_STATE_CHANGED. Otherwise return CIRCPAD_STATE_UNCHANGED. */ circpad_decision_t -circpad_send_padding_cell_for_callback(circpad_machine_state_t *mi) +circpad_send_padding_cell_for_callback(circpad_machine_runtime_t *mi) { circuit_t *circ = mi->on_circ; int machine_idx = mi->machine_index; mi->padding_scheduled_at_usec = 0; circpad_statenum_t state = mi->current_state; - // Make sure circuit didn't close on us + /* Make sure circuit didn't close on us */ if (mi->on_circ->marked_for_close) { log_fn(LOG_INFO,LD_CIRC, - "Padding callback on a circuit marked for close. Ignoring."); + "Padding callback on circuit marked for close (%u). Ignoring.", + CIRCUIT_IS_ORIGIN(mi->on_circ) ? + TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier : 0); return CIRCPAD_STATE_CHANGED; } - /* If it's a histogram, reduce the token count */ - if (mi->histogram && mi->histogram_len) { - /* Basic sanity check on the histogram before removing anything */ - if (BUG(mi->chosen_bin >= mi->histogram_len) || - BUG(mi->histogram[mi->chosen_bin] == 0)) { - return CIRCPAD_STATE_CHANGED; - } - - mi->histogram[mi->chosen_bin]--; - } - - /* If we have a valid state length bound, consider it */ - if (mi->state_length != CIRCPAD_STATE_LENGTH_INFINITE && - !BUG(mi->state_length <= 0)) { - mi->state_length--; - } - - /* - * Update non-padding counts for rate limiting: We scale at UINT16_MAX - * because we only use this for a percentile limit of 2 sig figs, and - * space is scare in the machineinfo struct. - */ - mi->padding_sent++; - if (mi->padding_sent == UINT16_MAX) { - mi->padding_sent /= 2; - mi->nonpadding_sent /= 2; - } - circpad_global_padding_sent++; + circpad_machine_count_padding_sent(mi); if (CIRCUIT_IS_ORIGIN(mi->on_circ)) { circpad_send_command_to_hop(TO_ORIGIN_CIRCUIT(mi->on_circ), CIRCPAD_GET_MACHINE(mi)->target_hopnum, RELAY_COMMAND_DROP, NULL, 0); - log_fn(LOG_INFO,LD_CIRC, "Callback: Sending padding to origin circuit %u.", - TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier); + log_info(LD_CIRC, "Callback: Sending padding to origin circuit %u" + " (%d) [length: %"PRIu64"]", + TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier, + mi->on_circ->purpose, mi->state_length); } else { // If we're a non-origin circ, we can just send from here as if we're the // edge. if (TO_OR_CIRCUIT(circ)->p_chan_cells.n <= circpad_max_circ_queued_cells) { - log_fn(LOG_INFO,LD_CIRC, - "Callback: Sending padding to non-origin circuit."); + log_info(LD_CIRC, "Callback: Sending padding to circuit (%d)" + " [length: %"PRIu64"]", mi->on_circ->purpose, mi->state_length); relay_send_command_from_edge(0, mi->on_circ, RELAY_COMMAND_DROP, NULL, 0, NULL); + rep_hist_padding_count_write(PADDING_TYPE_DROP); } else { static ratelim_t cell_lim = RATELIM_INIT(600); log_fn_ratelim(&cell_lim,LOG_NOTICE,LD_CIRC, @@ -1050,7 +1240,6 @@ circpad_send_padding_cell_for_callback(circpad_machine_state_t *mi) } } - rep_hist_padding_count_write(PADDING_TYPE_DROP); /* This is a padding cell sent from the client or from the middle node, * (because it's invoked from circuitpadding.c) */ circpad_cell_event_padding_sent(circ); @@ -1071,7 +1260,7 @@ circpad_send_padding_cell_for_callback(circpad_machine_state_t *mi) /** * Tor-timer compatible callback that tells us to send a padding cell. * - * Timers are associated with circpad_machine_state_t's. When the machineinfo + * Timers are associated with circpad_machine_runtime_t's. When the machineinfo * is freed on a circuit, the timers are cancelled. Since the lifetime * of machineinfo is always longer than the timers, handles are not * needed. @@ -1080,7 +1269,7 @@ static void circpad_send_padding_callback(tor_timer_t *timer, void *args, const struct monotime_t *time) { - circpad_machine_state_t *mi = ((circpad_machine_state_t*)args); + circpad_machine_runtime_t *mi = ((circpad_machine_runtime_t*)args); (void)timer; (void)time; if (mi && mi->on_circ) { @@ -1103,6 +1292,14 @@ circpad_send_padding_callback(tor_timer_t *timer, void *args, void circpad_new_consensus_params(const networkstatus_t *ns) { + circpad_padding_disabled = + networkstatus_get_param(ns, "circpad_padding_disabled", + 0, 0, 1); + + circpad_padding_reduced = + networkstatus_get_param(ns, "circpad_padding_reduced", + 0, 0, 1); + circpad_global_allowed_cells = networkstatus_get_param(ns, "circpad_global_allowed_cells", 0, 0, UINT16_MAX-1); @@ -1116,6 +1313,24 @@ circpad_new_consensus_params(const networkstatus_t *ns) CIRCWINDOW_START_MAX, 0, 50*CIRCWINDOW_START_MAX); } +/** + * Return true if padding is allowed by torrc and consensus. + */ +static bool +circpad_is_padding_allowed(void) +{ + /* If padding has been disabled in the consensus, don't send any more + * padding. Technically the machine should be shut down when the next + * machine condition check happens, but machine checks only happen on + * certain circuit events, and if padding is disabled due to some + * network overload or DoS condition, we really want to stop ASAP. */ + if (circpad_padding_disabled || !get_options()->CircuitPadding) { + return 0; + } + + return 1; +} + /** * Check this machine against its padding limits, as well as global * consensus limits. @@ -1130,14 +1345,14 @@ circpad_new_consensus_params(const networkstatus_t *ns) * Returns 1 if limits are set and we've hit them. Otherwise returns 0. */ STATIC bool -circpad_machine_reached_padding_limit(circpad_machine_state_t *mi) +circpad_machine_reached_padding_limit(circpad_machine_runtime_t *mi) { const circpad_machine_spec_t *machine = CIRCPAD_GET_MACHINE(mi); /* If machine_padding_pct is non-zero, and we've sent more * than the allowed count of padding cells, then check our * percent limits for this machine. */ - if (machine->max_padding_percent && + if (machine->max_padding_percent && mi->padding_sent >= machine->allowed_padding_count) { uint32_t total_cells = mi->padding_sent + mi->nonpadding_sent; @@ -1178,16 +1393,36 @@ circpad_machine_reached_padding_limit(circpad_machine_state_t *mi) * 0 otherwise. */ MOCK_IMPL(circpad_decision_t, -circpad_machine_schedule_padding,(circpad_machine_state_t *mi)) +circpad_machine_schedule_padding,(circpad_machine_runtime_t *mi)) { circpad_delay_t in_usec = 0; struct timeval timeout; tor_assert(mi); + /* Don't schedule padding if it is disabled */ + if (!circpad_is_padding_allowed()) { + static ratelim_t padding_lim = RATELIM_INIT(600); + log_fn_ratelim(&padding_lim,LOG_INFO,LD_CIRC, + "Padding has been disabled, but machine still on circuit %"PRIu64 + ", %d", + mi->on_circ->n_chan ? mi->on_circ->n_chan->global_identifier : 0, + mi->on_circ->n_circ_id); + + return CIRCPAD_STATE_UNCHANGED; + } + + /* Don't schedule padding if we are currently in dormant mode. */ + if (!is_participating_on_network()) { + log_info(LD_CIRC, "Not scheduling padding because we are dormant."); + return CIRCPAD_STATE_UNCHANGED; + } + // Don't pad in end (but also don't cancel any previously // scheduled padding either). if (mi->current_state == CIRCPAD_STATE_END) { - log_fn(LOG_INFO, LD_CIRC, "Padding end state"); + log_fn(LOG_INFO, LD_CIRC, "Padding end state on circuit %u", + CIRCUIT_IS_ORIGIN(mi->on_circ) ? + TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier : 0); return CIRCPAD_STATE_UNCHANGED; } @@ -1198,7 +1433,8 @@ circpad_machine_schedule_padding,(circpad_machine_state_t *mi)) "Padding machine has reached padding limit on circuit %u", TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier); } else { - log_fn(LOG_INFO, LD_CIRC, + static ratelim_t padding_lim = RATELIM_INIT(600); + log_fn_ratelim(&padding_lim,LOG_INFO,LD_CIRC, "Padding machine has reached padding limit on circuit %"PRIu64 ", %d", mi->on_circ->n_chan ? mi->on_circ->n_chan->global_identifier : 0, @@ -1215,8 +1451,20 @@ circpad_machine_schedule_padding,(circpad_machine_state_t *mi)) /* in_usec = in microseconds */ in_usec = circpad_machine_sample_delay(mi); - mi->padding_scheduled_at_usec = monotime_absolute_usec(); - log_fn(LOG_INFO,LD_CIRC,"\tPadding in %u usec", in_usec); + /* If we're using token removal, we need to know when the padding + * was scheduled at, so we can remove the appropriate token if + * a non-padding cell is sent before the padding timer expires. + * + * However, since monotime is unpredictably expensive, let's avoid + * using it for machines that don't need token removal. */ + if (circpad_is_token_removal_supported(mi)) { + mi->padding_scheduled_at_usec = monotime_absolute_usec(); + } else { + mi->padding_scheduled_at_usec = 1; + } + log_fn(LOG_INFO,LD_CIRC,"\tPadding in %u usec on circuit %u", in_usec, + CIRCUIT_IS_ORIGIN(mi->on_circ) ? + TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier : 0); // Don't schedule if we have infinite delay. if (in_usec == CIRCPAD_DELAY_INFINITE) { @@ -1240,7 +1488,9 @@ circpad_machine_schedule_padding,(circpad_machine_state_t *mi)) timeout.tv_sec = in_usec/TOR_USEC_PER_SEC; timeout.tv_usec = (in_usec%TOR_USEC_PER_SEC); - log_fn(LOG_INFO, LD_CIRC, "\tPadding in %u sec, %u usec", + log_fn(LOG_INFO, LD_CIRC, "\tPadding circuit %u in %u sec, %u usec", + CIRCUIT_IS_ORIGIN(mi->on_circ) ? + TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier : 0, (unsigned)timeout.tv_sec, (unsigned)timeout.tv_usec); if (mi->padding_timer) { @@ -1268,9 +1518,15 @@ circpad_machine_schedule_padding,(circpad_machine_state_t *mi)) * not access it. */ static void -circpad_machine_spec_transitioned_to_end(circpad_machine_state_t *mi) +circpad_machine_spec_transitioned_to_end(circpad_machine_runtime_t *mi) { const circpad_machine_spec_t *machine = CIRCPAD_GET_MACHINE(mi); + circuit_t *on_circ = mi->on_circ; + + log_fn(LOG_INFO,LD_CIRC, "Padding machine in end state on circuit %u (%d)", + CIRCUIT_IS_ORIGIN(on_circ) ? + TO_ORIGIN_CIRCUIT(on_circ)->global_identifier : 0, + on_circ->purpose); /* * We allow machines to shut down and delete themselves as opposed @@ -1286,7 +1542,6 @@ circpad_machine_spec_transitioned_to_end(circpad_machine_state_t *mi) * here does. */ if (machine->should_negotiate_end) { - circuit_t *on_circ = mi->on_circ; if (machine->is_origin_side) { /* We free the machine info here so that we can be replaced * by a different machine. But we must leave the padding_machine @@ -1318,7 +1573,7 @@ circpad_machine_spec_transitioned_to_end(circpad_machine_state_t *mi) * Returns 1 if we transition states, 0 otherwise. */ MOCK_IMPL(circpad_decision_t, -circpad_machine_spec_transition,(circpad_machine_state_t *mi, +circpad_machine_spec_transition,(circpad_machine_runtime_t *mi, circpad_event_t event)) { const circpad_state_t *state = @@ -1352,9 +1607,10 @@ circpad_machine_spec_transition,(circpad_machine_state_t *mi, * a transition to itself. All non-specified events are ignored. */ log_fn(LOG_INFO, LD_CIRC, - "Circpad machine %d transitioning from %s to %s", - mi->machine_index, circpad_state_to_string(mi->current_state), - circpad_state_to_string(s)); + "Circuit %u circpad machine %d transitioning from %u to %u", + CIRCUIT_IS_ORIGIN(mi->on_circ) ? + TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier : 0, + mi->machine_index, mi->current_state, s); /* If this is not the same state, switch and init tokens, * otherwise just reschedule padding. */ @@ -1399,7 +1655,7 @@ circpad_machine_spec_transition,(circpad_machine_state_t *mi, */ static void circpad_estimate_circ_rtt_on_received(circuit_t *circ, - circpad_machine_state_t *mi) + circpad_machine_runtime_t *mi) { /* Origin circuits don't estimate RTT. They could do it easily enough, * but they have no reason to use it in any delay calculations. */ @@ -1428,10 +1684,29 @@ circpad_estimate_circ_rtt_on_received(circuit_t *circ, ", %d) after two back to back packets. Current RTT: %d", circ->n_chan ? circ->n_chan->global_identifier : 0, circ->n_circ_id, mi->rtt_estimate_usec); - mi->stop_rtt_update = 1; + mi->stop_rtt_update = 1; + + if (!mi->rtt_estimate_usec) { + static ratelim_t rtt_lim = RATELIM_INIT(600); + log_fn_ratelim(&rtt_lim,LOG_NOTICE,LD_BUG, + "Circuit got two cells back to back before estimating RTT."); + } } } else { - mi->last_received_time_usec = monotime_absolute_usec(); + const circpad_state_t *state = circpad_machine_current_state(mi); + if (BUG(!state)) { + return; + } + + /* Since monotime is unpredictably expensive, only update this field + * if rtt estimates are needed. Otherwise, stop the rtt update. */ + if (state->use_rtt_estimate) { + mi->last_received_time_usec = monotime_absolute_usec(); + } else { + /* Let's fast-path future decisions not to update rtt if the + * feature is not in use. */ + mi->stop_rtt_update = 1; + } } } @@ -1446,7 +1721,7 @@ circpad_estimate_circ_rtt_on_received(circuit_t *circ, */ static void circpad_estimate_circ_rtt_on_send(circuit_t *circ, - circpad_machine_state_t *mi) + circpad_machine_runtime_t *mi) { /* Origin circuits don't estimate RTT. They could do it easily enough, * but they have no reason to use it in any delay calculations. */ @@ -1488,12 +1763,12 @@ circpad_estimate_circ_rtt_on_send(circuit_t *circ, * to back. Stop estimating RTT in this case. Note that we only * stop RTT update if the circuit is opened, to allow for RTT estimates * of var cells during circ setup. */ - mi->stop_rtt_update = 1; - - if (!mi->rtt_estimate_usec) { - log_fn(LOG_NOTICE, LD_CIRC, - "Got two cells back to back on a circuit before estimating RTT."); + if (!mi->rtt_estimate_usec && !mi->stop_rtt_update) { + static ratelim_t rtt_lim = RATELIM_INIT(600); + log_fn_ratelim(&rtt_lim,LOG_NOTICE,LD_BUG, + "Circuit sent two cells back to back before estimating RTT."); } + mi->stop_rtt_update = 1; } } @@ -1513,12 +1788,17 @@ circpad_cell_event_nonpadding_sent(circuit_t *on_circ) /* If there are no machines then this loop should not iterate */ FOR_EACH_ACTIVE_CIRCUIT_MACHINE_BEGIN(i, on_circ) { - /* First, update any RTT estimate */ + /* First, update any timestamps */ + on_circ->padding_info[i]->last_cell_time_sec = approx_time(); circpad_estimate_circ_rtt_on_send(on_circ, on_circ->padding_info[i]); - /* Remove a token: this is the idea of adaptive padding, since we have an - * ideal distribution that we want our distribution to look like. */ - if (!circpad_machine_remove_token(on_circ->padding_info[i])) { + /* Then, do accounting */ + circpad_machine_count_nonpadding_sent(on_circ->padding_info[i]); + + /* Check to see if we've run out of tokens for this state already, + * and if not, check for other state transitions */ + if (check_machine_token_supply(on_circ->padding_info[i]) + == CIRCPAD_STATE_UNCHANGED) { /* If removing a token did not cause a transition, check if * non-padding sent event should */ circpad_machine_spec_transition(on_circ->padding_info[i], @@ -1539,7 +1819,8 @@ void circpad_cell_event_nonpadding_received(circuit_t *on_circ) { FOR_EACH_ACTIVE_CIRCUIT_MACHINE_BEGIN(i, on_circ) { - /* First, update any RTT estimate */ + /* First, update any timestamps */ + on_circ->padding_info[i]->last_cell_time_sec = approx_time(); circpad_estimate_circ_rtt_on_received(on_circ, on_circ->padding_info[i]); circpad_machine_spec_transition(on_circ->padding_info[i], @@ -1559,8 +1840,17 @@ void circpad_cell_event_padding_sent(circuit_t *on_circ) { FOR_EACH_ACTIVE_CIRCUIT_MACHINE_BEGIN(i, on_circ) { - circpad_machine_spec_transition(on_circ->padding_info[i], + /* Check to see if we've run out of tokens for this state already, + * and if not, check for other state transitions */ + if (check_machine_token_supply(on_circ->padding_info[i]) + == CIRCPAD_STATE_UNCHANGED) { + /* If removing a token did not cause a transition, check if + * non-padding sent event should */ + + on_circ->padding_info[i]->last_cell_time_sec = approx_time(); + circpad_machine_spec_transition(on_circ->padding_info[i], CIRCPAD_EVENT_PADDING_SENT); + } } FOR_EACH_ACTIVE_CIRCUIT_MACHINE_END; } @@ -1577,6 +1867,7 @@ circpad_cell_event_padding_received(circuit_t *on_circ) { /* identical to padding sent */ FOR_EACH_ACTIVE_CIRCUIT_MACHINE_BEGIN(i, on_circ) { + on_circ->padding_info[i]->last_cell_time_sec = approx_time(); circpad_machine_spec_transition(on_circ->padding_info[i], CIRCPAD_EVENT_PADDING_RECV); } FOR_EACH_ACTIVE_CIRCUIT_MACHINE_END; @@ -1592,7 +1883,7 @@ circpad_cell_event_padding_received(circuit_t *on_circ) * Return 1 if we decide to transition, 0 otherwise. */ circpad_decision_t -circpad_internal_event_infinity(circpad_machine_state_t *mi) +circpad_internal_event_infinity(circpad_machine_runtime_t *mi) { return circpad_machine_spec_transition(mi, CIRCPAD_EVENT_INFINITY); } @@ -1606,7 +1897,7 @@ circpad_internal_event_infinity(circpad_machine_state_t *mi) * Return 1 if we decide to transition, 0 otherwise. */ circpad_decision_t -circpad_internal_event_bins_empty(circpad_machine_state_t *mi) +circpad_internal_event_bins_empty(circpad_machine_runtime_t *mi) { if (circpad_machine_spec_transition(mi, CIRCPAD_EVENT_BINS_EMPTY) == CIRCPAD_STATE_CHANGED) { @@ -1625,7 +1916,7 @@ circpad_internal_event_bins_empty(circpad_machine_state_t *mi) * Return 1 if we decide to transition, 0 otherwise. */ circpad_decision_t -circpad_internal_event_state_length_up(circpad_machine_state_t *mi) +circpad_internal_event_state_length_up(circpad_machine_runtime_t *mi) { return circpad_machine_spec_transition(mi, CIRCPAD_EVENT_LENGTH_COUNT); } @@ -1637,6 +1928,19 @@ static inline bool circpad_machine_conditions_met(origin_circuit_t *circ, const circpad_machine_spec_t *machine) { + /* If padding is disabled, no machines should match/apply. This has + * the effect of shutting down all machines, and not adding any more. */ + if (circpad_padding_disabled || !get_options()->CircuitPadding) + return 0; + + /* If the consensus or our torrc has selected reduced connection padding, + * then only allow this machine if it is flagged as acceptable under + * reduced padding conditions */ + if (circpad_padding_reduced || get_options()->ReducedCircuitPadding) { + if (!machine->conditions.reduced_padding_ok) + return 0; + } + if (!(circpad_circ_purpose_to_mask(TO_CIRCUIT(circ)->purpose) & machine->conditions.purpose_mask)) return 0; @@ -1700,7 +2004,6 @@ circpad_circuit_state(origin_circuit_t *circ) * Convert a normal circuit purpose into a bitmask that we can * use for determining matching circuits. */ -static inline circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t circ_purpose) { @@ -1743,7 +2046,8 @@ circpad_shutdown_old_machines(origin_circuit_t *on_circ) } /** - * Negotiate new machines that would apply to this circuit. + * Negotiate new machines that would apply to this circuit, given the machines + * inside machines_sl. * * This function checks to see if we have any free machine indexes, * and for each free machine index, it initializes the most recently @@ -1751,14 +2055,15 @@ circpad_shutdown_old_machines(origin_circuit_t *on_circ) * index and circuit conditions, and negotiates it with the appropriate * middle relay. */ -static void -circpad_add_matching_machines(origin_circuit_t *on_circ) +STATIC void +circpad_add_matching_machines(origin_circuit_t *on_circ, + smartlist_t *machines_sl) { circuit_t *circ = TO_CIRCUIT(on_circ); #ifdef TOR_UNIT_TESTS /* Tests don't have to init our padding machines */ - if (!origin_padding_machines) + if (!machines_sl) return; #endif @@ -1775,7 +2080,7 @@ circpad_add_matching_machines(origin_circuit_t *on_circ) /* We have a free machine index. Check the origin padding * machines in reverse order, so that more recently added * machines take priority over older ones. */ - SMARTLIST_FOREACH_REVERSE_BEGIN(origin_padding_machines, + SMARTLIST_FOREACH_REVERSE_BEGIN(machines_sl, circpad_machine_spec_t *, machine) { /* Machine definitions have a specific target machine index. @@ -1803,6 +2108,10 @@ circpad_add_matching_machines(origin_circuit_t *on_circ) if (circpad_negotiate_padding(on_circ, machine->machine_num, machine->target_hopnum, CIRCPAD_COMMAND_START) < 0) { + log_info(LD_CIRC, + "Padding not negotiated. Cleaning machine from circuit %u", + CIRCUIT_IS_ORIGIN(circ) ? + TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0); circpad_circuit_machineinfo_free_idx(circ, i); circ->padding_machine[i] = NULL; on_circ->padding_negotiation_failed = 1; @@ -1826,7 +2135,7 @@ circpad_machine_event_circ_added_hop(origin_circuit_t *on_circ) { /* Since our padding conditions do not specify a max_hops, * all we can do is add machines here */ - circpad_add_matching_machines(on_circ); + circpad_add_matching_machines(on_circ, origin_padding_machines); } /** @@ -1839,7 +2148,7 @@ void circpad_machine_event_circ_built(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); - circpad_add_matching_machines(circ); + circpad_add_matching_machines(circ, origin_padding_machines); } /** @@ -1852,7 +2161,7 @@ void circpad_machine_event_circ_purpose_changed(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); - circpad_add_matching_machines(circ); + circpad_add_matching_machines(circ, origin_padding_machines); } /** @@ -1866,7 +2175,7 @@ void circpad_machine_event_circ_has_no_relay_early(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); - circpad_add_matching_machines(circ); + circpad_add_matching_machines(circ, origin_padding_machines); } /** @@ -1881,7 +2190,7 @@ void circpad_machine_event_circ_has_streams(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); - circpad_add_matching_machines(circ); + circpad_add_matching_machines(circ, origin_padding_machines); } /** @@ -1896,7 +2205,7 @@ void circpad_machine_event_circ_has_no_streams(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); - circpad_add_matching_machines(circ); + circpad_add_matching_machines(circ, origin_padding_machines); } /** @@ -1977,13 +2286,6 @@ circpad_deliver_recognized_relay_cell_events(circuit_t *circ, uint8_t relay_command, crypt_path_t *layer_hint) { - /* Padding negotiate cells are ignored by the state machines - * for simplicity. */ - if (relay_command == RELAY_COMMAND_PADDING_NEGOTIATE || - relay_command == RELAY_COMMAND_PADDING_NEGOTIATED) { - return; - } - if (relay_command == RELAY_COMMAND_DROP) { rep_hist_padding_count_read(PADDING_TYPE_DROP); @@ -2020,16 +2322,12 @@ void circpad_deliver_sent_relay_cell_events(circuit_t *circ, uint8_t relay_command) { - /* Padding negotiate cells are ignored by the state machines - * for simplicity. */ - if (relay_command == RELAY_COMMAND_PADDING_NEGOTIATE || - relay_command == RELAY_COMMAND_PADDING_NEGOTIATED) { - return; - } - /* RELAY_COMMAND_DROP is the multi-hop (aka circuit-level) padding cell in * tor. (CELL_PADDING is a channel-level padding cell, which is not relayed - * or processed here) */ + * or processed here). + * + * We do generate events for PADDING_NEGOTIATE and PADDING_NEGOTIATED cells. + */ if (relay_command == RELAY_COMMAND_DROP) { /* Optimization: The event for RELAY_COMMAND_DROP is sent directly * from circpad_send_padding_cell_for_callback(). This is to avoid @@ -2087,25 +2385,112 @@ circpad_setup_machine_on_circ(circuit_t *on_circ, == NULL); tor_assert_nonfatal(on_circ->padding_info[machine->machine_index] == NULL); + /* Log message */ + if (CIRCUIT_IS_ORIGIN(on_circ)) { + log_info(LD_CIRC, "Registering machine %s to origin circ %u (%d)", + machine->name, + TO_ORIGIN_CIRCUIT(on_circ)->global_identifier, on_circ->purpose); + } else { + log_info(LD_CIRC, "Registering machine %s to non-origin circ (%d)", + machine->name, on_circ->purpose); + } + on_circ->padding_info[machine->machine_index] = circpad_circuit_machineinfo_new(on_circ, machine->machine_index); on_circ->padding_machine[machine->machine_index] = machine; } -/* These padding machines are only used for tests pending #28634. */ +/** Validate a single state of a padding machine */ +static bool +padding_machine_state_is_valid(const circpad_state_t *state) +{ + int b; + uint32_t tokens_count = 0; + circpad_delay_t prev_bin_edge = 0; + + /* We only validate histograms */ + if (!state->histogram_len) { + return true; + } + + /* We need at least two bins in a histogram */ + if (state->histogram_len < 2) { + log_warn(LD_CIRC, "You can't have a histogram with less than 2 bins"); + return false; + } + + /* For each machine state, if it's a histogram, make sure all the + * histogram edges are well defined (i.e. are strictly monotonic). */ + for (b = 0 ; b < state->histogram_len ; b++) { + /* Check that histogram edges are strictly increasing. Ignore the first + * edge since it can be zero. */ + if (prev_bin_edge >= state->histogram_edges[b] && b > 0) { + log_warn(LD_CIRC, "Histogram edges are not increasing [%u/%u]", + prev_bin_edge, state->histogram_edges[b]); + return false; + } + + prev_bin_edge = state->histogram_edges[b]; + + /* Also count the number of tokens as we go through the histogram states */ + tokens_count += state->histogram[b]; + } + /* Verify that the total number of tokens is correct */ + if (tokens_count != state->histogram_total_tokens) { + log_warn(LD_CIRC, "Histogram token count is wrong [%u/%u]", + tokens_count, state->histogram_total_tokens); + return false; + } + + return true; +} + +/** Basic validation of padding machine */ +static bool +padding_machine_is_valid(const circpad_machine_spec_t *machine) +{ + int i; + + /* Validate the histograms of the padding machine */ + for (i = 0 ; i < machine->num_states ; i++) { + if (!padding_machine_state_is_valid(&machine->states[i])) { + return false; + } + } + + return true; +} + +/* Validate and register machine into machine_list. If + * machine_list is NULL, then just validate. */ +void +circpad_register_padding_machine(circpad_machine_spec_t *machine, + smartlist_t *machine_list) +{ + if (!padding_machine_is_valid(machine)) { + log_warn(LD_CIRC, "Machine #%u is invalid. Ignoring.", + machine->machine_num); + return; + } + + if (machine_list) { + smartlist_add(machine_list, machine); + } +} + #ifdef TOR_UNIT_TESTS +/* These padding machines are only used for tests pending #28634. */ static void circpad_circ_client_machine_init(void) { circpad_machine_spec_t *circ_client_machine = tor_malloc_zero(sizeof(circpad_machine_spec_t)); - // XXX: Better conditions for merge.. Or disable this machine in - // merge? circ_client_machine->conditions.min_hops = 2; circ_client_machine->conditions.state_mask = CIRCPAD_CIRC_BUILDING|CIRCPAD_CIRC_OPENED|CIRCPAD_CIRC_HAS_RELAY_EARLY; circ_client_machine->conditions.purpose_mask = CIRCPAD_PURPOSE_ALL; + circ_client_machine->conditions.reduced_padding_ok = 1; circ_client_machine->target_hopnum = 2; circ_client_machine->is_origin_side = 1; @@ -2133,19 +2518,21 @@ circpad_circ_client_machine_init(void) circ_client_machine->states[CIRCPAD_STATE_BURST].token_removal = CIRCPAD_TOKEN_REMOVAL_CLOSEST; - // FIXME: Tune this histogram circ_client_machine->states[CIRCPAD_STATE_BURST].histogram_len = 2; - circ_client_machine->states[CIRCPAD_STATE_BURST].start_usec = 500; - circ_client_machine->states[CIRCPAD_STATE_BURST].range_usec = 1000000; + circ_client_machine->states[CIRCPAD_STATE_BURST].histogram_edges[0]= 500; + circ_client_machine->states[CIRCPAD_STATE_BURST].histogram_edges[1]= 1000000; + /* We have 5 tokens in the histogram, which means that all circuits will look * like they have 7 hops (since we start this machine after the second hop, * and tokens are decremented for any valid hops, and fake extends are * used after that -- 2+5==7). */ circ_client_machine->states[CIRCPAD_STATE_BURST].histogram[0] = 5; + circ_client_machine->states[CIRCPAD_STATE_BURST].histogram_total_tokens = 5; circ_client_machine->machine_num = smartlist_len(origin_padding_machines); - smartlist_add(origin_padding_machines, circ_client_machine); + circpad_register_padding_machine(circ_client_machine, + origin_padding_machines); } static void @@ -2192,8 +2579,9 @@ circpad_circ_responder_machine_init(void) circ_responder_machine->states[CIRCPAD_STATE_BURST].use_rtt_estimate = 1; /* The histogram is 2 bins: an empty one, and infinity */ circ_responder_machine->states[CIRCPAD_STATE_BURST].histogram_len = 2; - circ_responder_machine->states[CIRCPAD_STATE_BURST].start_usec = 5000; - circ_responder_machine->states[CIRCPAD_STATE_BURST].range_usec = 1000000; + circ_responder_machine->states[CIRCPAD_STATE_BURST].histogram_edges[0]= 500; + circ_responder_machine->states[CIRCPAD_STATE_BURST].histogram_edges[1] = + 1000000; /* During burst state we wait forever for padding to arrive. We are waiting for a padding cell from the client to come in, so that we @@ -2224,8 +2612,14 @@ circpad_circ_responder_machine_init(void) before you send a padding response */ circ_responder_machine->states[CIRCPAD_STATE_GAP].use_rtt_estimate = 1; circ_responder_machine->states[CIRCPAD_STATE_GAP].histogram_len = 6; - circ_responder_machine->states[CIRCPAD_STATE_GAP].start_usec = 5000; - circ_responder_machine->states[CIRCPAD_STATE_GAP].range_usec = 1000000; + /* Specify histogram bins */ + circ_responder_machine->states[CIRCPAD_STATE_GAP].histogram_edges[0]= 500; + circ_responder_machine->states[CIRCPAD_STATE_GAP].histogram_edges[1]= 1000; + circ_responder_machine->states[CIRCPAD_STATE_GAP].histogram_edges[2]= 2000; + circ_responder_machine->states[CIRCPAD_STATE_GAP].histogram_edges[3]= 4000; + circ_responder_machine->states[CIRCPAD_STATE_GAP].histogram_edges[4]= 8000; + circ_responder_machine->states[CIRCPAD_STATE_GAP].histogram_edges[5]= 16000; + /* Specify histogram tokens */ circ_responder_machine->states[CIRCPAD_STATE_GAP].histogram[0] = 0; circ_responder_machine->states[CIRCPAD_STATE_GAP].histogram[1] = 1; circ_responder_machine->states[CIRCPAD_STATE_GAP].histogram[2] = 2; @@ -2233,13 +2627,15 @@ circpad_circ_responder_machine_init(void) circ_responder_machine->states[CIRCPAD_STATE_GAP].histogram[4] = 1; /* Total number of tokens */ circ_responder_machine->states[CIRCPAD_STATE_GAP].histogram_total_tokens = 6; + circ_responder_machine->states[CIRCPAD_STATE_GAP].token_removal = CIRCPAD_TOKEN_REMOVAL_CLOSEST_USEC; circ_responder_machine->machine_num = smartlist_len(relay_padding_machines); - smartlist_add(relay_padding_machines, circ_responder_machine); + circpad_register_padding_machine(circ_responder_machine, + relay_padding_machines); } -#endif +#endif /* defined(TOR_UNIT_TESTS) */ /** * Initialize all of our padding machines. @@ -2256,6 +2652,14 @@ circpad_machines_init(void) origin_padding_machines = smartlist_new(); relay_padding_machines = smartlist_new(); + /* Register machines for hiding client-side intro circuits */ + circpad_machine_client_hide_intro_circuits(origin_padding_machines); + circpad_machine_relay_hide_intro_circuits(relay_padding_machines); + + /* Register machines for hiding client-side rendezvous circuits */ + circpad_machine_client_hide_rend_circuits(origin_padding_machines); + circpad_machine_relay_hide_rend_circuits(relay_padding_machines); + // TODO: Parse machines from consensus and torrc #ifdef TOR_UNIT_TESTS circpad_circ_client_machine_init(); @@ -2292,8 +2696,9 @@ circpad_node_supports_padding(const node_t *node) { if (node->rs) { log_fn(LOG_INFO, LD_CIRC, "Checking padding: %s", - node->rs->pv.supports_padding ? "supported" : "unsupported"); - return node->rs->pv.supports_padding; + node->rs->pv.supports_hs_setup_padding ? + "supported" : "unsupported"); + return node->rs->pv.supports_hs_setup_padding; } log_fn(LOG_INFO, LD_CIRC, "Empty routerstatus in padding check"); @@ -2306,8 +2711,8 @@ circpad_node_supports_padding(const node_t *node) * Returns node_t from the consensus for that hop, if it is opened. * Otherwise returns NULL. */ -static const node_t * -circuit_get_nth_node(origin_circuit_t *circ, int hop) +MOCK_IMPL(STATIC const node_t *, +circuit_get_nth_node,(origin_circuit_t *circ, int hop)) { crypt_path_t *iter = circuit_get_cpath_hop(circ, hop); @@ -2370,8 +2775,9 @@ circpad_negotiate_padding(origin_circuit_t *circ, &type)) < 0) return -1; - log_fn(LOG_INFO,LD_CIRC, "Negotiating padding on circuit %u", - circ->global_identifier); + log_fn(LOG_INFO,LD_CIRC, + "Negotiating padding on circuit %u (%d), command %d", + circ->global_identifier, TO_CIRCUIT(circ)->purpose, command); return circpad_send_command_to_hop(circ, target_hopnum, RELAY_COMMAND_PADDING_NEGOTIATE, @@ -2434,7 +2840,8 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell) if (CIRCUIT_IS_ORIGIN(circ)) { log_fn(LOG_PROTOCOL_WARN, LD_CIRC, - "Padding negotiate cell unsupported at origin."); + "Padding negotiate cell unsupported at origin (circuit %u)", + TO_ORIGIN_CIRCUIT(circ)->global_identifier); return -1; } @@ -2461,6 +2868,7 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell) const circpad_machine_spec_t *, m) { if (m->machine_num == negotiate->machine_type) { circpad_setup_machine_on_circ(circ, m); + circpad_cell_event_nonpadding_received(circ); goto done; } } SMARTLIST_FOREACH_END(m); @@ -2500,20 +2908,24 @@ circpad_handle_padding_negotiated(circuit_t *circ, cell_t *cell, /* Verify this came from the expected hop */ if (!circpad_padding_is_from_expected_hop(circ, layer_hint)) { - log_fn(LOG_WARN, LD_CIRC, - "Padding negotiated cell from wrong hop!"); + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Padding negotiated cell from wrong hop on circuit %u", + TO_ORIGIN_CIRCUIT(circ)->global_identifier); return -1; } if (circpad_negotiated_parse(&negotiated, cell->payload+RELAY_HEADER_SIZE, CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_CIRC, - "Received malformed PADDING_NEGOTIATED cell; " - "dropping."); + "Received malformed PADDING_NEGOTIATED cell on circuit %u; " + "dropping.", TO_ORIGIN_CIRCUIT(circ)->global_identifier); return -1; } if (negotiated->command == CIRCPAD_COMMAND_STOP) { + log_info(LD_CIRC, + "Received STOP command on PADDING_NEGOTIATED for circuit %u", + TO_ORIGIN_CIRCUIT(circ)->global_identifier); /* There may not be a padding_info here if we shut down the * machine in circpad_shutdown_old_machines(). Or, if * circpad_add_matching_matchines() added a new machine, @@ -2527,13 +2939,45 @@ circpad_handle_padding_negotiated(circuit_t *circ, cell_t *cell, free_circ_machineinfos_with_machine_num(circ, negotiated->machine_type); TO_ORIGIN_CIRCUIT(circ)->padding_negotiation_failed = 1; log_fn(LOG_PROTOCOL_WARN, LD_CIRC, - "Middle node did not accept our padding request."); + "Middle node did not accept our padding request on circuit %u (%d)", + TO_ORIGIN_CIRCUIT(circ)->global_identifier, + circ->purpose); } circpad_negotiated_free(negotiated); return 0; } +/** Free memory allocated by this machine spec. */ +STATIC void +machine_spec_free_(circpad_machine_spec_t *m) +{ + if (!m) return; + + tor_free(m->states); + tor_free(m); +} + +/** Free all memory allocated by the circuitpadding subsystem. */ +void +circpad_free_all(void) +{ + if (origin_padding_machines) { + SMARTLIST_FOREACH_BEGIN(origin_padding_machines, + circpad_machine_spec_t *, m) { + machine_spec_free(m); + } SMARTLIST_FOREACH_END(m); + smartlist_free(origin_padding_machines); + } + if (relay_padding_machines) { + SMARTLIST_FOREACH_BEGIN(relay_padding_machines, + circpad_machine_spec_t *, m) { + machine_spec_free(m); + } SMARTLIST_FOREACH_END(m); + smartlist_free(relay_padding_machines); + } +} + /* Serialization */ // TODO: Should we use keyword=value here? Are there helpers for that? #if 0 @@ -2586,4 +3030,4 @@ circpad_string_to_machine(const char *str) return NULL; } -#endif +#endif /* 0 */ diff --git a/src/core/or/circuitpadding.h b/src/core/or/circuitpadding.h index 92fd4fc2d5..3cf40e11db 100644 --- a/src/core/or/circuitpadding.h +++ b/src/core/or/circuitpadding.h @@ -10,7 +10,7 @@ #ifndef TOR_CIRCUITPADDING_H #define TOR_CIRCUITPADDING_H -#include "src/trunnel/circpad_negotiation.h" +#include "trunnel/circpad_negotiation.h" #include "lib/evloop/timers.h" struct circuit_t; @@ -73,6 +73,7 @@ typedef uint64_t circpad_time_t; /** The type for timer delays, in microseconds */ typedef uint32_t circpad_delay_t; +#define CIRCPAD_DELAY_UNITS_PER_SECOND (1000*1000) /** * An infinite padding cell delay means don't schedule any padding -- @@ -85,10 +86,17 @@ typedef uint32_t circpad_delay_t; */ #define CIRCPAD_DELAY_INFINITE (UINT32_MAX) +/** + * This is the maximum delay that the circuit padding system can have, in + * seconds. + */ +#define CIRCPAD_DELAY_MAX_SECS \ + ((CIRCPAD_DELAY_INFINITE/CIRCPAD_DELAY_UNITS_PER_SECOND)+1) + /** * Macro to clarify when we're checking the infinity bin. * - * Works with either circpad_state_t or circpad_machine_state_t + * Works with either circpad_state_t or circpad_machine_runtime_t */ #define CIRCPAD_INFINITY_BIN(mi) ((mi)->histogram_len-1) @@ -152,6 +160,17 @@ typedef struct circpad_machine_conditions_t { /** Only apply the machine *if* vanguards are enabled */ unsigned requires_vanguards : 1; + /** + * This machine is ok to use if reduced padding is set in consensus + * or torrc. This machine will still be applied even if reduced padding + * is not set; this flag only acts to exclude machines that don't have + * it set when reduced padding is requested. Therefore, reduced padding + * machines should appear at the lowest priority in the padding machine + * lists (aka first in the list), so that non-reduced padding machines + * for the same purpose are given a chance to apply when reduced padding + * is not requested. */ + unsigned reduced_padding_ok : 1; + /** Only apply the machine *if* the circuit's state matches any of * the bits set in this bitmask. */ circpad_circuit_state_t state_mask; @@ -198,14 +217,23 @@ typedef enum { * These can be used instead of histograms for the inter-packet * timing distribution, or to specify a distribution on the number * of cells that can be sent while in a specific state of the state - * machine. */ + * machine. + * + * Each distribution takes up to two parameters which are described below. */ typedef enum { + /* No probability distribution is used */ CIRCPAD_DIST_NONE = 0, + /* Uniform distribution: param1 is lower bound and param2 is upper bound */ CIRCPAD_DIST_UNIFORM = 1, + /* Logistic distribution: param1 is Mu, param2 is sigma. */ CIRCPAD_DIST_LOGISTIC = 2, + /* Log-logistic distribution: param1 is Alpha, param2 is 1.0/Beta */ CIRCPAD_DIST_LOG_LOGISTIC = 3, + /* Geometric distribution: param1 is 'p' (success probability) */ CIRCPAD_DIST_GEOMETRIC = 4, + /* Weibull distribution: param1 is k, param2 is Lambda */ CIRCPAD_DIST_WEIBULL = 5, + /* Generalized Pareto distribution: param1 is sigma, param2 is xi */ CIRCPAD_DIST_PARETO = 6 } circpad_distribution_type_t; @@ -228,19 +256,24 @@ typedef uint16_t circpad_statenum_t; #define CIRCPAD_STATENUM_MAX (UINT16_MAX) /** A histogram is used to sample padding delays given a machine state. This - * constant defines the maximum histogram width (i.e. the max number of bins) + * constant defines the maximum histogram width (i.e. the max number of bins). * - * Each histogram bin is twice as large as the previous. Two exceptions: The - * first bin has zero width (which means that minimum delay is applied to the - * next padding cell), and the last bin (infinity bin) has infinite width - * (which means that the next padding cell will be delayed infinitely). */ -#define CIRCPAD_MAX_HISTOGRAM_LEN (sizeof(circpad_delay_t)*8 + 1) + * The current limit is arbitrary and could be raised if there is a need, + * however too many bins will be hard to serialize in the future. + * + * Memory concerns are not so great here since the corresponding histogram and + * histogram_edges arrays are global and not per-circuit. + * + * If we ever upgrade this to a value that can't be represented by 8-bits we + * also need to upgrade circpad_hist_index_t. + */ +#define CIRCPAD_MAX_HISTOGRAM_LEN (100) /** * A state of a padding state machine. The information here are immutable and * represent the initial form of the state; it does not get updated as things * happen. The mutable information that gets updated in runtime are carried in - * a circpad_machine_state_t. + * a circpad_machine_runtime_t. * * This struct describes the histograms and parameters of a single * state in the adaptive padding machine. Instances of this struct @@ -248,38 +281,60 @@ typedef uint16_t circpad_statenum_t; * or the consensus. */ typedef struct circpad_state_t { - /** If a histogram is used for this state, this specifies the number of bins - * of this histogram. Histograms must have at least 2 bins. + /** + * If a histogram is used for this state, this specifies the number of bins + * of this histogram. Histograms must have at least 2 bins. + * + * In particular, the following histogram: + * + * Tokens + * + + * 10 | +----+ + * 9 | | | +---------+ + * 8 | | | | | + * 7 | | | +-----+ | + * 6 +----+ Bin+-----+ | +---------------+ + * 5 | | #1 | | | | | + * | Bin| | Bin | Bin | Bin #4 | Bin #5 | + * | #0 | | #2 | #3 | | (infinity bin)| + * | | | | | | | + * | | | | | | | + * 0 +----+----+-----+-----+---------+---------------+ + * 0 100 200 350 500 1000 ∞ microseconds * - * If a delay probability distribution is used for this state, this is set - * to 0. */ + * would be specified the following way: + * histogram_len = 6; + * histogram[] = { 6, 10, 6, 7, 9, 6 } + * histogram_edges[] = { 0, 100, 200, 350, 500, 1000 } + * + * The final bin is called the "infinity bin" and if it's chosen we don't + * schedule any padding. The infinity bin is strange because its lower edge + * is the max value of possible non-infinite delay allowed by this histogram, + * and its upper edge is CIRCPAD_DELAY_INFINITE. You can tell if the infinity + * bin is chosen by inspecting its bin index or inspecting its upper edge. + * + * If a delay probability distribution is used for this state, this is set + * to 0. */ circpad_hist_index_t histogram_len; /** The histogram itself: an array of uint16s of tokens, whose - * widths are exponentially spaced, in microseconds */ + * widths are exponentially spaced, in microseconds. + * + * This array must have histogram_len elements that are strictly + * monotonically increasing. */ circpad_hist_token_t histogram[CIRCPAD_MAX_HISTOGRAM_LEN]; + /* The histogram bin edges in usec. + * + * Each element of this array specifies the left edge of the corresponding + * bin. The rightmost edge is always infinity and is not specified in this + * array. + * + * This array must have histogram_len elements. */ + circpad_delay_t histogram_edges[CIRCPAD_MAX_HISTOGRAM_LEN+1]; /** Total number of tokens in this histogram. This is a constant and is *not* * decremented every time we spend a token. It's used for initializing and * refilling the histogram. */ uint32_t histogram_total_tokens; - /** Minimum padding delay of this state in microseconds. - * - * If histograms are used, this is the left (and right) bound of the first - * bin (since it has zero width). - * - * If a delay probability distribution is used, this represents the minimum - * delay we can sample from the distribution. - */ - circpad_delay_t start_usec; - - /** If histograms are used, this is the width of the whole histogram in - * microseconds, and it's used to calculate individual bin width. - * - * If a delay probability distribution is used, this is used as the max - * delay we can sample from the distribution. - */ - circpad_delay_t range_usec; - /** * Represents a delay probability distribution (aka IAT distribution). It's a * parametrized way of encoding inter-packet delay information in @@ -292,6 +347,16 @@ typedef struct circpad_state_t { * results of sampling from this distribution (range_sec is used as a max). */ circpad_distribution_t iat_dist; + /* If a delay probability distribution is used, this is used as the max + * value we can sample from the distribution. However, RTT measurements and + * dist_added_shift gets applied on top of this value to derive the final + * padding delay. */ + circpad_delay_t dist_max_sample_usec; + /* If a delay probability distribution is used and this is set, we will add + * this value on top of the value sampled from the IAT distribution to + * derive the final padding delay (We also add the RTT measurement if it's + * enabled.). */ + circpad_delay_t dist_added_shift_usec; /** * The length dist is a parameterized way of encoding how long this @@ -430,7 +495,7 @@ typedef struct circpad_state_t { * * XXX: Play with layout to minimize space on x64 Linux (most common relay). */ -typedef struct circpad_machine_state_t { +typedef struct circpad_machine_runtime_t { /** The callback pointer for the padding callbacks. * * These timers stick around the machineinfo until the machineinfo's circuit @@ -467,6 +532,14 @@ typedef struct circpad_machine_state_t { * half. */ uint16_t nonpadding_sent; + /** + * Timestamp of the most recent cell event (sent, received, padding, + * non-padding), in seconds from approx_time(). + * + * Used as an emergency break to stop holding padding circuits open. + */ + time_t last_cell_time_sec; + /** * EWMA estimate of the RTT of the circuit from this hop * to the exit end, in microseconds. */ @@ -514,7 +587,7 @@ typedef struct circpad_machine_state_t { * CIRCPAD_MAX_MACHINES define). */ unsigned machine_index : 1; -} circpad_machine_state_t; +} circpad_machine_runtime_t; /** Helper macro to get an actual state machine from a machineinfo */ #define CIRCPAD_GET_MACHINE(machineinfo) \ @@ -530,6 +603,9 @@ typedef uint8_t circpad_machine_num_t; /** Global state machine structure from the consensus */ typedef struct circpad_machine_spec_t { + /* Just a user-friendly machine name for logs */ + const char *name; + /** Global machine number */ circpad_machine_num_t machine_num; @@ -548,6 +624,19 @@ typedef struct circpad_machine_spec_t { * 1-indexed (ie: hop #1 is guard, #2 middle, #3 exit). */ unsigned target_hopnum : 3; + /** If this flag is enabled, don't close circuits that use this machine even + * if another part of Tor wants to close this circuit. + * + * If this flag is set, the circuitpadding subsystem will close circuits the + * moment the machine transitions to the END state, and only if the circuit + * has already been asked to be closed by another part of Tor. + * + * Circuits that should have been closed but were kept open by a padding + * machine are re-purposed to CIRCUIT_PURPOSE_C_CIRCUIT_PADDING, hence + * machines should take that purpose into account if they are filtering + * circuits by purpose. */ + unsigned manage_circ_lifetime : 1; + /** This machine only kills fascists if the following conditions are met. */ circpad_machine_conditions_t conditions; @@ -573,6 +662,8 @@ typedef struct circpad_machine_spec_t { void circpad_new_consensus_params(const networkstatus_t *ns); +int circpad_marked_circuit_for_padding(circuit_t *circ, int reason); + /** * The following are event call-in points that are of interest to * the state machines. They are called during cell processing. */ @@ -592,11 +683,11 @@ void circpad_cell_event_padding_received(struct circuit_t *on_circ); /** Internal events are events the machines send to themselves */ circpad_decision_t -circpad_internal_event_infinity(circpad_machine_state_t *mi); +circpad_internal_event_infinity(circpad_machine_runtime_t *mi); circpad_decision_t -circpad_internal_event_bins_empty(circpad_machine_state_t *); +circpad_internal_event_bins_empty(circpad_machine_runtime_t *); circpad_decision_t circpad_internal_event_state_length_up( - circpad_machine_state_t *); + circpad_machine_runtime_t *); /** Machine creation events are events that cause us to set up or * tear down padding state machines. */ @@ -610,6 +701,8 @@ circpad_machine_event_circ_has_no_relay_early(struct origin_circuit_t *circ); void circpad_machines_init(void); void circpad_machines_free(void); +void circpad_register_padding_machine(circpad_machine_spec_t *machine, + smartlist_t *machine_list); void circpad_machine_states_init(circpad_machine_spec_t *machine, circpad_statenum_t num_states); @@ -638,59 +731,78 @@ bool circpad_padding_negotiated(struct circuit_t *circ, uint8_t command, uint8_t response); +circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t circ_purpose); + MOCK_DECL(circpad_decision_t, -circpad_machine_schedule_padding,(circpad_machine_state_t *)); +circpad_machine_schedule_padding,(circpad_machine_runtime_t *)); MOCK_DECL(circpad_decision_t, -circpad_machine_spec_transition, (circpad_machine_state_t *mi, +circpad_machine_spec_transition, (circpad_machine_runtime_t *mi, circpad_event_t event)); circpad_decision_t circpad_send_padding_cell_for_callback( - circpad_machine_state_t *mi); + circpad_machine_runtime_t *mi); + +void circpad_free_all(void); #ifdef CIRCUITPADDING_PRIVATE +STATIC void machine_spec_free_(circpad_machine_spec_t *m); +#define machine_spec_free(chan) \ + FREE_AND_NULL(circpad_machine_spec_t,machine_spec_free_, (m)) + STATIC circpad_delay_t -circpad_machine_sample_delay(circpad_machine_state_t *mi); +circpad_machine_sample_delay(circpad_machine_runtime_t *mi); STATIC bool -circpad_machine_reached_padding_limit(circpad_machine_state_t *mi); - -STATIC -circpad_decision_t circpad_machine_remove_token(circpad_machine_state_t *mi); +circpad_machine_reached_padding_limit(circpad_machine_runtime_t *mi); STATIC circpad_delay_t -circpad_histogram_bin_to_usec(const circpad_machine_state_t *mi, +circpad_histogram_bin_to_usec(const circpad_machine_runtime_t *mi, circpad_hist_index_t bin); STATIC const circpad_state_t * -circpad_machine_current_state(const circpad_machine_state_t *mi); +circpad_machine_current_state(const circpad_machine_runtime_t *mi); + +STATIC void circpad_machine_remove_token(circpad_machine_runtime_t *mi); STATIC circpad_hist_index_t circpad_histogram_usec_to_bin( - const circpad_machine_state_t *mi, + const circpad_machine_runtime_t *mi, circpad_delay_t us); -STATIC circpad_machine_state_t *circpad_circuit_machineinfo_new( +STATIC circpad_machine_runtime_t *circpad_circuit_machineinfo_new( struct circuit_t *on_circ, int machine_index); -STATIC void circpad_machine_remove_higher_token(circpad_machine_state_t *mi, +STATIC void circpad_machine_remove_higher_token(circpad_machine_runtime_t *mi, circpad_delay_t target_bin_us); -STATIC void circpad_machine_remove_lower_token(circpad_machine_state_t *mi, +STATIC void circpad_machine_remove_lower_token(circpad_machine_runtime_t *mi, circpad_delay_t target_bin_us); -STATIC void circpad_machine_remove_closest_token(circpad_machine_state_t *mi, +STATIC void circpad_machine_remove_closest_token(circpad_machine_runtime_t *mi, circpad_delay_t target_bin_us, bool use_usec); -STATIC void circpad_machine_setup_tokens(circpad_machine_state_t *mi); +STATIC void circpad_machine_setup_tokens(circpad_machine_runtime_t *mi); MOCK_DECL(STATIC signed_error_t, circpad_send_command_to_hop,(struct origin_circuit_t *circ, uint8_t hopnum, uint8_t relay_command, const uint8_t *payload, ssize_t payload_len)); +MOCK_DECL(STATIC const node_t *, +circuit_get_nth_node,(origin_circuit_t *circ, int hop)); + +STATIC circpad_delay_t +histogram_get_bin_upper_bound(const circpad_machine_runtime_t *mi, + circpad_hist_index_t bin); + +STATIC void +circpad_add_matching_machines(origin_circuit_t *on_circ, + smartlist_t *machines_sl); + #ifdef TOR_UNIT_TESTS extern smartlist_t *origin_padding_machines; extern smartlist_t *relay_padding_machines; -#endif #endif -#endif +#endif /* defined(CIRCUITPADDING_PRIVATE) */ + +#endif /* !defined(TOR_CIRCUITPADDING_H) */ diff --git a/src/core/or/circuitpadding_machines.c b/src/core/or/circuitpadding_machines.c new file mode 100644 index 0000000000..75d2614aca --- /dev/null +++ b/src/core/or/circuitpadding_machines.c @@ -0,0 +1,458 @@ +/* Copyright (c) 2019 The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitpadding_machines.c + * \brief Circuit padding state machines + * + * \detail + * + * Introduce circuit padding machines that will be used by Tor circuits, as + * specified by proposal 302 "Hiding onion service clients using padding". + * + * Right now this file introduces two machines that aim to hide the client-side + * of onion service circuits against naive classifiers like the ones from the + * "Circuit Fingerprinting Attacks: Passive Deanonymization of Tor Hidden + * Services" paper from USENIX. By naive classifiers we mean classifiers that + * use basic features like "circuit construction circuits" and "incoming and + * outgoing cell counts" and "duration of activity". + * + * In particular, these machines aim to be lightweight and protect against + * these basic classifiers. They don't aim to protect against more advanced + * attacks that use deep learning or even correlate various circuit + * construction events together. Machines that fool such advanced classifiers + * are also possible, but they can't be so lightweight and might require more + * WTF-PAD features. So for now we opt for the following two machines: + * + * Client-side introduction circuit hiding machine: + * + * This machine hides client-side introduction circuits by making their + * circuit consruction sequence look like normal general circuits that + * download directory information. Furthermore, the circuits are kept open + * until all the padding has been sent, since intro circuits are usually + * very short lived and this act as a distinguisher. For more info see + * circpad_machine_client_hide_intro_circuits() and the sec. + * + * Client-side rendezvous circuit hiding machine: + * + * This machine hides client-side rendezvous circuits by making their + * circuit construction sequence look like normal general circuits. For more + * details see circpad_machine_client_hide_rend_circuits() and the spec. + * + * TODO: These are simple machines that carefully manipulate the cells of the + * initial circuit setup procedure to make them look like general + * circuits. In the future, more states can be baked into their state machine + * to do more advanced obfuscation. + **/ + +#define CIRCUITPADDING_MACHINES_PRIVATE + +#include "core/or/or.h" +#include "feature/nodelist/networkstatus.h" + +#include "lib/crypt_ops/crypto_rand.h" + +#include "core/or/circuitlist.h" + +#include "core/or/circuitpadding_machines.h" +#include "core/or/circuitpadding.h" + +/** Create a client-side padding machine that aims to hide IP circuits. In + * particular, it keeps intro circuits alive until a bunch of fake traffic has + * been pushed through. + */ +void +circpad_machine_client_hide_intro_circuits(smartlist_t *machines_sl) +{ + circpad_machine_spec_t *client_machine + = tor_malloc_zero(sizeof(circpad_machine_spec_t)); + + client_machine->name = "client_ip_circ"; + + client_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED; + client_machine->target_hopnum = 2; + + /* This is a client machine */ + client_machine->is_origin_side = 1; + + /* We only want to pad introduction circuits, and we want to start padding + * only after the INTRODUCE1 cell has been sent, so set the purposes + * appropriately. + * + * In particular we want introduction circuits to blend as much as possible + * with general circuits. Most general circuits have the following initial + * relay cell sequence (outgoing cells marked in [brackets]): + * + * [EXTEND2] -> EXTENDED2 -> [EXTEND2] -> EXTENDED2 -> [BEGIN] -> CONNECTED + * -> [DATA] -> [DATA] -> DATA -> DATA...(inbound data cells continue) + * + * Whereas normal introduction circuits usually look like: + * + * [EXTEND2] -> EXTENDED2 -> [EXTEND2] -> EXTENDED2 -> [EXTEND2] -> EXTENDED2 + * -> [INTRO1] -> INTRODUCE_ACK + * + * This means that up to the sixth cell (first line of each sequence above), + * both general and intro circuits have identical cell sequences. After that + * we want to mimic the second line sequence of + * -> [DATA] -> [DATA] -> DATA -> DATA...(inbound data cells continue) + * + * We achieve this by starting padding INTRODUCE1 has been sent. With padding + * negotiation cells, in the common case of the second line looks like: + * -> [INTRO1] -> [PADDING_NEGOTIATE] -> PADDING_NEGOTIATED -> INTRO_ACK + * + * Then, the middle node will send between INTRO_MACHINE_MINIMUM_PADDING and + * INTRO_MACHINE_MAXIMUM_PADDING cells, to match the "...(inbound data cells + * continue)" portion of the trace (aka the rest of an HTTPS response body). + */ + client_machine->conditions.purpose_mask = + circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)| + circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_INTRODUCE_ACKED)| + circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_CIRCUIT_PADDING); + + /* Keep the circuit alive even after the introduction has been finished, + * otherwise the short-term lifetime of the circuit will blow our cover */ + client_machine->manage_circ_lifetime = 1; + + /* Set padding machine limits to help guard against excessive padding */ + client_machine->allowed_padding_count = INTRO_MACHINE_MAXIMUM_PADDING; + client_machine->max_padding_percent = 1; + + /* Two states: START, OBFUSCATE_CIRC_SETUP (and END) */ + circpad_machine_states_init(client_machine, 2); + + /* For the origin-side machine, we transition to OBFUSCATE_CIRC_SETUP after + * sending PADDING_NEGOTIATE, and we stay there (without sending any padding) + * until we receive a STOP from the other side. */ + client_machine->states[CIRCPAD_STATE_START]. + next_state[CIRCPAD_EVENT_NONPADDING_SENT] = + CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP; + + /* origin-side machine has no event reactions while in + * CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP, so no more state transitions here. */ + + /* The client side should never send padding, so it does not need + * to specify token removal, or a histogram definition or state lengths. + * That is all controlled by the middle node. */ + + /* Register the machine */ + client_machine->machine_num = smartlist_len(machines_sl); + circpad_register_padding_machine(client_machine, machines_sl); + + log_info(LD_CIRC, + "Registered client intro point hiding padding machine (%u)", + client_machine->machine_num); +} + +/** Create a relay-side padding machine that aims to hide IP circuits. See + * comments on the function above for more details on the workings of the + * machine. */ +void +circpad_machine_relay_hide_intro_circuits(smartlist_t *machines_sl) +{ + circpad_machine_spec_t *relay_machine + = tor_malloc_zero(sizeof(circpad_machine_spec_t)); + + relay_machine->name = "relay_ip_circ"; + + relay_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED; + relay_machine->target_hopnum = 2; + + /* This is a relay-side machine */ + relay_machine->is_origin_side = 0; + + /* We want to negotiate END from this side after all our padding is done, so + * that the origin-side machine goes into END state, and eventually closes + * the circuit. */ + relay_machine->should_negotiate_end = 1; + + /* Set padding machine limits to help guard against excessive padding */ + relay_machine->allowed_padding_count = INTRO_MACHINE_MAXIMUM_PADDING; + relay_machine->max_padding_percent = 1; + + /* Two states: START, OBFUSCATE_CIRC_SETUP (and END) */ + circpad_machine_states_init(relay_machine, 2); + + /* For the relay-side machine, we want to transition + * START -> OBFUSCATE_CIRC_SETUP upon first non-padding + * cell sent (PADDING_NEGOTIATED in this case). */ + relay_machine->states[CIRCPAD_STATE_START]. + next_state[CIRCPAD_EVENT_NONPADDING_SENT] = + CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP; + + /* For the relay-side, we want to transition from OBFUSCATE_CIRC_SETUP to END + * state when the length finishes. */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END; + + /* Now let's define the OBF -> OBF transitions that maintain our padding + * flow: + * + * For the relay-side machine, we want to keep on sending padding bytes even + * when nothing else happens on this circuit. */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + next_state[CIRCPAD_EVENT_PADDING_SENT] = + CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP; + /* For the relay-side machine, we need this transition so that we re-enter + the state, after PADDING_NEGOTIATED is sent. Otherwise, the remove token + function will disable the timer, and nothing will restart it since there + is no other motion on an intro circuit. */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + next_state[CIRCPAD_EVENT_NONPADDING_SENT] = + CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP; + + /* Token removal strategy for OBFUSCATE_CIRC_SETUP state: Don't + * remove any tokens. + * + * We rely on the state length sampling and not token removal, to avoid + * the mallocs required to copy the histograms for token removal, + * and to avoid monotime calls needed to determine histogram + * bins for token removal. */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + token_removal = CIRCPAD_TOKEN_REMOVAL_NONE; + + /* Figure out the length of the OBFUSCATE_CIRC_SETUP state so that it's + * randomized. The relay side will send between INTRO_MACHINE_MINIMUM_PADDING + * and INTRO_MACHINE_MAXIMUM_PADDING padding cells towards the client. */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + length_dist.type = CIRCPAD_DIST_UNIFORM; + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + length_dist.param1 = INTRO_MACHINE_MINIMUM_PADDING; + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + length_dist.param2 = INTRO_MACHINE_MAXIMUM_PADDING; + + /* Configure histogram */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram_len = 2; + + /* For the relay-side machine we want to batch padding instantly to pretend + * its an incoming directory download. So set the histogram edges tight: + * (1, 10ms, infinity). */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram_edges[0] = 1000; + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram_edges[1] = 10000; + + /* We put all our tokens in bin 0, which means we want 100% probability + * for choosing a inter-packet delay of between 1000 and 10000 microseconds + * (1 to 10ms). Since we only have 1 bin, it doesn't matter how many tokens + * there are, 1000 out of 1000 is 100% */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram[0] = 1000; + + /* just one bin, so setup the total tokens */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram_total_tokens = + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].histogram[0]; + + /* Register the machine */ + relay_machine->machine_num = smartlist_len(machines_sl); + circpad_register_padding_machine(relay_machine, machines_sl); + + log_info(LD_CIRC, + "Registered relay intro circuit hiding padding machine (%u)", + relay_machine->machine_num); +} + +/************************** Rendezvous-circuit machine ***********************/ + +/** Create a client-side padding machine that aims to hide rendezvous + * circuits.*/ +void +circpad_machine_client_hide_rend_circuits(smartlist_t *machines_sl) +{ + circpad_machine_spec_t *client_machine + = tor_malloc_zero(sizeof(circpad_machine_spec_t)); + + client_machine->name = "client_rp_circ"; + + /* Only pad after the circuit has been built and pad to the middle */ + client_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED; + client_machine->target_hopnum = 2; + + /* This is a client machine */ + client_machine->is_origin_side = 1; + + /* We only want to pad rendezvous circuits, and we want to start padding only + * after the rendezvous circuit has been established. + * + * Following a similar argument as for intro circuits, we are aiming for + * padded rendezvous circuits to blend in with the initial cell sequence of + * general circuits which usually look like this: + * + * [EXTEND2] -> EXTENDED2 -> [EXTEND2] -> EXTENDED2 -> [BEGIN] -> CONNECTED + * -> [DATA] -> [DATA] -> DATA -> DATA...(incoming cells continue) + * + * Whereas normal rendezvous circuits usually look like: + * + * [EXTEND2] -> EXTENDED2 -> [EXTEND2] -> EXTENDED2 -> [EST_REND] -> REND_EST + * -> REND2 -> [BEGIN] + * + * This means that up to the sixth cell (in the first line), both general and + * rend circuits have identical cell sequences. + * + * After that we want to mimic a [DATA] -> [DATA] -> DATA -> DATA sequence. + * + * With padding negotiation right after the REND_ESTABLISHED, the sequence + * becomes: + * + * [EXTEND2] -> EXTENDED2 -> [EXTEND2] -> EXTENDED2 -> [EST_REND] -> REND_EST + * -> [PADDING_NEGOTIATE] -> [DROP] -> PADDING_NEGOTIATED -> DROP... + * + * After which normal application DATA cells continue on the circuit. + * + * Hence this way we make rendezvous circuits look like general circuits up + * till the end of the circuit setup. */ + client_machine->conditions.purpose_mask = + circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_REND_JOINED)| + circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_REND_READY)| + circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED); + + /* Set padding machine limits to help guard against excessive padding */ + client_machine->allowed_padding_count = 1; + client_machine->max_padding_percent = 1; + + /* Two states: START, OBFUSCATE_CIRC_SETUP (and END) */ + circpad_machine_states_init(client_machine, 2); + + /* START -> OBFUSCATE_CIRC_SETUP transition upon sending the first + * non-padding cell (which is PADDING_NEGOTIATE) */ + client_machine->states[CIRCPAD_STATE_START]. + next_state[CIRCPAD_EVENT_NONPADDING_SENT] = + CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP; + + /* OBFUSCATE_CIRC_SETUP -> END transition when we send our first + * padding packet and/or hit the state length (the state length is 1). */ + client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + next_state[CIRCPAD_EVENT_PADDING_RECV] = CIRCPAD_STATE_END; + client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END; + + /* Don't use a token removal strategy since we don't want to use monotime + * functions and we want to avoid mallocing histogram copies. We want + * this machine to be light. */ + client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + token_removal = CIRCPAD_TOKEN_REMOVAL_NONE; + + /* Instead, to control the volume of padding (we just want to send a single + * padding cell) we will use a static state length. We just want one token, + * since we want to make the following pattern: + * [PADDING_NEGOTIATE] -> [DROP] -> PADDING_NEGOTIATED -> DROP */ + client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + length_dist.type = CIRCPAD_DIST_UNIFORM; + client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + length_dist.param1 = 1; + client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + length_dist.param2 = 2; // rand(1,2) is always 1 + + /* Histogram is: (0 msecs, 1 msec, infinity). We want this to be fast so + * that we send our outgoing [DROP] before the PADDING_NEGOTIATED comes + * back from the relay side. */ + client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram_len = 2; + client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram_edges[0] = 0; + client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram_edges[1] = 1000; + + /* We want a 100% probability of choosing an inter-packet delay of + * between 0 and 1ms. Since we don't use token removal, + * the number of tokens does not matter. (And also, state_length + * governs how many packets we send). */ + client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram[0] = 1; + client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram_total_tokens = 1; + + /* Register the machine */ + client_machine->machine_num = smartlist_len(machines_sl); + circpad_register_padding_machine(client_machine, machines_sl); + + log_info(LD_CIRC, + "Registered client rendezvous circuit hiding padding machine (%u)", + client_machine->machine_num); +} + +/** Create a relay-side padding machine that aims to hide IP circuits. + * + * This is meant to follow the client-side machine. + */ +void +circpad_machine_relay_hide_rend_circuits(smartlist_t *machines_sl) +{ + circpad_machine_spec_t *relay_machine + = tor_malloc_zero(sizeof(circpad_machine_spec_t)); + + relay_machine->name = "relay_rp_circ"; + + /* Only pad after the circuit has been built and pad to the middle */ + relay_machine->conditions.min_hops = 2; + relay_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED; + relay_machine->target_hopnum = 2; + + /* This is a relay-side machine */ + relay_machine->is_origin_side = 0; + + /* Set padding machine limits to help guard against excessive padding */ + relay_machine->allowed_padding_count = 1; + relay_machine->max_padding_percent = 1; + + /* Two states: START, OBFUSCATE_CIRC_SETUP (and END) */ + circpad_machine_states_init(relay_machine, 2); + + /* START -> OBFUSCATE_CIRC_SETUP transition upon sending the first + * non-padding cell (which is PADDING_NEGOTIATED) */ + relay_machine->states[CIRCPAD_STATE_START]. + next_state[CIRCPAD_EVENT_NONPADDING_SENT] = + CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP; + + /* OBFUSCATE_CIRC_SETUP -> END transition when we send our first + * padding packet and/or hit the state length (the state length is 1). */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + next_state[CIRCPAD_EVENT_PADDING_RECV] = CIRCPAD_STATE_END; + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END; + + /* Don't use a token removal strategy since we don't want to use monotime + * functions and we want to avoid mallocing histogram copies. We want + * this machine to be light. */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + token_removal = CIRCPAD_TOKEN_REMOVAL_NONE; + + /* Instead, to control the volume of padding (we just want to send a single + * padding cell) we will use a static state length. We just want one token, + * since we want to make the following pattern: + * [PADDING_NEGOTIATE] -> [DROP] -> PADDING_NEGOTIATED -> DROP */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + length_dist.type = CIRCPAD_DIST_UNIFORM; + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + length_dist.param1 = 1; + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + length_dist.param2 = 2; // rand(1,2) is always 1 + + /* Histogram is: (0 msecs, 1 msec, infinity). We want this to be fast so + * that the outgoing DROP cell is sent immediately after the + * PADDING_NEGOTIATED. */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram_len = 2; + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram_edges[0] = 0; + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram_edges[1] = 1000; + + /* We want a 100% probability of choosing an inter-packet delay of + * between 0 and 1ms. Since we don't use token removal, + * the number of tokens does not matter. (And also, state_length + * governs how many packets we send). */ + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram[0] = 1; + relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP]. + histogram_total_tokens = 1; + + /* Register the machine */ + relay_machine->machine_num = smartlist_len(machines_sl); + circpad_register_padding_machine(relay_machine, machines_sl); + + log_info(LD_CIRC, + "Registered relay rendezvous circuit hiding padding machine (%u)", + relay_machine->machine_num); +} diff --git a/src/core/or/circuitpadding_machines.h b/src/core/or/circuitpadding_machines.h new file mode 100644 index 0000000000..3c9798d42d --- /dev/null +++ b/src/core/or/circuitpadding_machines.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2018 The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitpadding_machines.h + * \brief Header file for circuitpadding_machines.c. + **/ + +#ifndef TOR_CIRCUITPADDING_MACHINES_H +#define TOR_CIRCUITPADDING_MACHINES_H + +void circpad_machine_relay_hide_intro_circuits(smartlist_t *machines_sl); +void circpad_machine_client_hide_intro_circuits(smartlist_t *machines_sl); +void circpad_machine_relay_hide_rend_circuits(smartlist_t *machines_sl); +void circpad_machine_client_hide_rend_circuits(smartlist_t *machines_sl); + +#ifdef CIRCUITPADDING_MACHINES_PRIVATE + +/** State of the padding machines that actually sends padding */ +#define CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP CIRCPAD_STATE_BURST + +/** Constants defining the amount of padding that a machine will send to hide + * HS circuits. The actual value is sampled uniformly random between the + * min/max values. + */ + +/** Minimum number of relay-side padding cells to be sent by this machine */ +#define INTRO_MACHINE_MINIMUM_PADDING 7 +/** Maximum number of relay-side padding cells to be sent by this machine. + * The actual value will be sampled between the min and max.*/ +#define INTRO_MACHINE_MAXIMUM_PADDING 10 + +#endif /* defined(CIRCUITPADDING_MACHINES_PRIVATE) */ + +#endif /* !defined(TOR_CIRCUITPADDING_MACHINES_H) */ diff --git a/src/core/or/circuitstats.c b/src/core/or/circuitstats.c index c6ea2fff97..03eea1d779 100644 --- a/src/core/or/circuitstats.c +++ b/src/core/or/circuitstats.c @@ -30,7 +30,7 @@ #include "core/or/circuitstats.h" #include "app/config/config.h" #include "app/config/confparse.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "lib/crypt_ops/crypto_rand.h" #include "core/mainloop/mainloop.h" #include "feature/nodelist/networkstatus.h" @@ -44,6 +44,7 @@ #include "lib/time/tvdiff.h" #include "lib/encoding/confline.h" #include "feature/dirauth/authmode.h" +#include "feature/relay/relay_periodic.h" #include "core/or/crypt_path_st.h" #include "core/or/origin_circuit_st.h" @@ -1420,6 +1421,7 @@ void circuit_build_times_network_is_live(circuit_build_times_t *cbt) { time_t now = approx_time(); + // XXXX this should use pubsub if (cbt->liveness.nonlive_timeouts > 0) { time_t time_since_live = now - cbt->liveness.network_last_live; log_notice(LD_CIRC, diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c index fd782c0cd1..18b419e99d 100644 --- a/src/core/or/circuituse.c +++ b/src/core/or/circuituse.c @@ -42,7 +42,7 @@ #include "feature/client/bridges.h" #include "feature/client/circpathbias.h" #include "feature/client/entrynodes.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dircommon/directory.h" #include "feature/hs/hs_circuit.h" #include "feature/hs/hs_client.h" @@ -70,7 +70,7 @@ #include "core/or/origin_circuit_st.h" #include "core/or/socks_request_st.h" -static void circuit_expire_old_circuits_clientside(void); +STATIC void circuit_expire_old_circuits_clientside(void); static void circuit_increment_failure_count(void); /** Check whether the hidden service destination of the stream at @@ -178,7 +178,6 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, purpose == CIRCUIT_PURPOSE_S_HSDIR_POST || purpose == CIRCUIT_PURPOSE_C_HSDIR_GET) { tor_addr_t addr; - const int family = tor_addr_parse(&addr, conn->socks_request->address); if (!exitnode && !build_state->onehop_tunnel) { log_debug(LD_CIRC,"Not considering circuit with unknown router."); return 0; /* this circuit is screwed and doesn't know it yet, @@ -199,6 +198,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, return 0; /* this is a circuit to somewhere else */ if (tor_digest_is_zero(digest)) { /* we don't know the digest; have to compare addr:port */ + const int family = tor_addr_parse(&addr, + conn->socks_request->address); if (family < 0 || !tor_addr_eq(&build_state->chosen_exit->addr, &addr) || build_state->chosen_exit->port != conn->socks_request->port) @@ -211,12 +212,14 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, return 0; } } - if (origin_circ->prepend_policy && family != -1) { - int r = compare_tor_addr_to_addr_policy(&addr, - conn->socks_request->port, - origin_circ->prepend_policy); - if (r == ADDR_POLICY_REJECTED) - return 0; + if (origin_circ->prepend_policy) { + if (tor_addr_parse(&addr, conn->socks_request->address) != -1) { + int r = compare_tor_addr_to_addr_policy(&addr, + conn->socks_request->port, + origin_circ->prepend_policy); + if (r == ADDR_POLICY_REJECTED) + return 0; + } } if (exitnode && !connection_ap_can_use_exit(conn, exitnode)) { /* can't exit from this router */ @@ -1471,7 +1474,7 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn) /** Find each circuit that has been unused for too long, or dirty * for too long and has no streams on it: mark it for close. */ -static void +STATIC void circuit_expire_old_circuits_clientside(void) { struct timeval cutoff, now; @@ -1511,6 +1514,7 @@ circuit_expire_old_circuits_clientside(void) circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT || circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || circ->purpose == CIRCUIT_PURPOSE_TESTING || + circ->purpose == CIRCUIT_PURPOSE_C_CIRCUIT_PADDING || (circ->purpose >= CIRCUIT_PURPOSE_C_INTRODUCING && circ->purpose <= CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) || circ->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) { @@ -3078,6 +3082,12 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose) circ->purpose, circuit_purpose_to_string(new_purpose), new_purpose); + + /* Take specific actions if we are repurposing a hidden service circuit. */ + if (circuit_purpose_is_hidden_service(circ->purpose) && + !circuit_purpose_is_hidden_service(new_purpose)) { + hs_circ_cleanup(circ); + } } old_purpose = circ->purpose; @@ -3121,7 +3131,9 @@ circuit_sent_valid_data(origin_circuit_t *circ, uint16_t relay_body_len) { if (!circ) return; - tor_assert_nonfatal(relay_body_len <= RELAY_PAYLOAD_SIZE); + tor_assertf_nonfatal(relay_body_len <= RELAY_PAYLOAD_SIZE, + "Wrong relay_body_len: %d (should be at most %d)", + relay_body_len, RELAY_PAYLOAD_SIZE); circ->n_delivered_written_circ_bw = tor_add_u32_nowrap(circ->n_delivered_written_circ_bw, relay_body_len); diff --git a/src/core/or/command.c b/src/core/or/command.c index 5fb6640c22..77e5447ce3 100644 --- a/src/core/or/command.c +++ b/src/core/or/command.c @@ -49,7 +49,7 @@ #include "core/or/dos.h" #include "core/or/onion.h" #include "core/or/relay.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/hibernate/hibernate.h" #include "feature/nodelist/describe.h" #include "feature/nodelist/nodelist.h" diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c index cc240bdc98..c08d2a9ff5 100644 --- a/src/core/or/connection_edge.c +++ b/src/core/or/connection_edge.c @@ -73,12 +73,13 @@ #include "core/or/policies.h" #include "core/or/reasons.h" #include "core/or/relay.h" +#include "core/or/sendme.h" #include "core/proto/proto_http.h" #include "core/proto/proto_socks.h" #include "feature/client/addressmap.h" #include "feature/client/circpathbias.h" #include "feature/client/dnsserv.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dircache/dirserv.h" #include "feature/dircommon/directory.h" #include "feature/hibernate/hibernate.h" @@ -767,7 +768,7 @@ connection_edge_flushed_some(edge_connection_t *conn) /* falls through. */ case EXIT_CONN_STATE_OPEN: - connection_edge_consider_sending_sendme(conn); + sendme_connection_edge_consider_sending(conn); break; } return 0; @@ -791,7 +792,7 @@ connection_edge_finished_flushing(edge_connection_t *conn) switch (conn->base_.state) { case AP_CONN_STATE_OPEN: case EXIT_CONN_STATE_OPEN: - connection_edge_consider_sending_sendme(conn); + sendme_connection_edge_consider_sending(conn); return 0; case AP_CONN_STATE_SOCKS_WAIT: case AP_CONN_STATE_NATD_WAIT: @@ -2810,6 +2811,31 @@ connection_ap_process_natd(entry_connection_t *conn) return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); } +static const char HTTP_CONNECT_IS_NOT_AN_HTTP_PROXY_MSG[] = + "HTTP/1.0 405 Method Not Allowed\r\n" + "Content-Type: text/html; charset=iso-8859-1\r\n\r\n" + "\n" + "\n" + "This is an HTTP CONNECT tunnel, not a full HTTP Proxy\n" + "\n" + "\n" + "

This is an HTTP CONNECT tunnel, not an HTTP proxy.

\n" + "

\n" + "It appears you have configured your web browser to use this Tor port as\n" + "an HTTP proxy.\n" + "

\n" + "This is not correct: This port is configured as a CONNECT tunnel, not\n" + "an HTTP proxy. Please configure your client accordingly. You can also\n" + "use HTTPS; then the client should automatically use HTTP CONNECT." + "

\n" + "

\n" + "See " + "https://www.torproject.org/documentation.html for more " + "information.\n" + "

\n" + "\n" + "\n"; + /** Called on an HTTP CONNECT entry connection when some bytes have arrived, * but we have not yet received a full HTTP CONNECT request. Try to parse an * HTTP CONNECT request from the connection's inbuf. On success, set up the @@ -2850,7 +2876,7 @@ connection_ap_process_http_connect(entry_connection_t *conn) tor_assert(command); tor_assert(addrport); if (strcasecmp(command, "connect")) { - errmsg = "HTTP/1.0 405 Method Not Allowed\r\n\r\n"; + errmsg = HTTP_CONNECT_IS_NOT_AN_HTTP_PROXY_MSG; goto err; } @@ -4539,6 +4565,25 @@ circuit_clear_isolation(origin_circuit_t *circ) circ->socks_username_len = circ->socks_password_len = 0; } +/** Send an END and mark for close the given edge connection conn using the + * given reason that has to be a stream reason. + * + * Note: We don't unattached the AP connection (if applicable) because we + * don't want to flush the remaining data. This function aims at ending + * everything quickly regardless of the connection state. + * + * This function can't fail and does nothing if conn is NULL. */ +void +connection_edge_end_close(edge_connection_t *conn, uint8_t reason) +{ + if (!conn) { + return; + } + + connection_edge_end(conn, reason); + connection_mark_for_close(TO_CONN(conn)); +} + /** Free all storage held in module-scoped variables for connection_edge.c */ void connection_edge_free_all(void) diff --git a/src/core/or/connection_edge.h b/src/core/or/connection_edge.h index 68d8b19a11..e82b6bd765 100644 --- a/src/core/or/connection_edge.h +++ b/src/core/or/connection_edge.h @@ -80,6 +80,7 @@ int connection_edge_process_inbuf(edge_connection_t *conn, int connection_edge_destroy(circid_t circ_id, edge_connection_t *conn); int connection_edge_end(edge_connection_t *conn, uint8_t reason); int connection_edge_end_errno(edge_connection_t *conn); +void connection_edge_end_close(edge_connection_t *conn, uint8_t reason); int connection_edge_flushed_some(edge_connection_t *conn); int connection_edge_finished_flushing(edge_connection_t *conn); int connection_edge_finished_connecting(edge_connection_t *conn); diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c index debf482cb3..830e09fd54 100644 --- a/src/core/or/connection_or.c +++ b/src/core/or/connection_or.c @@ -39,7 +39,7 @@ #include "app/config/config.h" #include "core/mainloop/connection.h" #include "core/or/connection_or.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" #include "feature/dirauth/reachability.h" @@ -2308,6 +2308,8 @@ connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn) cell_pack(&networkcell, cell, conn->wide_circ_ids); + /* We need to count padding cells from this non-packed code path + * since they are sent via chan->write_cell() (which is not packed) */ rep_hist_padding_count_write(PADDING_TYPE_TOTAL); if (cell->command == CELL_PADDING) rep_hist_padding_count_write(PADDING_TYPE_CELL); @@ -2318,7 +2320,7 @@ connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn) if (conn->chan) { channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); - if (TLS_CHAN_TO_BASE(conn->chan)->currently_padding) { + if (TLS_CHAN_TO_BASE(conn->chan)->padding_enabled) { rep_hist_padding_count_write(PADDING_TYPE_ENABLED_TOTAL); if (cell->command == CELL_PADDING) rep_hist_padding_count_write(PADDING_TYPE_ENABLED_CELL); @@ -2348,6 +2350,7 @@ connection_or_write_var_cell_to_buf,(const var_cell_t *cell, if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) or_handshake_state_record_var_cell(conn, conn->handshake_state, cell, 0); + rep_hist_padding_count_write(PADDING_TYPE_TOTAL); /* Touch the channel's active timestamp if there is one */ if (conn->chan) channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); diff --git a/src/core/or/connection_st.h b/src/core/or/connection_st.h index d1430eda14..1c42a56d6b 100644 --- a/src/core/or/connection_st.h +++ b/src/core/or/connection_st.h @@ -146,4 +146,4 @@ struct connection_t { * directory connection. */ #define DIR_CONN_IS_SERVER(conn) ((conn)->purpose == DIR_PURPOSE_SERVER) -#endif +#endif /* !defined(CONNECTION_ST_H) */ diff --git a/src/core/or/cpath_build_state_st.h b/src/core/or/cpath_build_state_st.h index dbe596d851..4572a10430 100644 --- a/src/core/or/cpath_build_state_st.h +++ b/src/core/or/cpath_build_state_st.h @@ -34,5 +34,5 @@ struct cpath_build_state_t { time_t expiry_time; }; -#endif +#endif /* !defined(CIRCUIT_BUILD_STATE_ST_ST_H) */ diff --git a/src/core/or/crypt_path.c b/src/core/or/crypt_path.c new file mode 100644 index 0000000000..6d5245510f --- /dev/null +++ b/src/core/or/crypt_path.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypt_path.c + * + * \brief Functions dealing with layered circuit encryption. This file aims to + * provide an API around the crypt_path_t structure which holds crypto + * information about a specific hop of a circuit. + * + * TODO: We should eventually move all functions dealing and manipulating + * crypt_path_t to this file, so that eventually we encapsulate more and more + * of crypt_path_t. Here are some more functions that can be moved here with + * some more effort: + * + * - circuit_list_path_impl() + * - Functions dealing with cpaths in HSv2 create_rend_cpath() and + * create_rend_cpath_legacy() + * - The cpath related parts of rend_service_receive_introduction() and + * rend_client_send_introduction(). + **/ + +#define CRYPT_PATH_PRIVATE + +#include "core/or/or.h" +#include "core/or/crypt_path.h" + +#include "core/crypto/relay_crypto.h" +#include "core/crypto/onion_crypto.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" + +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_util.h" + +#include "core/or/crypt_path_st.h" +#include "core/or/cell_st.h" + +/** Add new_hop to the end of the doubly-linked-list head_ptr. + * This function is used to extend cpath by another hop. + */ +void +cpath_extend_linked_list(crypt_path_t **head_ptr, crypt_path_t *new_hop) +{ + if (*head_ptr) { + new_hop->next = (*head_ptr); + new_hop->prev = (*head_ptr)->prev; + (*head_ptr)->prev->next = new_hop; + (*head_ptr)->prev = new_hop; + } else { + *head_ptr = new_hop; + new_hop->prev = new_hop->next = new_hop; + } +} + +/** Create a new hop, annotate it with information about its + * corresponding router choice, and append it to the + * end of the cpath head_ptr. */ +int +cpath_append_hop(crypt_path_t **head_ptr, extend_info_t *choice) +{ + crypt_path_t *hop = tor_malloc_zero(sizeof(crypt_path_t)); + + /* link hop into the cpath, at the end. */ + cpath_extend_linked_list(head_ptr, hop); + + hop->magic = CRYPT_PATH_MAGIC; + hop->state = CPATH_STATE_CLOSED; + + hop->extend_info = extend_info_dup(choice); + + hop->package_window = circuit_initial_package_window(); + hop->deliver_window = CIRCWINDOW_START; + + return 0; +} + +/** Verify that cpath cp has all of its invariants + * correct. Trigger an assert if anything is invalid. + */ +void +cpath_assert_ok(const crypt_path_t *cp) +{ + const crypt_path_t *start = cp; + + do { + cpath_assert_layer_ok(cp); + /* layers must be in sequence of: "open* awaiting? closed*" */ + if (cp != start) { + if (cp->state == CPATH_STATE_AWAITING_KEYS) { + tor_assert(cp->prev->state == CPATH_STATE_OPEN); + } else if (cp->state == CPATH_STATE_OPEN) { + tor_assert(cp->prev->state == CPATH_STATE_OPEN); + } + } + cp = cp->next; + tor_assert(cp); + } while (cp != start); +} + +/** Verify that cpath layer cp has all of its invariants + * correct. Trigger an assert if anything is invalid. + */ +void +cpath_assert_layer_ok(const crypt_path_t *cp) +{ +// tor_assert(cp->addr); /* these are zero for rendezvous extra-hops */ +// tor_assert(cp->port); + tor_assert(cp); + tor_assert(cp->magic == CRYPT_PATH_MAGIC); + switch (cp->state) + { + case CPATH_STATE_OPEN: + relay_crypto_assert_ok(&cp->pvt_crypto); + /* fall through */ + case CPATH_STATE_CLOSED: + /*XXXX Assert that there's no handshake_state either. */ + tor_assert(!cp->rend_dh_handshake_state); + break; + case CPATH_STATE_AWAITING_KEYS: + /* tor_assert(cp->dh_handshake_state); */ + break; + default: + log_fn(LOG_ERR, LD_BUG, "Unexpected state %d", cp->state); + tor_assert(0); + } + tor_assert(cp->package_window >= 0); + tor_assert(cp->deliver_window >= 0); +} + +/** Initialize cpath-\>{f|b}_{crypto|digest} from the key material in key_data. + * + * If is_hs_v3 is set, this cpath will be used for next gen hidden + * service circuits and key_data must be at least + * HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN bytes in length. + * + * If is_hs_v3 is not set, key_data must contain CPATH_KEY_MATERIAL_LEN + * bytes, which are used as follows: + * - 20 to initialize f_digest + * - 20 to initialize b_digest + * - 16 to key f_crypto + * - 16 to key b_crypto + * + * (If 'reverse' is true, then f_XX and b_XX are swapped.) + * + * Return 0 if init was successful, else -1 if it failed. + */ +int +cpath_init_circuit_crypto(crypt_path_t *cpath, + const char *key_data, size_t key_data_len, + int reverse, int is_hs_v3) +{ + + tor_assert(cpath); + return relay_crypto_init(&cpath->pvt_crypto, key_data, key_data_len, + reverse, is_hs_v3); +} + +/** Deallocate space associated with the cpath node victim. */ +void +cpath_free(crypt_path_t *victim) +{ + if (!victim) + return; + + relay_crypto_clear(&victim->pvt_crypto); + onion_handshake_state_release(&victim->handshake_state); + crypto_dh_free(victim->rend_dh_handshake_state); + extend_info_free(victim->extend_info); + + memwipe(victim, 0xBB, sizeof(crypt_path_t)); /* poison memory */ + tor_free(victim); +} + +/********************** cpath crypto API *******************************/ + +/** Encrypt or decrypt payload using the crypto of cpath. Actual + * operation decided by is_decrypt. */ +void +cpath_crypt_cell(const crypt_path_t *cpath, uint8_t *payload, bool is_decrypt) +{ + if (is_decrypt) { + relay_crypt_one_payload(cpath->pvt_crypto.b_crypto, payload); + } else { + relay_crypt_one_payload(cpath->pvt_crypto.f_crypto, payload); + } +} + +/** Getter for the incoming digest of cpath. */ +struct crypto_digest_t * +cpath_get_incoming_digest(const crypt_path_t *cpath) +{ + return cpath->pvt_crypto.b_digest; +} + +/** Set the right integrity digest on the outgoing cell based on the + * cell payload and update the forward digest of cpath. */ +void +cpath_set_cell_forward_digest(crypt_path_t *cpath, cell_t *cell) +{ + relay_set_digest(cpath->pvt_crypto.f_digest, cell); +} + +/************ cpath sendme API ***************************/ + +/** Return the sendme_digest of this cpath. */ +uint8_t * +cpath_get_sendme_digest(crypt_path_t *cpath) +{ + return relay_crypto_get_sendme_digest(&cpath->pvt_crypto); +} + +/** Record the cell digest, indicated by is_foward_digest or not, as the + * SENDME cell digest. */ +void +cpath_sendme_record_cell_digest(crypt_path_t *cpath, bool is_foward_digest) +{ + tor_assert(cpath); + relay_crypto_record_sendme_digest(&cpath->pvt_crypto, is_foward_digest); +} + +/************ other cpath functions ***************************/ + +/** Return the first non-open hop in cpath, or return NULL if all + * hops are open. */ +crypt_path_t * +cpath_get_next_non_open_hop(crypt_path_t *cpath) +{ + crypt_path_t *hop = cpath; + do { + if (hop->state != CPATH_STATE_OPEN) + return hop; + hop = hop->next; + } while (hop != cpath); + return NULL; +} + +#ifdef TOR_UNIT_TESTS + +/** Unittest helper function: Count number of hops in cpath linked list. */ +unsigned int +cpath_get_n_hops(crypt_path_t **head_ptr) +{ + unsigned int n_hops = 0; + crypt_path_t *tmp; + + if (!*head_ptr) { + return 0; + } + + tmp = *head_ptr; + do { + n_hops++; + tmp = tmp->next; + } while (tmp != *head_ptr); + + return n_hops; +} + +#endif /* defined(TOR_UNIT_TESTS) */ + diff --git a/src/core/or/crypt_path.h b/src/core/or/crypt_path.h new file mode 100644 index 0000000000..7a95fec2b4 --- /dev/null +++ b/src/core/or/crypt_path.h @@ -0,0 +1,46 @@ +/** + * \file crypt_path.h + * \brief Header file for crypt_path.c. + **/ + +#ifndef CRYPT_PATH_H +#define CRYPT_PATH_H + +void cpath_assert_layer_ok(const crypt_path_t *cp); + +void cpath_assert_ok(const crypt_path_t *cp); + +int cpath_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); + +int cpath_init_circuit_crypto(crypt_path_t *cpath, + const char *key_data, size_t key_data_len, + int reverse, int is_hs_v3); + +void +cpath_free(crypt_path_t *victim); + +void cpath_extend_linked_list(crypt_path_t **head_ptr, crypt_path_t *new_hop); + +void +cpath_crypt_cell(const crypt_path_t *cpath, uint8_t *payload, bool is_decrypt); + +struct crypto_digest_t * +cpath_get_incoming_digest(const crypt_path_t *cpath); + +void cpath_sendme_record_cell_digest(crypt_path_t *cpath, + bool is_foward_digest); + +void +cpath_set_cell_forward_digest(crypt_path_t *cpath, cell_t *cell); + +crypt_path_t *cpath_get_next_non_open_hop(crypt_path_t *cpath); + +void cpath_sendme_circuit_record_inbound_cell(crypt_path_t *cpath); + +uint8_t *cpath_get_sendme_digest(crypt_path_t *cpath); + +#if defined(TOR_UNIT_TESTS) +unsigned int cpath_get_n_hops(crypt_path_t **head_ptr); +#endif /* defined(TOR_UNIT_TESTS) */ + +#endif /* !defined(CRYPT_PATH_H) */ diff --git a/src/core/or/crypt_path_reference_st.h b/src/core/or/crypt_path_reference_st.h index 3d79f26c1c..1827022b4e 100644 --- a/src/core/or/crypt_path_reference_st.h +++ b/src/core/or/crypt_path_reference_st.h @@ -19,5 +19,5 @@ struct crypt_path_reference_t { crypt_path_t *cpath; }; -#endif +#endif /* !defined(CRYPT_PATH_REFERENCE_ST_H) */ diff --git a/src/core/or/crypt_path_st.h b/src/core/or/crypt_path_st.h index 429480f8ab..249ac6aaa3 100644 --- a/src/core/or/crypt_path_st.h +++ b/src/core/or/crypt_path_st.h @@ -24,15 +24,24 @@ struct onion_handshake_state_t { } u; }; +/** Macro to encapsulate private members of a struct. + * + * Renames 'x' to 'x_crypt_path_private_field'. + */ +#define CRYPT_PATH_PRIV_FIELD(x) x ## _crypt_path_private_field + +#ifdef CRYPT_PATH_PRIVATE + +/* Helper macro to access private members of a struct. */ +#define pvt_crypto CRYPT_PATH_PRIV_FIELD(crypto) + +#endif /* defined(CRYPT_PATH_PRIVATE) */ + /** Holds accounting information for a single step in the layered encryption * performed by a circuit. Used only at the client edge of a circuit. */ struct crypt_path_t { uint32_t magic; - /** Cryptographic state used for encrypting and authenticating relay - * cells to and from this hop. */ - relay_crypto_t crypto; - /** Current state of the handshake as performed with the OR at this * step. */ onion_handshake_state_t handshake_state; @@ -65,6 +74,12 @@ struct crypt_path_t { * at this step? */ int deliver_window; /**< How many cells are we willing to deliver originating * at this step? */ + + /*********************** Private members ****************************/ + + /** Private member: Cryptographic state used for encrypting and + * authenticating relay cells to and from this hop. */ + relay_crypto_t CRYPT_PATH_PRIV_FIELD(crypto); }; -#endif +#endif /* !defined(CRYPT_PATH_ST_H) */ diff --git a/src/core/or/destroy_cell_queue_st.h b/src/core/or/destroy_cell_queue_st.h index 56630670ba..e917afc700 100644 --- a/src/core/or/destroy_cell_queue_st.h +++ b/src/core/or/destroy_cell_queue_st.h @@ -23,5 +23,5 @@ struct destroy_cell_queue_t { int n; /**< The number of cells in the queue. */ }; -#endif +#endif /* !defined(DESTROY_CELL_QUEUE_ST_H) */ diff --git a/src/core/or/dos.h b/src/core/or/dos.h index 95448d0530..b5154a7cd2 100644 --- a/src/core/or/dos.h +++ b/src/core/or/dos.h @@ -134,7 +134,7 @@ MOCK_DECL(STATIC unsigned int, get_param_cc_enabled, MOCK_DECL(STATIC unsigned int, get_param_conn_enabled, (const networkstatus_t *ns)); -#endif /* TOR_DOS_PRIVATE */ +#endif /* defined(DOS_PRIVATE) */ -#endif /* TOR_DOS_H */ +#endif /* !defined(TOR_DOS_H) */ diff --git a/src/core/or/edge_connection_st.h b/src/core/or/edge_connection_st.h index 1665b8589f..8922a3a9cf 100644 --- a/src/core/or/edge_connection_st.h +++ b/src/core/or/edge_connection_st.h @@ -73,5 +73,5 @@ struct edge_connection_t { uint64_t dirreq_id; }; -#endif +#endif /* !defined(EDGE_CONNECTION_ST_H) */ diff --git a/src/core/or/entry_connection_st.h b/src/core/or/entry_connection_st.h index 45621fadbf..e65c545d17 100644 --- a/src/core/or/entry_connection_st.h +++ b/src/core/or/entry_connection_st.h @@ -96,5 +96,5 @@ struct entry_connection_t { /** Cast a entry_connection_t subtype pointer to a edge_connection_t **/ #define ENTRY_TO_EDGE_CONN(c) (&(((c))->edge_)) -#endif +#endif /* !defined(ENTRY_CONNECTION_ST_H) */ diff --git a/src/core/or/entry_port_cfg_st.h b/src/core/or/entry_port_cfg_st.h index 87dfb331e5..b84838d44f 100644 --- a/src/core/or/entry_port_cfg_st.h +++ b/src/core/or/entry_port_cfg_st.h @@ -50,5 +50,5 @@ struct entry_port_cfg_t { }; -#endif +#endif /* !defined(ENTRY_PORT_CFG_ST_H) */ diff --git a/src/core/or/extend_info_st.h b/src/core/or/extend_info_st.h index bc7a77b1b2..7704ff16b5 100644 --- a/src/core/or/extend_info_st.h +++ b/src/core/or/extend_info_st.h @@ -27,4 +27,4 @@ struct extend_info_t { curve25519_public_key_t curve25519_onion_key; }; -#endif +#endif /* !defined(EXTEND_INFO_ST_H) */ diff --git a/src/core/or/half_edge_st.h b/src/core/or/half_edge_st.h index d4617be108..1fe47ad3f1 100644 --- a/src/core/or/half_edge_st.h +++ b/src/core/or/half_edge_st.h @@ -30,5 +30,5 @@ typedef struct half_edge_t { int connected_pending : 1; } half_edge_t; -#endif +#endif /* !defined(HALF_EDGE_ST_H) */ diff --git a/src/core/or/listener_connection_st.h b/src/core/or/listener_connection_st.h index 8989a39dc8..1250d9c9b4 100644 --- a/src/core/or/listener_connection_st.h +++ b/src/core/or/listener_connection_st.h @@ -21,5 +21,5 @@ struct listener_connection_t { }; -#endif +#endif /* !defined(LISTENER_CONNECTION_ST_H) */ diff --git a/src/core/or/ocirc_event.h b/src/core/or/ocirc_event.h index 0b125c2898..59ec9e27cb 100644 --- a/src/core/or/ocirc_event.h +++ b/src/core/or/ocirc_event.h @@ -86,4 +86,4 @@ void ocirc_event_subscribe(ocirc_event_rcvr_t fn); void ocirc_event_publish(const ocirc_event_msg_t *msg); #endif -#endif /* defined(TOR_OCIRC_EVENT_STATE_H) */ +#endif /* !defined(TOR_OCIRC_EVENT_H) */ diff --git a/src/core/or/ocirc_event_sys.h b/src/core/or/ocirc_event_sys.h index 9d4bfe5333..61180496da 100644 --- a/src/core/or/ocirc_event_sys.h +++ b/src/core/or/ocirc_event_sys.h @@ -10,4 +10,4 @@ extern const struct subsys_fns_t sys_ocirc_event; -#endif /* defined(TOR_OCIRC_EVENT_H) */ +#endif /* !defined(TOR_OCIRC_EVENT_SYS_H) */ diff --git a/src/core/or/or.h b/src/core/or/or.h index db6d089582..ab258629a6 100644 --- a/src/core/or/or.h +++ b/src/core/or/or.h @@ -841,8 +841,8 @@ typedef struct protover_summary_flags_t { unsigned int supports_v3_rendezvous_point: 1; /** True iff this router has a protocol list that allows clients to - * negotiate link-level padding. Requires Padding>=1. */ - unsigned int supports_padding : 1; + * negotiate hs circuit setup padding. Requires Padding>=2. */ + unsigned int supports_hs_setup_padding : 1; } protover_summary_flags_t; typedef struct routerinfo_t routerinfo_t; diff --git a/src/core/or/or_circuit_st.h b/src/core/or/or_circuit_st.h index 6b6feb9d89..6789668224 100644 --- a/src/core/or/or_circuit_st.h +++ b/src/core/or/or_circuit_st.h @@ -33,11 +33,6 @@ struct or_circuit_t { cell_queue_t p_chan_cells; /** The channel that is previous in this circuit. */ channel_t *p_chan; - /** - * Circuit mux associated with p_chan to which this circuit is attached; - * NULL if we have no p_chan. - */ - circuitmux_t *p_mux; /** Linked list of Exit streams associated with this circuit. */ edge_connection_t *n_streams; /** Linked list of Exit streams associated with this circuit that are @@ -76,5 +71,5 @@ struct or_circuit_t { uint64_t total_cell_waiting_time; }; -#endif +#endif /* !defined(OR_CIRCUIT_ST_H) */ diff --git a/src/core/or/or_connection_st.h b/src/core/or/or_connection_st.h index a5ce844bff..051fcd00d3 100644 --- a/src/core/or/or_connection_st.h +++ b/src/core/or/or_connection_st.h @@ -91,4 +91,4 @@ struct or_connection_t { uint64_t bytes_xmitted, bytes_xmitted_by_tls; }; -#endif +#endif /* !defined(OR_CONNECTION_ST_H) */ diff --git a/src/core/or/or_handshake_certs_st.h b/src/core/or/or_handshake_certs_st.h index a93b7104aa..9deb6d6d59 100644 --- a/src/core/or/or_handshake_certs_st.h +++ b/src/core/or/or_handshake_certs_st.h @@ -37,4 +37,4 @@ struct or_handshake_certs_t { size_t ed_rsa_crosscert_len; }; -#endif +#endif /* !defined(OR_HANDSHAKE_CERTS_ST) */ diff --git a/src/core/or/or_handshake_state_st.h b/src/core/or/or_handshake_state_st.h index 09a8a34179..472ce8a302 100644 --- a/src/core/or/or_handshake_state_st.h +++ b/src/core/or/or_handshake_state_st.h @@ -74,5 +74,5 @@ struct or_handshake_state_t { or_handshake_certs_t *certs; }; -#endif +#endif /* !defined(OR_HANDSHAKE_STATE_ST) */ diff --git a/src/core/or/or_periodic.c b/src/core/or/or_periodic.c new file mode 100644 index 0000000000..fe28c99192 --- /dev/null +++ b/src/core/or/or_periodic.c @@ -0,0 +1,65 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file or_periodic.c + * @brief Periodic callbacks for the onion routing subsystem + **/ + +#include "orconfig.h" +#include "core/or/or.h" + +#include "core/mainloop/periodic.h" + +#include "core/or/channel.h" +#include "core/or/circuituse.h" +#include "core/or/or_periodic.h" + +#include "feature/relay/routermode.h" + +#define DECLARE_EVENT(name, roles, flags) \ + static periodic_event_item_t name ## _event = \ + PERIODIC_EVENT(name, \ + PERIODIC_EVENT_ROLE_##roles, \ + flags) + +#define FL(name) (PERIODIC_EVENT_FLAG_ ## name) + +#define CHANNEL_CHECK_INTERVAL (60*60) +static int +check_canonical_channels_callback(time_t now, const or_options_t *options) +{ + (void)now; + if (public_server_mode(options)) + channel_check_for_duplicates(); + + return CHANNEL_CHECK_INTERVAL; +} + +DECLARE_EVENT(check_canonical_channels, RELAY, FL(NEED_NET)); + +/** + * Periodic callback: as a server, see if we have any old unused circuits + * that should be expired */ +static int +expire_old_circuits_serverside_callback(time_t now, + const or_options_t *options) +{ + (void)options; + /* every 11 seconds, so not usually the same second as other such events */ + circuit_expire_old_circuits_serverside(now); + return 11; +} + +DECLARE_EVENT(expire_old_circuits_serverside, ROUTER, FL(NEED_NET)); + +void +or_register_periodic_events(void) +{ + // These are router-only events, but they're owned by the OR subsystem. */ + periodic_events_register(&check_canonical_channels_event); + periodic_events_register(&expire_old_circuits_serverside_event); +} diff --git a/src/core/or/or_periodic.h b/src/core/or/or_periodic.h new file mode 100644 index 0000000000..c2f47cf5ef --- /dev/null +++ b/src/core/or/or_periodic.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file or_periodic.h + * @brief Header for core/or/or_periodic.c + **/ + +#ifndef TOR_CORE_OR_OR_PERIODIC_H +#define TOR_CORE_OR_OR_PERIODIC_H + +void or_register_periodic_events(void); + +#endif /* !defined(TOR_CORE_OR_OR_PERIODIC_H) */ diff --git a/src/core/or/or_sys.c b/src/core/or/or_sys.c new file mode 100644 index 0000000000..6f8c81a4df --- /dev/null +++ b/src/core/or/or_sys.c @@ -0,0 +1,43 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file or_sys.c + * @brief Subsystem definitions for OR module. + **/ + +#include "orconfig.h" +#include "core/or/or.h" +#include "core/or/or_periodic.h" +#include "core/or/or_sys.h" +#include "core/or/policies.h" +#include "core/or/protover.h" +#include "core/or/versions.h" + +#include "lib/subsys/subsys.h" + +static int +subsys_or_initialize(void) +{ + or_register_periodic_events(); + return 0; +} + +static void +subsys_or_shutdown(void) +{ + protover_free_all(); + protover_summary_cache_free_all(); + policies_free_all(); +} + +const struct subsys_fns_t sys_or = { + .name = "or", + .supported = true, + .level = 20, + .initialize = subsys_or_initialize, + .shutdown = subsys_or_shutdown, +}; diff --git a/src/core/or/or_sys.h b/src/core/or/or_sys.h new file mode 100644 index 0000000000..c37ef01858 --- /dev/null +++ b/src/core/or/or_sys.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file or_sys.h + * @brief Header for core/or/or_sys.c + **/ + +#ifndef TOR_CORE_OR_OR_SYS_H +#define TOR_CORE_OR_OR_SYS_H + +extern const struct subsys_fns_t sys_or; + +#endif /* !defined(TOR_CORE_OR_OR_SYS_H) */ diff --git a/src/core/or/orconn_event.h b/src/core/or/orconn_event.h index 80289d53e6..d6635793db 100644 --- a/src/core/or/orconn_event.h +++ b/src/core/or/orconn_event.h @@ -117,4 +117,4 @@ void orconn_event_subscribe(orconn_event_rcvr_t); void orconn_event_publish(const orconn_event_msg_t *); #endif -#endif /* defined(TOR_ORCONN_EVENT_H) */ +#endif /* !defined(TOR_ORCONN_EVENT_H) */ diff --git a/src/core/or/orconn_event_sys.h b/src/core/or/orconn_event_sys.h index bfb0a3ac4a..9703b2e3d1 100644 --- a/src/core/or/orconn_event_sys.h +++ b/src/core/or/orconn_event_sys.h @@ -9,4 +9,4 @@ extern const struct subsys_fns_t sys_orconn_event; -#endif /* defined(TOR_ORCONN_SYS_H) */ +#endif /* !defined(TOR_ORCONN_EVENT_SYS_H) */ diff --git a/src/core/or/origin_circuit_st.h b/src/core/or/origin_circuit_st.h index daa5f41dad..01bbc84ae2 100644 --- a/src/core/or/origin_circuit_st.h +++ b/src/core/or/origin_circuit_st.h @@ -295,4 +295,4 @@ struct origin_circuit_t { }; -#endif +#endif /* !defined(ORIGIN_CIRCUIT_ST_H) */ diff --git a/src/core/or/policies.c b/src/core/or/policies.c index a6d66d36de..83d9a53fc0 100644 --- a/src/core/or/policies.c +++ b/src/core/or/policies.c @@ -31,6 +31,7 @@ #include "ht.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/encoding/confline.h" +#include "trunnel/ed25519_cert.h" #include "core/or/addr_policy_st.h" #include "feature/dirclient/dir_server_st.h" @@ -1015,6 +1016,83 @@ fascist_firewall_choose_address_rs(const routerstatus_t *rs, } } +/** Like fascist_firewall_choose_address_base(), but takes in a smartlist + * lspecs consisting of one or more link specifiers. We assume + * fw_connection is FIREWALL_OR_CONNECTION as link specifiers cannot + * contain DirPorts. + */ +void +fascist_firewall_choose_address_ls(const smartlist_t *lspecs, + int pref_only, tor_addr_port_t* ap) +{ + int have_v4 = 0, have_v6 = 0; + uint16_t port_v4 = 0, port_v6 = 0; + tor_addr_t addr_v4, addr_v6; + + tor_assert(ap); + + if (lspecs == NULL) { + log_warn(LD_BUG, "Unknown or missing link specifiers"); + return; + } + if (smartlist_len(lspecs) == 0) { + log_warn(LD_PROTOCOL, "Link specifiers are empty"); + return; + } + + tor_addr_make_null(&ap->addr, AF_UNSPEC); + ap->port = 0; + + tor_addr_make_null(&addr_v4, AF_INET); + tor_addr_make_null(&addr_v6, AF_INET6); + + SMARTLIST_FOREACH_BEGIN(lspecs, const link_specifier_t *, ls) { + switch (link_specifier_get_ls_type(ls)) { + case LS_IPV4: + /* Skip if we already seen a v4. */ + if (have_v4) continue; + tor_addr_from_ipv4h(&addr_v4, + link_specifier_get_un_ipv4_addr(ls)); + port_v4 = link_specifier_get_un_ipv4_port(ls); + have_v4 = 1; + break; + case LS_IPV6: + /* Skip if we already seen a v6, or deliberately skip it if we're not a + * direct connection. */ + if (have_v6) continue; + tor_addr_from_ipv6_bytes(&addr_v6, + (const char *) link_specifier_getconstarray_un_ipv6_addr(ls)); + port_v6 = link_specifier_get_un_ipv6_port(ls); + have_v6 = 1; + break; + default: + /* Ignore unknown. */ + break; + } + } SMARTLIST_FOREACH_END(ls); + + /* If we don't have IPv4 or IPv6 in link specifiers, log a bug and return. */ + if (!have_v4 && !have_v6) { + if (!have_v6) { + log_warn(LD_PROTOCOL, "None of our link specifiers have IPv4 or IPv6"); + } else { + log_warn(LD_PROTOCOL, "None of our link specifiers have IPv4"); + } + return; + } + + /* Here, don't check for DirPorts as link specifiers are only used for + * ORPorts. */ + const or_options_t *options = get_options(); + int pref_ipv6 = fascist_firewall_prefer_ipv6_orport(options); + /* Assume that the DirPorts are zero as link specifiers only use ORPorts. */ + fascist_firewall_choose_address_base(&addr_v4, port_v4, 0, + &addr_v6, port_v6, 0, + FIREWALL_OR_CONNECTION, + pref_only, pref_ipv6, + ap); +} + /** Like fascist_firewall_choose_address_base(), but takes node, and * looks up the node's IPv6 preference rather than taking an argument * for pref_ipv6. */ @@ -1164,6 +1242,15 @@ authdir_policy_badexit_address(uint32_t addr, uint16_t port) #define REJECT(arg) \ STMT_BEGIN *msg = tor_strdup(arg); goto err; STMT_END +/** Check or_options to determine whether or not we are using the + * default options for exit policy. Return true if so, false otherwise. */ +static int +policy_using_default_exit_options(const or_options_t *or_options) +{ + return (or_options->ExitPolicy == NULL && or_options->ExitRelay == -1 && + or_options->ReducedExitPolicy == 0 && or_options->IPv6Exit == 0); +} + /** Config helper: If there's any problem with the policy configuration * options in options, return -1 and set msg to a newly * allocated description of the error. Else return 0. */ @@ -1182,9 +1269,8 @@ validate_addr_policies(const or_options_t *options, char **msg) static int warned_about_nonexit = 0; - if (public_server_mode(options) && - !warned_about_nonexit && options->ExitPolicy == NULL && - options->ExitRelay == -1 && options->ReducedExitPolicy == 0) { + if (public_server_mode(options) && !warned_about_nonexit && + policy_using_default_exit_options(options)) { warned_about_nonexit = 1; log_notice(LD_CONFIG, "By default, Tor does not run as an exit relay. " "If you want to be an exit relay, " @@ -2141,9 +2227,9 @@ policies_parse_exit_policy_from_options(const or_options_t *or_options, int rv = 0; /* Short-circuit for non-exit relays, or for relays where we didn't specify - * ExitPolicy or ReducedExitPolicy and ExitRelay is auto. */ - if (or_options->ExitRelay == 0 || (or_options->ExitPolicy == NULL && - or_options->ExitRelay == -1 && or_options->ReducedExitPolicy == 0)) { + * ExitPolicy or ReducedExitPolicy or IPv6Exit and ExitRelay is auto. */ + if (or_options->ExitRelay == 0 || + policy_using_default_exit_options(or_options)) { append_exit_policy_string(result, "reject *4:*"); append_exit_policy_string(result, "reject *6:*"); return 0; diff --git a/src/core/or/policies.h b/src/core/or/policies.h index 324c1c2dd1..3c46363c04 100644 --- a/src/core/or/policies.h +++ b/src/core/or/policies.h @@ -92,6 +92,8 @@ int fascist_firewall_allows_dir_server(const dir_server_t *ds, void fascist_firewall_choose_address_rs(const routerstatus_t *rs, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t* ap); +void fascist_firewall_choose_address_ls(const smartlist_t *lspecs, + int pref_only, tor_addr_port_t* ap); void fascist_firewall_choose_address_node(const node_t *node, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t* ap); diff --git a/src/core/or/port_cfg_st.h b/src/core/or/port_cfg_st.h index b67091ce32..e9e82bb1de 100644 --- a/src/core/or/port_cfg_st.h +++ b/src/core/or/port_cfg_st.h @@ -31,5 +31,5 @@ struct port_cfg_t { char unix_addr[FLEXIBLE_ARRAY_MEMBER]; }; -#endif +#endif /* !defined(PORT_CFG_ST_H) */ diff --git a/src/core/or/protover.c b/src/core/or/protover.c index 53709ad002..ccd33fabf7 100644 --- a/src/core/or/protover.c +++ b/src/core/or/protover.c @@ -53,7 +53,8 @@ static const struct { { PRT_DESC, "Desc" }, { PRT_MICRODESC, "Microdesc"}, { PRT_PADDING, "Padding"}, - { PRT_CONS, "Cons" } + { PRT_CONS, "Cons" }, + { PRT_FLOWCTRL, "FlowCtrl"}, }; #define N_PROTOCOL_NAMES ARRAY_LENGTH(PROTOCOL_NAMES) @@ -401,7 +402,8 @@ protover_get_supported_protocols(void) #endif "Microdesc=1-2 " "Relay=1-2 " - "Padding=1"; + "Padding=2 " + "FlowCtrl=1"; } /** The protocols from protover_get_supported_protocols(), as parsed into a @@ -820,6 +822,8 @@ protover_all_supported(const char *s, char **missing_out) * ones and, if so, add them to unsupported->ranges. */ if (versions->low != 0 && versions->high != 0) { smartlist_add(unsupported->ranges, versions); + } else { + tor_free(versions); } /* Finally, if we had something unsupported, add it to the list of * missing_some things and mark that there was something missing. */ @@ -828,7 +832,6 @@ protover_all_supported(const char *s, char **missing_out) all_supported = 0; } else { proto_entry_free(unsupported); - tor_free(versions); } } SMARTLIST_FOREACH_END(range); diff --git a/src/core/or/protover.h b/src/core/or/protover.h index 567b94a168..af45a31aeb 100644 --- a/src/core/or/protover.h +++ b/src/core/or/protover.h @@ -28,6 +28,8 @@ struct smartlist_t; #define PROTOVER_HS_INTRO_V3 4 /** The protover version number that signifies HSv3 rendezvous point support */ #define PROTOVER_HS_RENDEZVOUS_POINT_V3 2 +/** The protover that signals support for HS circuit setup padding machines */ +#define PROTOVER_HS_SETUP_PADDING 2 /** List of recognized subprotocols. */ /// C_RUST_COUPLED: src/rust/protover/ffi.rs `translate_to_rust` @@ -44,6 +46,7 @@ typedef enum protocol_type_t { PRT_MICRODESC = 8, PRT_CONS = 9, PRT_PADDING = 10, + PRT_FLOWCTRL = 11, } protocol_type_t; bool protover_contains_long_protocol_names(const char *s); diff --git a/src/core/or/relay.c b/src/core/or/relay.c index 706a6e05cb..9e691a02b5 100644 --- a/src/core/or/relay.c +++ b/src/core/or/relay.c @@ -61,7 +61,7 @@ #include "core/mainloop/connection.h" #include "core/or/connection_edge.h" #include "core/or/connection_or.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" #include "feature/dircommon/directory.h" @@ -93,15 +93,12 @@ #include "core/or/origin_circuit_st.h" #include "feature/nodelist/routerinfo_st.h" #include "core/or/socks_request_st.h" - -#include "lib/intmath/weakrng.h" +#include "core/or/sendme.h" static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction, crypt_path_t *layer_hint); -static void circuit_consider_sending_sendme(circuit_t *circ, - crypt_path_t *layer_hint); static void circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint); static int circuit_resume_edge_reading_helper(edge_connection_t *conn, @@ -134,9 +131,6 @@ uint64_t stats_n_relay_cells_delivered = 0; * reached (see append_cell_to_circuit_queue()) */ uint64_t stats_n_circ_max_cell_reached = 0; -/** Used to tell which stream to read from first on a circuit. */ -static tor_weak_rng_t stream_choice_rng = TOR_WEAK_RNG_INIT; - /** * Update channel usage state based on the type of relay cell and * circuit properties. @@ -253,6 +247,10 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, if (recognized) { edge_connection_t *conn = NULL; + /* Recognized cell, the cell digest has been updated, we'll record it for + * the SENDME if need be. */ + sendme_record_received_cell_digest(circ, layer_hint); + if (circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) { if (pathbias_check_probe_response(circ, cell) == -1) { pathbias_count_valid_cells(circ, cell); @@ -535,6 +533,64 @@ relay_command_to_string(uint8_t command) } } +/** When padding a cell with randomness, leave this many zeros after the + * payload. */ +#define CELL_PADDING_GAP 4 + +/** Return the offset where the padding should start. The data_len is + * the relay payload length expected to be put in the cell. It can not be + * bigger than RELAY_PAYLOAD_SIZE else this function assert(). + * + * Value will always be smaller than CELL_PAYLOAD_SIZE because this offset is + * for the entire cell length not just the data payload length. Zero is + * returned if there is no room for padding. + * + * This function always skips the first 4 bytes after the payload because + * having some unused zero bytes has saved us a lot of times in the past. */ + +STATIC size_t +get_pad_cell_offset(size_t data_len) +{ + /* This is never supposed to happen but in case it does, stop right away + * because if tor is tricked somehow into not adding random bytes to the + * payload with this function returning 0 for a bad data_len, the entire + * authenticated SENDME design can be bypassed leading to bad denial of + * service attacks. */ + tor_assert(data_len <= RELAY_PAYLOAD_SIZE); + + /* If the offset is larger than the cell payload size, we return an offset + * of zero indicating that no padding needs to be added. */ + size_t offset = RELAY_HEADER_SIZE + data_len + CELL_PADDING_GAP; + if (offset >= CELL_PAYLOAD_SIZE) { + return 0; + } + return offset; +} + +/* Add random bytes to the unused portion of the payload, to foil attacks + * where the other side can predict all of the bytes in the payload and thus + * compute the authenticated SENDME cells without seeing the traffic. See + * proposal 289. */ +static void +pad_cell_payload(uint8_t *cell_payload, size_t data_len) +{ + size_t pad_offset, pad_len; + + tor_assert(cell_payload); + + pad_offset = get_pad_cell_offset(data_len); + if (pad_offset == 0) { + /* We can't add padding so we are done. */ + return; + } + + /* Remember here that the cell_payload is the length of the header and + * payload size so we offset it using the full length of the cell. */ + pad_len = CELL_PAYLOAD_SIZE - pad_offset; + crypto_fast_rng_getbytes(get_thread_fast_rng(), + cell_payload + pad_offset, pad_len); +} + /** Make a relay cell out of relay_command and payload, and send * it onto the open circuit circ. stream_id is the ID on * circ for the stream that's sending the relay cell, or 0 if it's a @@ -578,6 +634,9 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ, if (payload_len) memcpy(cell.payload+RELAY_HEADER_SIZE, payload, payload_len); + /* Add random padding to the cell if we can. */ + pad_cell_payload(cell.payload, payload_len); + log_debug(LD_OR,"delivering %d cell %s.", relay_command, cell_direction == CELL_DIRECTION_OUT ? "forward" : "backward"); @@ -645,6 +704,14 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ, circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); return -1; } + + /* If applicable, note the cell digest for the SENDME version 1 purpose if + * we need to. This call needs to be after the circuit_package_relay_cell() + * because the cell digest is set within that function. */ + if (relay_command == RELAY_COMMAND_DATA) { + sendme_record_cell_digest_on_circ(circ, cpath_layer); + } + return 0; } @@ -1434,6 +1501,81 @@ connection_edge_process_relay_cell_not_open( // return -1; } +/** Process a SENDME cell that arrived on circ. If it is a stream level + * cell, it is destined for the given conn. If it is a circuit level + * cell, it is destined for the layer_hint. The domain is the + * logging domain that should be used. + * + * Return 0 if everything went well or a negative value representing a circuit + * end reason on error for which the caller is responsible for closing it. */ +static int +process_sendme_cell(const relay_header_t *rh, const cell_t *cell, + circuit_t *circ, edge_connection_t *conn, + crypt_path_t *layer_hint, int domain) +{ + int ret; + + tor_assert(rh); + + if (!rh->stream_id) { + /* Circuit level SENDME cell. */ + ret = sendme_process_circuit_level(layer_hint, circ, + cell->payload + RELAY_HEADER_SIZE, + rh->length); + if (ret < 0) { + return ret; + } + /* Resume reading on any streams now that we've processed a valid + * SENDME cell that updated our package window. */ + circuit_resume_edge_reading(circ, layer_hint); + /* We are done, the rest of the code is for the stream level. */ + return 0; + } + + /* No connection, might be half edge state. We are done if so. */ + if (!conn) { + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + if (connection_half_edge_is_valid_sendme(ocirc->half_streams, + rh->stream_id)) { + circuit_read_valid_data(ocirc, rh->length); + log_info(domain, "Sendme cell on circ %u valid on half-closed " + "stream id %d", + ocirc->global_identifier, rh->stream_id); + } + } + + log_info(domain, "SENDME cell dropped, unknown stream (streamid %d).", + rh->stream_id); + return 0; + } + + /* Stream level SENDME cell. */ + ret = sendme_process_stream_level(conn, circ, rh->length); + if (ret < 0) { + /* Means we need to close the circuit with reason ret. */ + return ret; + } + + /* We've now processed properly a SENDME cell, all windows have been + * properly updated, we'll read on the edge connection to see if we can + * get data out towards the end point (Exit or client) since we are now + * allowed to deliver more cells. */ + + if (circuit_queue_streams_are_blocked(circ)) { + /* Still waiting for queue to flush; don't touch conn */ + return 0; + } + connection_start_reading(TO_CONN(conn)); + /* handle whatever might still be on the inbuf */ + if (connection_edge_package_raw_inbuf(conn, 1, NULL) < 0) { + /* (We already sent an end cell if possible) */ + connection_mark_for_close(TO_CONN(conn)); + return 0; + } + return 0; +} + /** An incoming relay cell has arrived on circuit circ. If * conn is NULL this is a control cell, else cell is * destined for conn. @@ -1487,7 +1629,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, } } - /* Tell circpad that we've recieved a recognized cell */ + /* Tell circpad that we've received a recognized cell */ circpad_deliver_recognized_relay_cell_events(circ, rh.command, layer_hint); /* either conn is NULL, in which case we've got a control cell, or else @@ -1521,6 +1663,17 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, if (circpad_handle_padding_negotiated(circ, cell, layer_hint) == 0) circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length); return 0; + } + + /* If this is a padding circuit we don't need to parse any other commands + * than the padding ones. Just drop them to the floor. */ + if (circ->purpose == CIRCUIT_PURPOSE_C_CIRCUIT_PADDING) { + log_info(domain, "Ignored cell (%d) that arrived in padding circuit.", + rh.command); + return 0; + } + + switch (rh.command) { case RELAY_COMMAND_BEGIN: case RELAY_COMMAND_BEGIN_DIR: if (layer_hint && @@ -1554,22 +1707,19 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, return connection_exit_begin_conn(cell, circ); case RELAY_COMMAND_DATA: ++stats_n_data_cells_received; - if (( layer_hint && --layer_hint->deliver_window < 0) || - (!layer_hint && --circ->deliver_window < 0)) { + + /* Update our circuit-level deliver window that we received a DATA cell. + * If the deliver window goes below 0, we end the circuit and stream due + * to a protocol failure. */ + if (sendme_circuit_data_received(circ, layer_hint) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "(relay data) circ deliver_window below 0. Killing."); - if (conn) { - /* XXXX Do we actually need to do this? Will killing the circuit - * not send an END and mark the stream for close as appropriate? */ - connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL); - connection_mark_for_close(TO_CONN(conn)); - } + connection_edge_end_close(conn, END_STREAM_REASON_TORPROTOCOL); return -END_CIRC_REASON_TORPROTOCOL; } - log_debug(domain,"circ deliver_window now %d.", layer_hint ? - layer_hint->deliver_window : circ->deliver_window); - circuit_consider_sending_sendme(circ, layer_hint); + /* Consider sending a circuit-level SENDME cell. */ + sendme_circuit_consider_sending(circ, layer_hint); if (rh.stream_id == 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay data cell with zero " @@ -1592,9 +1742,14 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, return 0; } - if (--conn->deliver_window < 0) { /* is it below 0 after decrement? */ + /* Update our stream-level deliver window that we just received a DATA + * cell. Going below 0 means we have a protocol level error so the + * stream and circuit are closed. */ + + if (sendme_stream_data_received(conn) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "(relay data) conn deliver_window below 0. Killing."); + connection_edge_end_close(conn, END_STREAM_REASON_TORPROTOCOL); return -END_CIRC_REASON_TORPROTOCOL; } /* Total all valid application bytes delivered */ @@ -1620,7 +1775,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, /* Only send a SENDME if we're not getting optimistic data; otherwise * a SENDME could arrive before the CONNECTED. */ - connection_edge_consider_sending_sendme(conn); + sendme_connection_edge_consider_sending(conn); } return 0; @@ -1813,99 +1968,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, (unsigned)circ->n_circ_id, rh.stream_id); return 0; case RELAY_COMMAND_SENDME: - if (!rh.stream_id) { - if (layer_hint) { - if (layer_hint->package_window + CIRCWINDOW_INCREMENT > - CIRCWINDOW_START_MAX) { - static struct ratelim_t exit_warn_ratelim = RATELIM_INIT(600); - log_fn_ratelim(&exit_warn_ratelim, LOG_WARN, LD_PROTOCOL, - "Unexpected sendme cell from exit relay. " - "Closing circ."); - return -END_CIRC_REASON_TORPROTOCOL; - } - layer_hint->package_window += CIRCWINDOW_INCREMENT; - log_debug(LD_APP,"circ-level sendme at origin, packagewindow %d.", - layer_hint->package_window); - circuit_resume_edge_reading(circ, layer_hint); - - /* We count circuit-level sendme's as valid delivered data because - * they are rate limited. - */ - if (CIRCUIT_IS_ORIGIN(circ)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), - rh.length); - } - - } else { - if (circ->package_window + CIRCWINDOW_INCREMENT > - CIRCWINDOW_START_MAX) { - static struct ratelim_t client_warn_ratelim = RATELIM_INIT(600); - log_fn_ratelim(&client_warn_ratelim,LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Unexpected sendme cell from client. " - "Closing circ (window %d).", - circ->package_window); - return -END_CIRC_REASON_TORPROTOCOL; - } - circ->package_window += CIRCWINDOW_INCREMENT; - log_debug(LD_APP, - "circ-level sendme at non-origin, packagewindow %d.", - circ->package_window); - circuit_resume_edge_reading(circ, layer_hint); - } - return 0; - } - if (!conn) { - if (CIRCUIT_IS_ORIGIN(circ)) { - origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); - if (connection_half_edge_is_valid_sendme(ocirc->half_streams, - rh.stream_id)) { - circuit_read_valid_data(ocirc, rh.length); - log_info(domain, - "sendme cell on circ %u valid on half-closed " - "stream id %d", ocirc->global_identifier, rh.stream_id); - } - } - - log_info(domain,"sendme cell dropped, unknown stream (streamid %d).", - rh.stream_id); - return 0; - } - - /* Don't allow the other endpoint to request more than our maximum - * (i.e. initial) stream SENDME window worth of data. Well-behaved - * stock clients will not request more than this max (as per the check - * in the while loop of connection_edge_consider_sending_sendme()). - */ - if (conn->package_window + STREAMWINDOW_INCREMENT > - STREAMWINDOW_START_MAX) { - static struct ratelim_t stream_warn_ratelim = RATELIM_INIT(600); - log_fn_ratelim(&stream_warn_ratelim, LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Unexpected stream sendme cell. Closing circ (window %d).", - conn->package_window); - return -END_CIRC_REASON_TORPROTOCOL; - } - - /* At this point, the stream sendme is valid */ - if (CIRCUIT_IS_ORIGIN(circ)) { - circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), - rh.length); - } - - conn->package_window += STREAMWINDOW_INCREMENT; - log_debug(domain,"stream-level sendme, packagewindow now %d.", - conn->package_window); - if (circuit_queue_streams_are_blocked(circ)) { - /* Still waiting for queue to flush; don't touch conn */ - return 0; - } - connection_start_reading(TO_CONN(conn)); - /* handle whatever might still be on the inbuf */ - if (connection_edge_package_raw_inbuf(conn, 1, NULL) < 0) { - /* (We already sent an end cell if possible) */ - connection_mark_for_close(TO_CONN(conn)); - return 0; - } - return 0; + return process_sendme_cell(&rh, cell, circ, conn, layer_hint, domain); case RELAY_COMMAND_RESOLVE: if (layer_hint) { log_fn(LOG_PROTOCOL_WARN, LD_APP, @@ -1979,6 +2042,84 @@ uint64_t stats_n_data_cells_received = 0; * ever received were completely full of data. */ uint64_t stats_n_data_bytes_received = 0; +/** + * Called when initializing a circuit, or when we have reached the end of the + * window in which we need to send some randomness so that incoming sendme + * cells will be unpredictable. Resets the flags and picks a new window. + */ +void +circuit_reset_sendme_randomness(circuit_t *circ) +{ + circ->have_sent_sufficiently_random_cell = 0; + circ->send_randomness_after_n_cells = CIRCWINDOW_INCREMENT / 2 + + crypto_fast_rng_get_uint(get_thread_fast_rng(), CIRCWINDOW_INCREMENT / 2); +} + +/** + * Any relay data payload containing fewer than this many real bytes is + * considered to have enough randomness to. + **/ +#define RELAY_PAYLOAD_LENGTH_FOR_RANDOM_SENDMES \ + (RELAY_PAYLOAD_SIZE - CELL_PADDING_GAP - 16) + +/** + * Helper. Return the number of bytes that should be put into a cell from a + * given edge connection on which n_available bytes are available. + */ +STATIC size_t +connection_edge_get_inbuf_bytes_to_package(size_t n_available, + int package_partial, + circuit_t *on_circuit) +{ + if (!n_available) + return 0; + + /* Do we need to force this payload to have space for randomness? */ + const bool force_random_bytes = + (on_circuit->send_randomness_after_n_cells == 0) && + (! on_circuit->have_sent_sufficiently_random_cell); + + /* At most how much would we like to send in this cell? */ + size_t target_length; + if (force_random_bytes) { + target_length = RELAY_PAYLOAD_LENGTH_FOR_RANDOM_SENDMES; + } else { + target_length = RELAY_PAYLOAD_SIZE; + } + + /* Decide how many bytes we will actually put into this cell. */ + size_t package_length; + if (n_available >= target_length) { /* A full payload is available. */ + package_length = target_length; + } else { /* not a full payload available */ + if (package_partial) + package_length = n_available; /* just take whatever's available now */ + else + return 0; /* nothing to do until we have a full payload */ + } + + /* If we reach this point, we will be definitely sending the cell. */ + tor_assert_nonfatal(package_length > 0); + + if (package_length <= RELAY_PAYLOAD_LENGTH_FOR_RANDOM_SENDMES) { + /* This cell will have enough randomness in the padding to make a future + * sendme cell unpredictable. */ + on_circuit->have_sent_sufficiently_random_cell = 1; + } + + if (on_circuit->send_randomness_after_n_cells == 0) { + /* Either this cell, or some previous cell, had enough padding to + * ensure sendme unpredictability. */ + tor_assert_nonfatal(on_circuit->have_sent_sufficiently_random_cell); + /* Pick a new interval in which we need to send randomness. */ + circuit_reset_sendme_randomness(on_circuit); + } + + --on_circuit->send_randomness_after_n_cells; + + return package_length; +} + /** If conn has an entire relay payload of bytes on its inbuf (or * package_partial is true), and the appropriate package windows aren't * empty, grab a cell and send it down the circuit. @@ -2051,17 +2192,14 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, bytes_to_process = connection_get_inbuf_len(TO_CONN(conn)); } - if (!bytes_to_process) + length = connection_edge_get_inbuf_bytes_to_package(bytes_to_process, + package_partial, circ); + if (!length) return 0; - if (!package_partial && bytes_to_process < RELAY_PAYLOAD_SIZE) - return 0; + /* If we reach this point, we will definitely be packaging bytes into + * a cell. */ - if (bytes_to_process > RELAY_PAYLOAD_SIZE) { - length = RELAY_PAYLOAD_SIZE; - } else { - length = bytes_to_process; - } stats_n_data_bytes_packaged += length; stats_n_data_cells_packaged += 1; @@ -2096,15 +2234,17 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, return 0; } - if (!cpath_layer) { /* non-rendezvous exit */ - tor_assert(circ->package_window > 0); - circ->package_window--; - } else { /* we're an AP, or an exit on a rendezvous circ */ - tor_assert(cpath_layer->package_window > 0); - cpath_layer->package_window--; + /* Handle the circuit-level SENDME package window. */ + if (sendme_note_circuit_data_packaged(circ, cpath_layer) < 0) { + /* Package window has gone under 0. Protocol issue. */ + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Circuit package window is below 0. Closing circuit."); + conn->end_reason = END_STREAM_REASON_TORPROTOCOL; + return -1; } - if (--conn->package_window <= 0) { /* is it 0 after decrement? */ + /* Handle the stream-level SENDME package window. */ + if (sendme_note_stream_data_packaged(conn) < 0) { connection_stop_reading(TO_CONN(conn)); log_debug(domain,"conn->package_window reached 0."); circuit_consider_stop_edge_reading(circ, cpath_layer); @@ -2122,42 +2262,6 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, goto repeat_connection_edge_package_raw_inbuf; } -/** Called when we've just received a relay data cell, when - * we've just finished flushing all bytes to stream conn, - * or when we've flushed *some* bytes to the stream conn. - * - * If conn->outbuf is not too full, and our deliver window is - * low, send back a suitable number of stream-level sendme cells. - */ -void -connection_edge_consider_sending_sendme(edge_connection_t *conn) -{ - circuit_t *circ; - - if (connection_outbuf_too_full(TO_CONN(conn))) - return; - - circ = circuit_get_by_edge_conn(conn); - if (!circ) { - /* this can legitimately happen if the destroy has already - * arrived and torn down the circuit */ - log_info(LD_APP,"No circuit associated with conn. Skipping."); - return; - } - - while (conn->deliver_window <= STREAMWINDOW_START - STREAMWINDOW_INCREMENT) { - log_debug(conn->base_.type == CONN_TYPE_AP ?LD_APP:LD_EXIT, - "Outbuf %d, Queuing stream sendme.", - (int)conn->base_.outbuf_flushlen); - conn->deliver_window += STREAMWINDOW_INCREMENT; - if (connection_edge_send_command(conn, RELAY_COMMAND_SENDME, - NULL, 0) < 0) { - log_warn(LD_APP,"connection_edge_send_command failed. Skipping."); - return; /* the circuit's closed, don't continue */ - } - } -} - /** The circuit circ has received a circuit-level sendme * (on hop layer_hint, if we're the OP). Go through all the * attached streams and let them resume reading and packaging, if @@ -2180,12 +2284,6 @@ circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) circ, layer_hint); } -void -stream_choice_seed_weak_rng(void) -{ - crypto_seed_weak_rng(&stream_choice_rng); -} - /** A helper function for circuit_resume_edge_reading() above. * The arguments are the same, except that conn is the head * of a linked list of edge streams that should each be considered. @@ -2237,7 +2335,8 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn, int num_streams = 0; for (conn = first_conn; conn; conn = conn->next_stream) { num_streams++; - if (tor_weak_random_one_in_n(&stream_choice_rng, num_streams)) { + + if (crypto_fast_rng_one_in_n(get_thread_fast_rng(), num_streams)) { chosen_stream = conn; } /* Invariant: chosen_stream has been chosen uniformly at random from @@ -2379,33 +2478,6 @@ circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) return 0; } -/** Check if the deliver_window for circuit circ (at hop - * layer_hint if it's defined) is low enough that we should - * send a circuit-level sendme back down the circuit. If so, send - * enough sendmes that the window would be overfull if we sent any - * more. - */ -static void -circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint) -{ -// log_fn(LOG_INFO,"Considering: layer_hint is %s", -// layer_hint ? "defined" : "null"); - while ((layer_hint ? layer_hint->deliver_window : circ->deliver_window) <= - CIRCWINDOW_START - CIRCWINDOW_INCREMENT) { - log_debug(LD_CIRC,"Queuing circuit sendme."); - if (layer_hint) - layer_hint->deliver_window += CIRCWINDOW_INCREMENT; - else - circ->deliver_window += CIRCWINDOW_INCREMENT; - if (relay_send_command_from_edge(0, circ, RELAY_COMMAND_SENDME, - NULL, 0, layer_hint) < 0) { - log_warn(LD_CIRC, - "relay_send_command_from_edge failed. Circuit's closed."); - return; /* the circuit's closed, don't continue */ - } - } -} - /** The total number of cells we have allocated. */ static size_t total_cells_allocated = 0; @@ -2780,7 +2852,7 @@ set_streams_blocked_on_circ(circuit_t *circ, channel_t *chan, } /** Extract the command from a packed cell. */ -static uint8_t +uint8_t packed_cell_get_command(const packed_cell_t *cell, int wide_circ_ids) { if (wide_circ_ids) { diff --git a/src/core/or/relay.h b/src/core/or/relay.h index 044f6be156..79036f97bd 100644 --- a/src/core/or/relay.h +++ b/src/core/or/relay.h @@ -42,6 +42,7 @@ int connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, int *max_cells); void connection_edge_consider_sending_sendme(edge_connection_t *conn); +void circuit_reset_sendme_randomness(circuit_t *circ); extern uint64_t stats_n_data_cells_packaged; extern uint64_t stats_n_data_bytes_packaged; @@ -94,9 +95,8 @@ const uint8_t *decode_address_from_payload(tor_addr_t *addr_out, int payload_len); void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan); -void stream_choice_seed_weak_rng(void); - circid_t packed_cell_get_circid(const packed_cell_t *cell, int wide_circ_ids); +uint8_t packed_cell_get_command(const packed_cell_t *cell, int wide_circ_ids); #ifdef RELAY_PRIVATE STATIC int connected_cell_parse(const relay_header_t *rh, const cell_t *cell, @@ -122,8 +122,11 @@ STATIC int cell_queues_check_size(void); STATIC int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, edge_connection_t *conn, crypt_path_t *layer_hint); +STATIC size_t get_pad_cell_offset(size_t payload_len); +STATIC size_t connection_edge_get_inbuf_bytes_to_package(size_t n_available, + int package_partial, + circuit_t *on_circuit); #endif /* defined(RELAY_PRIVATE) */ #endif /* !defined(TOR_RELAY_H) */ - diff --git a/src/core/or/relay_crypto_st.h b/src/core/or/relay_crypto_st.h index dafce257c7..83bbd329a6 100644 --- a/src/core/or/relay_crypto_st.h +++ b/src/core/or/relay_crypto_st.h @@ -25,7 +25,9 @@ struct relay_crypto_t { /** Digest state for cells heading away from the OR at this step. */ struct crypto_digest_t *b_digest; + /** Digest used for the next SENDME cell if any. */ + uint8_t sendme_digest[DIGEST_LEN]; }; #undef crypto_cipher_t -#endif +#endif /* !defined(RELAY_CRYPTO_ST_H) */ diff --git a/src/core/or/sendme.c b/src/core/or/sendme.c new file mode 100644 index 0000000000..47ac95f3cf --- /dev/null +++ b/src/core/or/sendme.c @@ -0,0 +1,710 @@ +/* Copyright (c) 2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file sendme.c + * \brief Code that is related to SENDME cells both in terms of + * creating/parsing cells and handling the content. + */ + +#define SENDME_PRIVATE + +#include "core/or/or.h" + +#include "app/config/config.h" +#include "core/crypto/relay_crypto.h" +#include "core/mainloop/connection.h" +#include "core/or/cell_st.h" +#include "core/or/crypt_path.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "core/or/or_circuit_st.h" +#include "core/or/relay.h" +#include "core/or/sendme.h" +#include "feature/nodelist/networkstatus.h" +#include "lib/ctime/di_ops.h" +#include "trunnel/sendme.h" + +/* Return the minimum version given by the consensus (if any) that should be + * used when emitting a SENDME cell. */ +STATIC int +get_emit_min_version(void) +{ + return networkstatus_get_param(NULL, "sendme_emit_min_version", + SENDME_EMIT_MIN_VERSION_DEFAULT, + SENDME_EMIT_MIN_VERSION_MIN, + SENDME_EMIT_MIN_VERSION_MAX); +} + +/* Return the minimum version given by the consensus (if any) that should be + * accepted when receiving a SENDME cell. */ +STATIC int +get_accept_min_version(void) +{ + return networkstatus_get_param(NULL, "sendme_accept_min_version", + SENDME_ACCEPT_MIN_VERSION_DEFAULT, + SENDME_ACCEPT_MIN_VERSION_MIN, + SENDME_ACCEPT_MIN_VERSION_MAX); +} + +/* Pop the first cell digset on the given circuit from the SENDME last digests + * list. NULL is returned if the list is uninitialized or empty. + * + * The caller gets ownership of the returned digest thus is responsible for + * freeing the memory. */ +static uint8_t * +pop_first_cell_digest(const circuit_t *circ) +{ + uint8_t *circ_digest; + + tor_assert(circ); + + if (circ->sendme_last_digests == NULL || + smartlist_len(circ->sendme_last_digests) == 0) { + return NULL; + } + + /* More cell digest than the SENDME window is never suppose to happen. The + * cell should have been rejected before reaching this point due to its + * package_window down to 0 leading to a circuit close. Scream loudly but + * still pop the element so we don't memory leak. */ + tor_assert_nonfatal(smartlist_len(circ->sendme_last_digests) <= + CIRCWINDOW_START_MAX / CIRCWINDOW_INCREMENT); + + circ_digest = smartlist_get(circ->sendme_last_digests, 0); + smartlist_del_keeporder(circ->sendme_last_digests, 0); + return circ_digest; +} + +/* Return true iff the given cell digest matches the first digest in the + * circuit sendme list. */ +static bool +v1_digest_matches(const uint8_t *circ_digest, const uint8_t *cell_digest) +{ + tor_assert(circ_digest); + tor_assert(cell_digest); + + /* Compare the digest with the one in the SENDME. This cell is invalid + * without a perfect match. */ + if (tor_memneq(circ_digest, cell_digest, TRUNNEL_SENDME_V1_DIGEST_LEN)) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "SENDME v1 cell digest do not match."); + return false; + } + + /* Digests matches! */ + return true; +} + +/* Return true iff the given decoded SENDME version 1 cell is valid and + * matches the expected digest on the circuit. + * + * Validation is done by comparing the digest in the cell from the previous + * cell we saw which tells us that the other side has in fact seen that cell. + * See proposal 289 for more details. */ +static bool +cell_v1_is_valid(const sendme_cell_t *cell, const uint8_t *circ_digest) +{ + tor_assert(cell); + tor_assert(circ_digest); + + const uint8_t *cell_digest = sendme_cell_getconstarray_data_v1_digest(cell); + return v1_digest_matches(circ_digest, cell_digest); +} + +/* Return true iff the given cell version can be handled or if the minimum + * accepted version from the consensus is known to us. */ +STATIC bool +cell_version_can_be_handled(uint8_t cell_version) +{ + int accept_version = get_accept_min_version(); + + /* We will first check if the consensus minimum accepted version can be + * handled by us and if not, regardless of the cell version we got, we can't + * continue. */ + if (accept_version > SENDME_MAX_SUPPORTED_VERSION) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Unable to accept SENDME version %u (from consensus). " + "We only support <= %u. Probably your tor is too old?", + accept_version, SENDME_MAX_SUPPORTED_VERSION); + goto invalid; + } + + /* Then, is this version below the accepted version from the consensus? If + * yes, we must not handle it. */ + if (cell_version < accept_version) { + log_info(LD_PROTOCOL, "Unacceptable SENDME version %u. Only " + "accepting %u (from consensus). Closing circuit.", + cell_version, accept_version); + goto invalid; + } + + /* Is this cell version supported by us? */ + if (cell_version > SENDME_MAX_SUPPORTED_VERSION) { + log_info(LD_PROTOCOL, "SENDME cell version %u is not supported by us. " + "We only support <= %u", + cell_version, SENDME_MAX_SUPPORTED_VERSION); + goto invalid; + } + + return true; + invalid: + return false; +} + +/* Return true iff the encoded SENDME cell in cell_payload of length + * cell_payload_len is valid. For each version: + * + * 0: No validation + * 1: Authenticated with last cell digest. + * + * This is the main critical function to make sure we can continue to + * send/recv cells on a circuit. If the SENDME is invalid, the circuit should + * be marked for close by the caller. */ +STATIC bool +sendme_is_valid(const circuit_t *circ, const uint8_t *cell_payload, + size_t cell_payload_len) +{ + uint8_t cell_version; + uint8_t *circ_digest = NULL; + sendme_cell_t *cell = NULL; + + tor_assert(circ); + tor_assert(cell_payload); + + /* An empty payload means version 0 so skip trunnel parsing. We won't be + * able to parse a 0 length buffer into a valid SENDME cell. */ + if (cell_payload_len == 0) { + cell_version = 0; + } else { + /* First we'll decode the cell so we can get the version. */ + if (sendme_cell_parse(&cell, cell_payload, cell_payload_len) < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Unparseable SENDME cell received. Closing circuit."); + goto invalid; + } + cell_version = sendme_cell_get_version(cell); + } + + /* Validate that we can handle this cell version. */ + if (!cell_version_can_be_handled(cell_version)) { + goto invalid; + } + + /* Pop the first element that was added (FIFO). We do that regardless of the + * version so we don't accumulate on the circuit if v0 is used by the other + * end point. */ + circ_digest = pop_first_cell_digest(circ); + if (circ_digest == NULL) { + /* We shouldn't have received a SENDME if we have no digests. Log at + * protocol warning because it can be tricked by sending many SENDMEs + * without prior data cell. */ + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "We received a SENDME but we have no cell digests to match. " + "Closing circuit."); + goto invalid; + } + + /* Validate depending on the version now. */ + switch (cell_version) { + case 0x01: + if (!cell_v1_is_valid(cell, circ_digest)) { + goto invalid; + } + break; + case 0x00: + /* Version 0, there is no work to be done on the payload so it is + * necessarily valid if we pass the version validation. */ + break; + default: + log_warn(LD_PROTOCOL, "Unknown SENDME cell version %d received.", + cell_version); + tor_assert_nonfatal_unreached(); + break; + } + + /* Valid cell. */ + sendme_cell_free(cell); + tor_free(circ_digest); + return true; + invalid: + sendme_cell_free(cell); + tor_free(circ_digest); + return false; +} + +/* Build and encode a version 1 SENDME cell into payload, which must be at + * least of RELAY_PAYLOAD_SIZE bytes, using the digest for the cell data. + * + * Return the size in bytes of the encoded cell in payload. A negative value + * is returned on encoding failure. */ +STATIC ssize_t +build_cell_payload_v1(const uint8_t *cell_digest, uint8_t *payload) +{ + ssize_t len = -1; + sendme_cell_t *cell = NULL; + + tor_assert(cell_digest); + tor_assert(payload); + + cell = sendme_cell_new(); + + /* Building a payload for version 1. */ + sendme_cell_set_version(cell, 0x01); + /* Set the data length field for v1. */ + sendme_cell_set_data_len(cell, TRUNNEL_SENDME_V1_DIGEST_LEN); + + /* Copy the digest into the data payload. */ + memcpy(sendme_cell_getarray_data_v1_digest(cell), cell_digest, + sendme_cell_get_data_len(cell)); + + /* Finally, encode the cell into the payload. */ + len = sendme_cell_encode(payload, RELAY_PAYLOAD_SIZE, cell); + + sendme_cell_free(cell); + return len; +} + +/* Send a circuit-level SENDME on the given circuit using the layer_hint if + * not NULL. The digest is only used for version 1. + * + * Return 0 on success else a negative value and the circuit will be closed + * because we failed to send the cell on it. */ +static int +send_circuit_level_sendme(circuit_t *circ, crypt_path_t *layer_hint, + const uint8_t *cell_digest) +{ + uint8_t emit_version; + uint8_t payload[RELAY_PAYLOAD_SIZE]; + ssize_t payload_len; + + tor_assert(circ); + tor_assert(cell_digest); + + emit_version = get_emit_min_version(); + switch (emit_version) { + case 0x01: + payload_len = build_cell_payload_v1(cell_digest, payload); + if (BUG(payload_len < 0)) { + /* Unable to encode the cell, abort. We can recover from this by closing + * the circuit but in theory it should never happen. */ + return -1; + } + log_debug(LD_PROTOCOL, "Emitting SENDME version 1 cell."); + break; + case 0x00: + /* Fallthrough because default is to use v0. */ + default: + /* Unknown version, fallback to version 0 meaning no payload. */ + payload_len = 0; + log_debug(LD_PROTOCOL, "Emitting SENDME version 0 cell. " + "Consensus emit version is %d", emit_version); + break; + } + + if (relay_send_command_from_edge(0, circ, RELAY_COMMAND_SENDME, + (char *) payload, payload_len, + layer_hint) < 0) { + log_warn(LD_CIRC, + "SENDME relay_send_command_from_edge failed. Circuit's closed."); + return -1; /* the circuit's closed, don't continue */ + } + return 0; +} + +/* Record the cell digest only if the next cell is expected to be a SENDME. */ +static void +record_cell_digest_on_circ(circuit_t *circ, const uint8_t *sendme_digest) +{ + tor_assert(circ); + tor_assert(sendme_digest); + + /* Add the digest to the last seen list in the circuit. */ + if (circ->sendme_last_digests == NULL) { + circ->sendme_last_digests = smartlist_new(); + } + smartlist_add(circ->sendme_last_digests, + tor_memdup(sendme_digest, DIGEST_LEN)); +} + +/* + * Public API + */ + +/** Return true iff the next cell for the given cell window is expected to be + * a SENDME. + * + * We are able to know that because the package or deliver window value minus + * one cell (the possible SENDME cell) should be a multiple of the increment + * window value. */ +static bool +circuit_sendme_cell_is_next(int window) +{ + /* At the start of the window, no SENDME will be expected. */ + if (window == CIRCWINDOW_START) { + return false; + } + + /* Are we at the limit of the increment and if not, we don't expect next + * cell is a SENDME. + * + * We test against the window minus 1 because when we are looking if the + * next cell is a SENDME, the window (either package or deliver) hasn't been + * decremented just yet so when this is called, we are currently processing + * the "window - 1" cell. + * + * This function is used when recording a cell digest and this is done quite + * low in the stack when decrypting or encrypting a cell. The window is only + * updated once the cell is actually put in the outbuf. */ + if (((window - 1) % CIRCWINDOW_INCREMENT) != 0) { + return false; + } + + /* Next cell is expected to be a SENDME. */ + return true; +} + +/** Called when we've just received a relay data cell, when we've just + * finished flushing all bytes to stream conn, or when we've flushed + * *some* bytes to the stream conn. + * + * If conn->outbuf is not too full, and our deliver window is low, send back a + * suitable number of stream-level sendme cells. + */ +void +sendme_connection_edge_consider_sending(edge_connection_t *conn) +{ + tor_assert(conn); + + int log_domain = TO_CONN(conn)->type == CONN_TYPE_AP ? LD_APP : LD_EXIT; + + /* Don't send it if we still have data to deliver. */ + if (connection_outbuf_too_full(TO_CONN(conn))) { + goto end; + } + + if (circuit_get_by_edge_conn(conn) == NULL) { + /* This can legitimately happen if the destroy has already arrived and + * torn down the circuit. */ + log_info(log_domain, "No circuit associated with edge connection. " + "Skipping sending SENDME."); + goto end; + } + + while (conn->deliver_window <= + (STREAMWINDOW_START - STREAMWINDOW_INCREMENT)) { + log_debug(log_domain, "Outbuf %" TOR_PRIuSZ ", queuing stream SENDME.", + TO_CONN(conn)->outbuf_flushlen); + conn->deliver_window += STREAMWINDOW_INCREMENT; + if (connection_edge_send_command(conn, RELAY_COMMAND_SENDME, + NULL, 0) < 0) { + log_warn(LD_BUG, "connection_edge_send_command failed while sending " + "a SENDME. Circuit probably closed, skipping."); + goto end; /* The circuit's closed, don't continue */ + } + } + + end: + return; +} + +/** Check if the deliver_window for circuit circ (at hop + * layer_hint if it's defined) is low enough that we should + * send a circuit-level sendme back down the circuit. If so, send + * enough sendmes that the window would be overfull if we sent any + * more. + */ +void +sendme_circuit_consider_sending(circuit_t *circ, crypt_path_t *layer_hint) +{ + bool sent_one_sendme = false; + const uint8_t *digest; + + while ((layer_hint ? layer_hint->deliver_window : circ->deliver_window) <= + CIRCWINDOW_START - CIRCWINDOW_INCREMENT) { + log_debug(LD_CIRC,"Queuing circuit sendme."); + if (layer_hint) { + layer_hint->deliver_window += CIRCWINDOW_INCREMENT; + digest = cpath_get_sendme_digest(layer_hint); + } else { + circ->deliver_window += CIRCWINDOW_INCREMENT; + digest = relay_crypto_get_sendme_digest(&TO_OR_CIRCUIT(circ)->crypto); + } + if (send_circuit_level_sendme(circ, layer_hint, digest) < 0) { + return; /* The circuit's closed, don't continue */ + } + /* Current implementation is not suppose to send multiple SENDME at once + * because this means we would use the same relay crypto digest for each + * SENDME leading to a mismatch on the other side and the circuit to + * collapse. Scream loudly if it ever happens so we can address it. */ + tor_assert_nonfatal(!sent_one_sendme); + sent_one_sendme = true; + } +} + +/* Process a circuit-level SENDME cell that we just received. The layer_hint, + * if not NULL, is the Exit hop of the connection which means that we are a + * client. In that case, circ must be an origin circuit. The cell_body_len is + * the length of the SENDME cell payload (excluding the header). The + * cell_payload is the payload. + * + * Return 0 on success (the SENDME is valid and the package window has + * been updated properly). + * + * On error, a negative value is returned, which indicates that the + * circuit must be closed using the value as the reason for it. */ +int +sendme_process_circuit_level(crypt_path_t *layer_hint, + circuit_t *circ, const uint8_t *cell_payload, + uint16_t cell_payload_len) +{ + tor_assert(circ); + tor_assert(cell_payload); + + /* Validate the SENDME cell. Depending on the version, different validation + * can be done. An invalid SENDME requires us to close the circuit. */ + if (!sendme_is_valid(circ, cell_payload, cell_payload_len)) { + return -END_CIRC_REASON_TORPROTOCOL; + } + + /* If we are the origin of the circuit, we are the Client so we use the + * layer hint (the Exit hop) for the package window tracking. */ + if (CIRCUIT_IS_ORIGIN(circ)) { + /* If we are the origin of the circuit, it is impossible to not have a + * cpath. Just in case, bug on it and close the circuit. */ + if (BUG(layer_hint == NULL)) { + return -END_CIRC_REASON_TORPROTOCOL; + } + if ((layer_hint->package_window + CIRCWINDOW_INCREMENT) > + CIRCWINDOW_START_MAX) { + static struct ratelim_t exit_warn_ratelim = RATELIM_INIT(600); + log_fn_ratelim(&exit_warn_ratelim, LOG_WARN, LD_PROTOCOL, + "Unexpected sendme cell from exit relay. " + "Closing circ."); + return -END_CIRC_REASON_TORPROTOCOL; + } + layer_hint->package_window += CIRCWINDOW_INCREMENT; + log_debug(LD_APP, "circ-level sendme at origin, packagewindow %d.", + layer_hint->package_window); + + /* We count circuit-level sendme's as valid delivered data because they + * are rate limited. */ + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), cell_payload_len); + } else { + /* We aren't the origin of this circuit so we are the Exit and thus we + * track the package window with the circuit object. */ + if ((circ->package_window + CIRCWINDOW_INCREMENT) > + CIRCWINDOW_START_MAX) { + static struct ratelim_t client_warn_ratelim = RATELIM_INIT(600); + log_fn_ratelim(&client_warn_ratelim, LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Unexpected sendme cell from client. " + "Closing circ (window %d).", circ->package_window); + return -END_CIRC_REASON_TORPROTOCOL; + } + circ->package_window += CIRCWINDOW_INCREMENT; + log_debug(LD_EXIT, "circ-level sendme at non-origin, packagewindow %d.", + circ->package_window); + } + + return 0; +} + +/* Process a stream-level SENDME cell that we just received. The conn is the + * edge connection (stream) that the circuit circ is associated with. The + * cell_body_len is the length of the payload (excluding the header). + * + * Return 0 on success (the SENDME is valid and the package window has + * been updated properly). + * + * On error, a negative value is returned, which indicates that the + * circuit must be closed using the value as the reason for it. */ +int +sendme_process_stream_level(edge_connection_t *conn, circuit_t *circ, + uint16_t cell_body_len) +{ + tor_assert(conn); + tor_assert(circ); + + /* Don't allow the other endpoint to request more than our maximum (i.e. + * initial) stream SENDME window worth of data. Well-behaved stock clients + * will not request more than this max (as per the check in the while loop + * of sendme_connection_edge_consider_sending()). */ + if ((conn->package_window + STREAMWINDOW_INCREMENT) > + STREAMWINDOW_START_MAX) { + static struct ratelim_t stream_warn_ratelim = RATELIM_INIT(600); + log_fn_ratelim(&stream_warn_ratelim, LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Unexpected stream sendme cell. Closing circ (window %d).", + conn->package_window); + return -END_CIRC_REASON_TORPROTOCOL; + } + /* At this point, the stream sendme is valid */ + conn->package_window += STREAMWINDOW_INCREMENT; + + /* We count circuit-level sendme's as valid delivered data because they are + * rate limited. */ + if (CIRCUIT_IS_ORIGIN(circ)) { + circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), cell_body_len); + } + + log_debug(CIRCUIT_IS_ORIGIN(circ) ? LD_APP : LD_EXIT, + "stream-level sendme, package_window now %d.", + conn->package_window); + return 0; +} + +/* Called when a relay DATA cell is received on the given circuit. If + * layer_hint is NULL, this means we are the Exit end point else we are the + * Client. Update the deliver window and return its new value. */ +int +sendme_circuit_data_received(circuit_t *circ, crypt_path_t *layer_hint) +{ + int deliver_window, domain; + + if (CIRCUIT_IS_ORIGIN(circ)) { + tor_assert(layer_hint); + --layer_hint->deliver_window; + deliver_window = layer_hint->deliver_window; + domain = LD_APP; + } else { + tor_assert(!layer_hint); + --circ->deliver_window; + deliver_window = circ->deliver_window; + domain = LD_EXIT; + } + + log_debug(domain, "Circuit deliver_window now %d.", deliver_window); + return deliver_window; +} + +/* Called when a relay DATA cell is received for the given edge connection + * conn. Update the deliver window and return its new value. */ +int +sendme_stream_data_received(edge_connection_t *conn) +{ + tor_assert(conn); + return --conn->deliver_window; +} + +/* Called when a relay DATA cell is packaged on the given circuit. If + * layer_hint is NULL, this means we are the Exit end point else we are the + * Client. Update the package window and return its new value. */ +int +sendme_note_circuit_data_packaged(circuit_t *circ, crypt_path_t *layer_hint) +{ + int package_window, domain; + + tor_assert(circ); + + if (CIRCUIT_IS_ORIGIN(circ)) { + /* Client side. */ + tor_assert(layer_hint); + --layer_hint->package_window; + package_window = layer_hint->package_window; + domain = LD_APP; + } else { + /* Exit side. */ + tor_assert(!layer_hint); + --circ->package_window; + package_window = circ->package_window; + domain = LD_EXIT; + } + + log_debug(domain, "Circuit package_window now %d.", package_window); + return package_window; +} + +/* Called when a relay DATA cell is packaged for the given edge connection + * conn. Update the package window and return its new value. */ +int +sendme_note_stream_data_packaged(edge_connection_t *conn) +{ + tor_assert(conn); + + --conn->package_window; + log_debug(LD_APP, "Stream package_window now %d.", conn->package_window); + return conn->package_window; +} + +/* Record the cell digest into the circuit sendme digest list depending on + * which edge we are. The digest is recorded only if we expect the next cell + * that we will receive is a SENDME so we can match the digest. */ +void +sendme_record_cell_digest_on_circ(circuit_t *circ, crypt_path_t *cpath) +{ + int package_window; + uint8_t *sendme_digest; + + tor_assert(circ); + + package_window = circ->package_window; + if (cpath) { + package_window = cpath->package_window; + } + + /* Is this the last cell before a SENDME? The idea is that if the + * package_window reaches a multiple of the increment, after this cell, we + * should expect a SENDME. */ + if (!circuit_sendme_cell_is_next(package_window)) { + return; + } + + /* Getting the digest is expensive so we only do it once we are certain to + * record it on the circuit. */ + if (cpath) { + sendme_digest = cpath_get_sendme_digest(cpath); + } else { + sendme_digest = + relay_crypto_get_sendme_digest(&TO_OR_CIRCUIT(circ)->crypto); + } + + record_cell_digest_on_circ(circ, sendme_digest); +} + +/* Called once we decrypted a cell and recognized it. Record the cell digest + * as the next sendme digest only if the next cell we'll send on the circuit + * is expected to be a SENDME. */ +void +sendme_record_received_cell_digest(circuit_t *circ, crypt_path_t *cpath) +{ + tor_assert(circ); + + /* Only record if the next cell is expected to be a SENDME. */ + if (!circuit_sendme_cell_is_next(cpath ? cpath->deliver_window : + circ->deliver_window)) { + return; + } + + if (cpath) { + /* Record incoming digest. */ + cpath_sendme_record_cell_digest(cpath, false); + } else { + /* Record foward digest. */ + relay_crypto_record_sendme_digest(&TO_OR_CIRCUIT(circ)->crypto, true); + } +} + +/* Called once we encrypted a cell. Record the cell digest as the next sendme + * digest only if the next cell we expect to receive is a SENDME so we can + * match the digests. */ +void +sendme_record_sending_cell_digest(circuit_t *circ, crypt_path_t *cpath) +{ + tor_assert(circ); + + /* Only record if the next cell is expected to be a SENDME. */ + if (!circuit_sendme_cell_is_next(cpath ? cpath->package_window : + circ->package_window)) { + goto end; + } + + if (cpath) { + /* Record the forward digest. */ + cpath_sendme_record_cell_digest(cpath, true); + } else { + /* Record the incoming digest. */ + relay_crypto_record_sendme_digest(&TO_OR_CIRCUIT(circ)->crypto, false); + } + + end: + return; +} diff --git a/src/core/or/sendme.h b/src/core/or/sendme.h new file mode 100644 index 0000000000..20477103fd --- /dev/null +++ b/src/core/or/sendme.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file sendme.h + * \brief Header file for sendme.c. + **/ + +#ifndef TOR_SENDME_H +#define TOR_SENDME_H + +#include "core/or/edge_connection_st.h" +#include "core/or/crypt_path_st.h" +#include "core/or/circuit_st.h" + +/* Sending SENDME cell. */ +void sendme_connection_edge_consider_sending(edge_connection_t *edge_conn); +void sendme_circuit_consider_sending(circuit_t *circ, + crypt_path_t *layer_hint); + +/* Processing SENDME cell. */ +int sendme_process_circuit_level(crypt_path_t *layer_hint, + circuit_t *circ, const uint8_t *cell_payload, + uint16_t cell_payload_len); +int sendme_process_stream_level(edge_connection_t *conn, circuit_t *circ, + uint16_t cell_body_len); + +/* Update deliver window functions. */ +int sendme_stream_data_received(edge_connection_t *conn); +int sendme_circuit_data_received(circuit_t *circ, crypt_path_t *layer_hint); + +/* Update package window functions. */ +int sendme_note_circuit_data_packaged(circuit_t *circ, + crypt_path_t *layer_hint); +int sendme_note_stream_data_packaged(edge_connection_t *conn); + +/* Record cell digest on circuit. */ +void sendme_record_cell_digest_on_circ(circuit_t *circ, crypt_path_t *cpath); +/* Record cell digest as the SENDME digest. */ +void sendme_record_received_cell_digest(circuit_t *circ, crypt_path_t *cpath); +void sendme_record_sending_cell_digest(circuit_t *circ, crypt_path_t *cpath); + +/* Private section starts. */ +#ifdef SENDME_PRIVATE + +/* The maximum supported version. Above that value, the cell can't be + * recognized as a valid SENDME. */ +#define SENDME_MAX_SUPPORTED_VERSION 1 + +/* The cell version constants for when emitting a cell. */ +#define SENDME_EMIT_MIN_VERSION_DEFAULT 0 +#define SENDME_EMIT_MIN_VERSION_MIN 0 +#define SENDME_EMIT_MIN_VERSION_MAX UINT8_MAX + +/* The cell version constants for when accepting a cell. */ +#define SENDME_ACCEPT_MIN_VERSION_DEFAULT 0 +#define SENDME_ACCEPT_MIN_VERSION_MIN 0 +#define SENDME_ACCEPT_MIN_VERSION_MAX UINT8_MAX + +/* + * Unit tests declaractions. + */ +#ifdef TOR_UNIT_TESTS + +STATIC int get_emit_min_version(void); +STATIC int get_accept_min_version(void); + +STATIC bool cell_version_can_be_handled(uint8_t cell_version); + +STATIC ssize_t build_cell_payload_v1(const uint8_t *cell_digest, + uint8_t *payload); +STATIC bool sendme_is_valid(const circuit_t *circ, + const uint8_t *cell_payload, + size_t cell_payload_len); + +#endif /* defined(TOR_UNIT_TESTS) */ + +#endif /* defined(SENDME_PRIVATE) */ + +#endif /* !defined(TOR_SENDME_H) */ diff --git a/src/core/or/server_port_cfg_st.h b/src/core/or/server_port_cfg_st.h index bd026af7ee..0738735c61 100644 --- a/src/core/or/server_port_cfg_st.h +++ b/src/core/or/server_port_cfg_st.h @@ -16,5 +16,5 @@ struct server_port_cfg_t { unsigned int bind_ipv6_only : 1; }; -#endif +#endif /* !defined(SERVER_PORT_CFG_ST_H) */ diff --git a/src/core/or/socks_request_st.h b/src/core/or/socks_request_st.h index 5922870c61..9fb941ff7e 100644 --- a/src/core/or/socks_request_st.h +++ b/src/core/or/socks_request_st.h @@ -74,4 +74,4 @@ struct socks_request_t { uint8_t socks5_atyp; /* SOCKS5 address type */ }; -#endif +#endif /* !defined(SOCKS_REQUEST_ST_H) */ diff --git a/src/core/or/tor_version_st.h b/src/core/or/tor_version_st.h index 716429bd32..c5bdcaf07b 100644 --- a/src/core/or/tor_version_st.h +++ b/src/core/or/tor_version_st.h @@ -28,5 +28,5 @@ struct tor_version_t { char git_tag[DIGEST_LEN]; }; -#endif +#endif /* !defined(TOR_VERSION_ST_H) */ diff --git a/src/core/or/var_cell_st.h b/src/core/or/var_cell_st.h index 4287c83f6d..607c0d6c83 100644 --- a/src/core/or/var_cell_st.h +++ b/src/core/or/var_cell_st.h @@ -19,5 +19,5 @@ struct var_cell_t { uint8_t payload[FLEXIBLE_ARRAY_MEMBER]; }; -#endif +#endif /* !defined(VAR_CELL_ST_H) */ diff --git a/src/core/or/versions.c b/src/core/or/versions.c index 2a572d4704..06417bb4eb 100644 --- a/src/core/or/versions.c +++ b/src/core/or/versions.c @@ -448,8 +448,9 @@ memoize_protover_summary(protover_summary_flags_t *out, out->supports_v3_rendezvous_point = protocol_list_supports_protocol(protocols, PRT_HSREND, PROTOVER_HS_RENDEZVOUS_POINT_V3); - out->supports_padding = - protocol_list_supports_protocol(protocols, PRT_PADDING, 1); + out->supports_hs_setup_padding = + protocol_list_supports_protocol(protocols, PRT_PADDING, + PROTOVER_HS_SETUP_PADDING); protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out)); cached = strmap_set(protover_summary_map, protocols, new_cached); diff --git a/src/core/proto/proto_socks.c b/src/core/proto/proto_socks.c index ac0c9e911b..b657a7b758 100644 --- a/src/core/proto/proto_socks.c +++ b/src/core/proto/proto_socks.c @@ -8,7 +8,7 @@ #include "feature/client/addressmap.h" #include "lib/buf/buffers.h" #include "core/mainloop/connection.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "app/config/config.h" #include "lib/crypt_ops/crypto_util.h" #include "feature/relay/ext_orport.h" diff --git a/src/ext/include.am b/src/ext/include.am index 6bdce2d79e..317e25d78e 100644 --- a/src/ext/include.am +++ b/src/ext/include.am @@ -143,6 +143,7 @@ noinst_HEADERS += $(ED25519_DONNA_HDRS) LIBED25519_DONNA=src/ext/ed25519/donna/libed25519_donna.a noinst_LIBRARIES += $(LIBED25519_DONNA) +if BUILD_KECCAK_TINY src_ext_keccak_tiny_libkeccak_tiny_a_CFLAGS=\ @CFLAGS_CONSTTIME@ @@ -156,6 +157,7 @@ noinst_HEADERS += $(LIBKECCAK_TINY_HDRS) LIBKECCAK_TINY=src/ext/keccak-tiny/libkeccak-tiny.a noinst_LIBRARIES += $(LIBKECCAK_TINY) +endif EXTRA_DIST += \ src/ext/timeouts/bench/bench-add.lua \ diff --git a/src/ext/timeouts/.may_include b/src/ext/timeouts/.may_include index 42f44befd4..92c7116555 100644 --- a/src/ext/timeouts/.may_include +++ b/src/ext/timeouts/.may_include @@ -1,6 +1,5 @@ orconfig.h ext/tor_queue.h -timeout-bitops.c -timeout-debug.h -timeout.h +ext/timeouts/*.h +ext/timeouts/timeout-bitops.c diff --git a/src/ext/timeouts/test-timeout.c b/src/ext/timeouts/test-timeout.c index 8077129376..52d2e31e0c 100644 --- a/src/ext/timeouts/test-timeout.c +++ b/src/ext/timeouts/test-timeout.c @@ -4,7 +4,7 @@ #include #include -#include "timeout.h" +#include "ext/timeouts/timeout.h" #define THE_END_OF_TIME ((timeout_t)-1) diff --git a/src/ext/timeouts/timeout.c b/src/ext/timeouts/timeout.c index 07d06772c5..79fcc168ed 100644 --- a/src/ext/timeouts/timeout.c +++ b/src/ext/timeouts/timeout.c @@ -40,14 +40,14 @@ #include "ext/tor_queue.h" /* TAILQ(3) */ -#include "timeout.h" +#include "ext/timeouts/timeout.h" #ifndef TIMEOUT_DEBUG #define TIMEOUT_DEBUG 0 #endif #if TIMEOUT_DEBUG - 0 -#include "timeout-debug.h" +#include "ext/timeouts/timeout-debug.h" #endif #ifdef TIMEOUT_DISABLE_RELATIVE_ACCESS @@ -141,7 +141,7 @@ #define WHEEL_MASK (WHEEL_LEN - 1) #define TIMEOUT_MAX ((TIMEOUT_C(1) << (WHEEL_BIT * WHEEL_NUM)) - 1) -#include "timeout-bitops.c" +#include "ext/timeouts/timeout-bitops.c" #if WHEEL_BIT == 6 #define ctz(n) ctz64(n) diff --git a/src/ext/tinytest.c b/src/ext/tinytest.c index 16f11e4639..239fdd0a38 100644 --- a/src/ext/tinytest.c +++ b/src/ext/tinytest.c @@ -492,6 +492,12 @@ tinytest_set_test_skipped_(void) cur_test_outcome = SKIP; } +int +tinytest_cur_test_has_failed(void) +{ + return (cur_test_outcome == FAIL); +} + char * tinytest_format_hex_(const void *val_, unsigned long len) { diff --git a/src/ext/tinytest.h b/src/ext/tinytest.h index ed07b26bc0..05c2fda052 100644 --- a/src/ext/tinytest.h +++ b/src/ext/tinytest.h @@ -72,6 +72,9 @@ struct testlist_alias_t { }; #define END_OF_ALIASES { NULL, NULL } +/** Return true iff the current test has failed. */ +int tinytest_cur_test_has_failed(void); + /** Implementation: called from a test to indicate failure, before logging. */ void tinytest_set_test_failed_(void); /** Implementation: called from a test to indicate that we're skipping. */ diff --git a/src/feature/api/tor_api.c b/src/feature/api/tor_api.c index 697397d46b..fd9d241353 100644 --- a/src/feature/api/tor_api.c +++ b/src/feature/api/tor_api.c @@ -40,10 +40,10 @@ #define raw_socketpair tor_ersatz_socketpair #define raw_closesocket closesocket #define snprintf _snprintf -#else +#else /* !(defined(_WIN32)) */ #define raw_socketpair socketpair #define raw_closesocket close -#endif +#endif /* defined(_WIN32) */ #ifdef HAVE_UNISTD_H #include diff --git a/src/feature/api/tor_api.h b/src/feature/api/tor_api.h index 2bf130c376..cb84853a52 100644 --- a/src/feature/api/tor_api.h +++ b/src/feature/api/tor_api.h @@ -55,7 +55,7 @@ typedef SOCKET tor_control_socket_t; #else typedef int tor_control_socket_t; #define INVALID_TOR_CONTROL_SOCKET (-1) -#endif +#endif /* defined(_WIN32) */ /** DOCDOC */ tor_control_socket_t tor_main_configuration_setup_control_socket( diff --git a/src/feature/client/addressmap.c b/src/feature/client/addressmap.c index bbe786a6a2..c5a27ce8c6 100644 --- a/src/feature/client/addressmap.c +++ b/src/feature/client/addressmap.c @@ -22,7 +22,7 @@ #include "core/or/circuituse.h" #include "app/config/config.h" #include "core/or/connection_edge.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/relay/dns.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerset.h" diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c index 05f89ad36c..f517876609 100644 --- a/src/feature/client/bridges.c +++ b/src/feature/client/bridges.c @@ -348,7 +348,7 @@ int node_is_a_configured_bridge(const node_t *node) { /* First, let's try searching for a bridge with matching identity. */ - if (BUG(tor_digest_is_zero(node->identity))) + if (BUG(fast_mem_is_zero(node->identity, DIGEST_LEN))) return 0; if (find_bridge_by_digest(node->identity) != NULL) diff --git a/src/feature/client/circpathbias.c b/src/feature/client/circpathbias.c index 1743ab5a81..3544dbb859 100644 --- a/src/feature/client/circpathbias.c +++ b/src/feature/client/circpathbias.c @@ -176,6 +176,7 @@ pathbias_get_scale_threshold(const or_options_t *options) static double pathbias_get_scale_ratio(const or_options_t *options) { + (void) options; /* * The scale factor is the denominator for our scaling * of circuit counts for our path bias window. @@ -185,7 +186,8 @@ pathbias_get_scale_ratio(const or_options_t *options) */ int denominator = networkstatus_get_param(NULL, "pb_scalefactor", 2, 2, INT32_MAX); - (void) options; + tor_assert(denominator > 0); + /** * The mult factor is the numerator for our scaling * of circuit counts for our path bias window. It @@ -369,8 +371,9 @@ pathbias_should_count(origin_circuit_t *circ) !circ->build_state->onehop_tunnel) { if ((rate_msg = rate_limit_log(&count_limit, approx_time()))) { log_info(LD_BUG, - "One-hop circuit has length %d. Path state is %s. " + "One-hop circuit %d has length %d. Path state is %s. " "Circuit is a %s currently %s.%s", + circ->global_identifier, circ->build_state->desired_path_len, pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), @@ -398,12 +401,13 @@ pathbias_should_count(origin_circuit_t *circ) /* Check to see if the shouldcount result has changed due to a * unexpected purpose change that would affect our results */ if (circ->pathbias_shouldcount == PATHBIAS_SHOULDCOUNT_IGNORED) { - log_info(LD_BUG, - "Circuit %d is now being counted despite being ignored " - "in the past. Purpose is %s, path state is %s", - circ->global_identifier, - circuit_purpose_to_string(circ->base_.purpose), - pathbias_state_to_string(circ->path_state)); + log_info(LD_CIRC, + "Circuit %d is not being counted by pathbias because it was " + "ignored in the past. Purpose is %s, path state is %s", + circ->global_identifier, + circuit_purpose_to_string(circ->base_.purpose), + pathbias_state_to_string(circ->path_state)); + return 0; } circ->pathbias_shouldcount = PATHBIAS_SHOULDCOUNT_COUNTED; @@ -434,8 +438,9 @@ pathbias_count_build_attempt(origin_circuit_t *circ) if ((rate_msg = rate_limit_log(&circ_attempt_notice_limit, approx_time()))) { log_info(LD_BUG, - "Opened circuit is in strange path state %s. " + "Opened circuit %d is in strange path state %s. " "Circuit is a %s currently %s.%s", + circ->global_identifier, pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state), @@ -468,8 +473,9 @@ pathbias_count_build_attempt(origin_circuit_t *circ) if ((rate_msg = rate_limit_log(&circ_attempt_notice_limit, approx_time()))) { log_info(LD_BUG, - "Unopened circuit has strange path state %s. " + "Unopened circuit %d has strange path state %s. " "Circuit is a %s currently %s.%s", + circ->global_identifier, pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state), @@ -538,8 +544,9 @@ pathbias_count_build_success(origin_circuit_t *circ) if ((rate_msg = rate_limit_log(&success_notice_limit, approx_time()))) { log_info(LD_BUG, - "Succeeded circuit is in strange path state %s. " + "Succeeded circuit %d is in strange path state %s. " "Circuit is a %s currently %s.%s", + circ->global_identifier, pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state), @@ -574,8 +581,9 @@ pathbias_count_build_success(origin_circuit_t *circ) if ((rate_msg = rate_limit_log(&success_notice_limit, approx_time()))) { log_info(LD_BUG, - "Opened circuit is in strange path state %s. " + "Opened circuit %d is in strange path state %s. " "Circuit is a %s currently %s.%s", + circ->global_identifier, pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state), @@ -601,8 +609,9 @@ pathbias_count_use_attempt(origin_circuit_t *circ) if (circ->path_state < PATH_STATE_BUILD_SUCCEEDED) { log_notice(LD_BUG, - "Used circuit is in strange path state %s. " + "Used circuit %d is in strange path state %s. " "Circuit is a %s currently %s.", + circ->global_identifier, pathbias_state_to_string(circ->path_state), circuit_purpose_to_string(circ->base_.purpose), circuit_state_to_string(circ->base_.state)); diff --git a/src/feature/client/dnsserv.c b/src/feature/client/dnsserv.c index 44e0caaafa..7fb3fff6c1 100644 --- a/src/feature/client/dnsserv.c +++ b/src/feature/client/dnsserv.c @@ -26,7 +26,7 @@ #include "app/config/config.h" #include "core/mainloop/connection.h" #include "core/or/connection_edge.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "core/mainloop/mainloop.h" #include "core/mainloop/netstatus.h" #include "core/or/policies.h" diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c index e543289ce0..54a9238d8f 100644 --- a/src/feature/client/entrynodes.c +++ b/src/feature/client/entrynodes.c @@ -128,7 +128,7 @@ #include "feature/client/circpathbias.h" #include "feature/client/entrynodes.h" #include "feature/client/transports.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dircommon/directory.h" #include "feature/nodelist/describe.h" #include "feature/nodelist/microdesc.h" @@ -2611,6 +2611,10 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs, entry_guard_t *guard = entry_guard_handle_get(state->guard); if (!guard || guard->in_selection != gs) continue; + if (TO_CIRCUIT(circ)->marked_for_close) { + /* Don't consider any marked for close circuits. */ + continue; + } smartlist_add(all_circuits, circ); } SMARTLIST_FOREACH_END(circ); @@ -3300,6 +3304,9 @@ num_bridges_usable,(int use_maybe_reachable)) } SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) { + /* Not a bridge, or not one we are configured to be able to use. */ + if (! guard->is_filtered_guard) + continue; /* Definitely not usable */ if (guard->is_reachable == GUARD_REACHABLE_NO) continue; diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c index e7ff3bf34a..97bfc8ae30 100644 --- a/src/feature/client/transports.c +++ b/src/feature/client/transports.c @@ -100,7 +100,7 @@ #include "app/config/statefile.h" #include "core/or/connection_or.h" #include "feature/relay/ext_orport.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "lib/encoding/confline.h" #include "lib/encoding/kvline.h" @@ -1424,11 +1424,6 @@ create_managed_proxy_environment(const managed_proxy_t *mp) } else { smartlist_add_asprintf(envs, "TOR_PT_EXTENDED_SERVER_PORT="); } - - /* All new versions of tor will keep stdin open, so PTs can use it - * as a reliable termination detection mechanism. - */ - smartlist_add_asprintf(envs, "TOR_PT_EXIT_ON_STDIN_CLOSE=1"); } else { /* If ClientTransportPlugin has a HTTPS/SOCKS proxy configured, set the * TOR_PT_PROXY line. @@ -1439,6 +1434,11 @@ create_managed_proxy_environment(const managed_proxy_t *mp) } } + /* All new versions of tor will keep stdin open, so PTs can use it + * as a reliable termination detection mechanism. + */ + smartlist_add_asprintf(envs, "TOR_PT_EXIT_ON_STDIN_CLOSE=1"); + SMARTLIST_FOREACH_BEGIN(envs, const char *, env_var) { set_environment_variable_in_smartlist(merged_env_vars, env_var, tor_free_, 1); diff --git a/src/feature/control/btrack_circuit.h b/src/feature/control/btrack_circuit.h index c40822f1f1..9e06fefb07 100644 --- a/src/feature/control/btrack_circuit.h +++ b/src/feature/control/btrack_circuit.h @@ -12,4 +12,4 @@ int btrack_circ_init(void); void btrack_circ_fini(void); -#endif /* defined(TOR_BTRACK_CIRCUIT_H) */ +#endif /* !defined(TOR_BTRACK_CIRCUIT_H) */ diff --git a/src/feature/control/btrack_orconn.h b/src/feature/control/btrack_orconn.h index 6ab4892a78..f8f5c1096c 100644 --- a/src/feature/control/btrack_orconn.h +++ b/src/feature/control/btrack_orconn.h @@ -30,9 +30,9 @@ typedef struct bt_orconn_t { bool is_onehop; /**< Is this for a one-hop circuit? */ } bt_orconn_t; -#endif /* defined(BTRACK_ORCONN_PRIVATE) */ +#endif /* defined(BTRACK_ORCONN_PRIVATE) */ int btrack_orconn_init(void); void btrack_orconn_fini(void); -#endif /* defined(TOR_BTRACK_ORCONN_H) */ +#endif /* !defined(TOR_BTRACK_ORCONN_H) */ diff --git a/src/feature/control/btrack_orconn_cevent.c b/src/feature/control/btrack_orconn_cevent.c index ee142f2873..535aa8f614 100644 --- a/src/feature/control/btrack_orconn_cevent.c +++ b/src/feature/control/btrack_orconn_cevent.c @@ -20,7 +20,7 @@ #include "core/or/orconn_event.h" #include "feature/control/btrack_orconn.h" #include "feature/control/btrack_orconn_cevent.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" /** * Have we completed our first OR connection? diff --git a/src/feature/control/btrack_orconn_cevent.h b/src/feature/control/btrack_orconn_cevent.h index f9d24633aa..afec55581e 100644 --- a/src/feature/control/btrack_orconn_cevent.h +++ b/src/feature/control/btrack_orconn_cevent.h @@ -7,6 +7,7 @@ **/ #ifndef TOR_BTRACK_ORCONN_CEVENT_H +#define TOR_BTRACK_ORCONN_CEVENT_H #include "feature/control/btrack_orconn.h" @@ -14,4 +15,4 @@ void bto_cevent_anyconn(const bt_orconn_t *); void bto_cevent_apconn(const bt_orconn_t *); void bto_cevent_reset(void); -#endif /* defined(TOR_BTRACK_ORCONN_CEVENT_H) */ +#endif /* !defined(TOR_BTRACK_ORCONN_CEVENT_H) */ diff --git a/src/feature/control/btrack_orconn_maps.h b/src/feature/control/btrack_orconn_maps.h index 3ead40984c..c2043fa153 100644 --- a/src/feature/control/btrack_orconn_maps.h +++ b/src/feature/control/btrack_orconn_maps.h @@ -7,6 +7,7 @@ **/ #ifndef TOR_BTRACK_ORCONN_MAPS_H +#define TOR_BTRACK_ORCONN_MAPS_H void bto_delete(uint64_t); bt_orconn_t *bto_find_or_new(uint64_t, uint64_t); @@ -14,4 +15,4 @@ bt_orconn_t *bto_find_or_new(uint64_t, uint64_t); void bto_init_maps(void); void bto_clear_maps(void); -#endif /* defined(TOR_BTRACK_ORCONN_MAPS_H) */ +#endif /* !defined(TOR_BTRACK_ORCONN_MAPS_H) */ diff --git a/src/feature/control/btrack_sys.h b/src/feature/control/btrack_sys.h index fad35b41db..3f831d0640 100644 --- a/src/feature/control/btrack_sys.h +++ b/src/feature/control/btrack_sys.h @@ -11,4 +11,4 @@ extern const struct subsys_fns_t sys_btrack; -#endif /* defined(TOR_BTRACK_SYS_H) */ +#endif /* !defined(TOR_BTRACK_SYS_H) */ diff --git a/src/feature/control/control.c b/src/feature/control/control.c index 6f8cd8f0aa..436bf423cf 100644 --- a/src/feature/control/control.c +++ b/src/feature/control/control.c @@ -1,4 +1,3 @@ - /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2019, The Tor Project, Inc. */ /* See LICENSE for licensing information */ @@ -33,86 +32,27 @@ * stack. **/ +#define CONTROL_MODULE_PRIVATE #define CONTROL_PRIVATE -#define OCIRC_EVENT_PRIVATE #include "core/or/or.h" #include "app/config/config.h" -#include "app/config/confparse.h" #include "app/main/main.h" #include "core/mainloop/connection.h" #include "core/mainloop/mainloop.h" -#include "core/or/channel.h" -#include "core/or/channeltls.h" -#include "core/or/circuitbuild.h" -#include "core/or/circuitlist.h" -#include "core/or/circuitstats.h" -#include "core/or/circuituse.h" -#include "core/or/command.h" -#include "core/or/connection_edge.h" #include "core/or/connection_or.h" -#include "core/or/ocirc_event.h" -#include "core/or/policies.h" -#include "core/or/reasons.h" -#include "core/or/versions.h" #include "core/proto/proto_control0.h" #include "core/proto/proto_http.h" -#include "feature/client/addressmap.h" -#include "feature/client/bridges.h" -#include "feature/client/dnsserv.h" -#include "feature/client/entrynodes.h" #include "feature/control/control.h" -#include "feature/control/fmt_serverstatus.h" -#include "feature/control/getinfo_geoip.h" -#include "feature/dircache/dirserv.h" -#include "feature/dirclient/dirclient.h" -#include "feature/dirclient/dlstatus.h" -#include "feature/dircommon/directory.h" -#include "feature/hibernate/hibernate.h" -#include "feature/hs/hs_cache.h" -#include "feature/hs/hs_common.h" -#include "feature/hs/hs_control.h" -#include "feature/hs_common/shared_random_client.h" -#include "feature/nodelist/authcert.h" -#include "feature/nodelist/dirlist.h" -#include "feature/nodelist/microdesc.h" -#include "feature/nodelist/networkstatus.h" -#include "feature/nodelist/nodelist.h" -#include "feature/nodelist/routerinfo.h" -#include "feature/nodelist/routerlist.h" -#include "feature/relay/router.h" -#include "feature/relay/routermode.h" -#include "feature/relay/selftest.h" -#include "feature/rend/rendclient.h" +#include "feature/control/control_auth.h" +#include "feature/control/control_cmd.h" +#include "feature/control/control_events.h" +#include "feature/control/control_proto.h" #include "feature/rend/rendcommon.h" -#include "feature/rend/rendparse.h" #include "feature/rend/rendservice.h" -#include "feature/stats/geoip_stats.h" -#include "feature/stats/predict_ports.h" -#include "lib/buf/buffers.h" -#include "lib/crypt_ops/crypto_rand.h" -#include "lib/crypt_ops/crypto_util.h" -#include "lib/encoding/confline.h" -#include "lib/evloop/compat_libevent.h" -#include "lib/version/torversion.h" +#include "lib/evloop/procmon.h" -#include "feature/dircache/cached_dir_st.h" #include "feature/control/control_connection_st.h" -#include "core/or/cpath_build_state_st.h" -#include "core/or/entry_connection_st.h" -#include "feature/nodelist/extrainfo_st.h" -#include "feature/nodelist/networkstatus_st.h" -#include "feature/nodelist/node_st.h" -#include "core/or/or_connection_st.h" -#include "core/or/or_circuit_st.h" -#include "core/or/origin_circuit_st.h" -#include "feature/nodelist/microdesc_st.h" -#include "feature/rend/rend_authorized_client_st.h" -#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" -#include "feature/rend/rend_service_descriptor_st.h" -#include "feature/nodelist/routerinfo_st.h" -#include "feature/nodelist/routerlist_st.h" -#include "core/or/socks_request_st.h" #ifdef HAVE_UNISTD_H #include @@ -121,145 +61,6 @@ #include #endif -#ifndef _WIN32 -#include -#include -#endif - -#include "lib/crypt_ops/crypto_s2k.h" -#include "lib/evloop/procmon.h" -#include "lib/evloop/compat_libevent.h" - -/** Yield true iff s is the state of a control_connection_t that has - * finished authentication and is accepting commands. */ -#define STATE_IS_OPEN(s) ((s) == CONTROL_CONN_STATE_OPEN) - -/** Bitfield: The bit 1<<e is set if any open control - * connection is interested in events of type e. We use this - * so that we can decide to skip generating event messages that nobody - * has interest in without having to walk over the global connection - * list to find out. - **/ -typedef uint64_t event_mask_t; - -/** An event mask of all the events that any controller is interested in - * receiving. */ -static event_mask_t global_event_mask = 0; - -/** True iff we have disabled log messages from being sent to the controller */ -static int disable_log_messages = 0; - -/** Macro: true if any control connection is interested in events of type - * e. */ -#define EVENT_IS_INTERESTING(e) \ - (!! (global_event_mask & EVENT_MASK_(e))) - -/** Macro: true if any event from the bitfield 'e' is interesting. */ -#define ANY_EVENT_IS_INTERESTING(e) \ - (!! (global_event_mask & (e))) - -/** If we're using cookie-type authentication, how long should our cookies be? - */ -#define AUTHENTICATION_COOKIE_LEN 32 - -/** If true, we've set authentication_cookie to a secret code and - * stored it to disk. */ -static int authentication_cookie_is_set = 0; -/** If authentication_cookie_is_set, a secret cookie that we've stored to disk - * and which we're using to authenticate controllers. (If the controller can - * read it off disk, it has permission to connect.) */ -static uint8_t *authentication_cookie = NULL; - -#define SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT \ - "Tor safe cookie authentication server-to-controller hash" -#define SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT \ - "Tor safe cookie authentication controller-to-server hash" -#define SAFECOOKIE_SERVER_NONCE_LEN DIGEST256_LEN - -/** The list of onion services that have been added via ADD_ONION that do not - * belong to any particular control connection. - */ -static smartlist_t *detached_onion_services = NULL; - -static void connection_printf_to_buf(control_connection_t *conn, - const char *format, ...) - CHECK_PRINTF(2,3); -static void send_control_event_impl(uint16_t event, - const char *format, va_list ap) - CHECK_PRINTF(2,0); -static int control_event_status(int type, int severity, const char *format, - va_list args) - CHECK_PRINTF(3,0); - -static void send_control_done(control_connection_t *conn); -static void send_control_event(uint16_t event, - const char *format, ...) - CHECK_PRINTF(2,3); -static int handle_control_setconf(control_connection_t *conn, uint32_t len, - char *body); -static int handle_control_resetconf(control_connection_t *conn, uint32_t len, - char *body); -static int handle_control_getconf(control_connection_t *conn, uint32_t len, - const char *body); -static int handle_control_loadconf(control_connection_t *conn, uint32_t len, - const char *body); -static int handle_control_setevents(control_connection_t *conn, uint32_t len, - const char *body); -static int handle_control_authenticate(control_connection_t *conn, - uint32_t len, - const char *body); -static int handle_control_signal(control_connection_t *conn, uint32_t len, - const char *body); -static int handle_control_mapaddress(control_connection_t *conn, uint32_t len, - const char *body); -static char *list_getinfo_options(void); -static int handle_control_getinfo(control_connection_t *conn, uint32_t len, - const char *body); -static int handle_control_extendcircuit(control_connection_t *conn, - uint32_t len, - const char *body); -static int handle_control_setcircuitpurpose(control_connection_t *conn, - uint32_t len, const char *body); -static int handle_control_attachstream(control_connection_t *conn, - uint32_t len, - const char *body); -static int handle_control_postdescriptor(control_connection_t *conn, - uint32_t len, - const char *body); -static int handle_control_redirectstream(control_connection_t *conn, - uint32_t len, - const char *body); -static int handle_control_closestream(control_connection_t *conn, uint32_t len, - const char *body); -static int handle_control_closecircuit(control_connection_t *conn, - uint32_t len, - const char *body); -static int handle_control_resolve(control_connection_t *conn, uint32_t len, - const char *body); -static int handle_control_usefeature(control_connection_t *conn, - uint32_t len, - const char *body); -static int handle_control_hsfetch(control_connection_t *conn, uint32_t len, - const char *body); -static int handle_control_hspost(control_connection_t *conn, uint32_t len, - const char *body); -static int handle_control_add_onion(control_connection_t *conn, uint32_t len, - const char *body); -static int handle_control_del_onion(control_connection_t *conn, uint32_t len, - const char *body); -static int write_stream_target_to_buf(entry_connection_t *conn, char *buf, - size_t len); -static void orconn_target_get_name(char *buf, size_t len, - or_connection_t *conn); - -static int get_cached_network_liveness(void); -static void set_cached_network_liveness(int liveness); - -static void flush_queued_events_cb(mainloop_event_t *event, void *arg); - -static char * download_status_to_string(const download_status_t *dl); -static void control_get_bytes_rw_last_sec(uint64_t *r, uint64_t *w); - /** Convert a connection_t* to an control_connection_t*; assert if the cast is * invalid. */ control_connection_t * @@ -269,410 +70,6 @@ TO_CONTROL_CONN(connection_t *c) return DOWNCAST(control_connection_t, c); } -/** Given a control event code for a message event, return the corresponding - * log severity. */ -static inline int -event_to_log_severity(int event) -{ - switch (event) { - case EVENT_DEBUG_MSG: return LOG_DEBUG; - case EVENT_INFO_MSG: return LOG_INFO; - case EVENT_NOTICE_MSG: return LOG_NOTICE; - case EVENT_WARN_MSG: return LOG_WARN; - case EVENT_ERR_MSG: return LOG_ERR; - default: return -1; - } -} - -/** Given a log severity, return the corresponding control event code. */ -static inline int -log_severity_to_event(int severity) -{ - switch (severity) { - case LOG_DEBUG: return EVENT_DEBUG_MSG; - case LOG_INFO: return EVENT_INFO_MSG; - case LOG_NOTICE: return EVENT_NOTICE_MSG; - case LOG_WARN: return EVENT_WARN_MSG; - case LOG_ERR: return EVENT_ERR_MSG; - default: return -1; - } -} - -/** Helper: clear bandwidth counters of all origin circuits. */ -static void -clear_circ_bw_fields(void) -{ - origin_circuit_t *ocirc; - SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { - if (!CIRCUIT_IS_ORIGIN(circ)) - continue; - ocirc = TO_ORIGIN_CIRCUIT(circ); - ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0; - ocirc->n_overhead_written_circ_bw = ocirc->n_overhead_read_circ_bw = 0; - ocirc->n_delivered_written_circ_bw = ocirc->n_delivered_read_circ_bw = 0; - } - SMARTLIST_FOREACH_END(circ); -} - -/** Set global_event_mask* to the bitwise OR of each live control - * connection's event_mask field. */ -void -control_update_global_event_mask(void) -{ - smartlist_t *conns = get_connection_array(); - event_mask_t old_mask, new_mask; - old_mask = global_event_mask; - int any_old_per_sec_events = control_any_per_second_event_enabled(); - - global_event_mask = 0; - SMARTLIST_FOREACH(conns, connection_t *, _conn, - { - if (_conn->type == CONN_TYPE_CONTROL && - STATE_IS_OPEN(_conn->state)) { - control_connection_t *conn = TO_CONTROL_CONN(_conn); - global_event_mask |= conn->event_mask; - } - }); - - new_mask = global_event_mask; - - /* Handle the aftermath. Set up the log callback to tell us only what - * we want to hear...*/ - control_adjust_event_log_severity(); - - /* Macro: true if ev was false before and is true now. */ -#define NEWLY_ENABLED(ev) \ - (! (old_mask & (ev)) && (new_mask & (ev))) - - /* ...then, if we've started logging stream or circ bw, clear the - * appropriate fields. */ - if (NEWLY_ENABLED(EVENT_STREAM_BANDWIDTH_USED)) { - SMARTLIST_FOREACH(conns, connection_t *, conn, - { - if (conn->type == CONN_TYPE_AP) { - edge_connection_t *edge_conn = TO_EDGE_CONN(conn); - edge_conn->n_written = edge_conn->n_read = 0; - } - }); - } - if (NEWLY_ENABLED(EVENT_CIRC_BANDWIDTH_USED)) { - clear_circ_bw_fields(); - } - if (NEWLY_ENABLED(EVENT_BANDWIDTH_USED)) { - uint64_t r, w; - control_get_bytes_rw_last_sec(&r, &w); - } - if (any_old_per_sec_events != control_any_per_second_event_enabled()) { - rescan_periodic_events(get_options()); - } - -#undef NEWLY_ENABLED -} - -/** Adjust the log severities that result in control_event_logmsg being called - * to match the severity of log messages that any controllers are interested - * in. */ -void -control_adjust_event_log_severity(void) -{ - int i; - int min_log_event=EVENT_ERR_MSG, max_log_event=EVENT_DEBUG_MSG; - - for (i = EVENT_DEBUG_MSG; i <= EVENT_ERR_MSG; ++i) { - if (EVENT_IS_INTERESTING(i)) { - min_log_event = i; - break; - } - } - for (i = EVENT_ERR_MSG; i >= EVENT_DEBUG_MSG; --i) { - if (EVENT_IS_INTERESTING(i)) { - max_log_event = i; - break; - } - } - if (EVENT_IS_INTERESTING(EVENT_STATUS_GENERAL)) { - if (min_log_event > EVENT_NOTICE_MSG) - min_log_event = EVENT_NOTICE_MSG; - if (max_log_event < EVENT_ERR_MSG) - max_log_event = EVENT_ERR_MSG; - } - if (min_log_event <= max_log_event) - change_callback_log_severity(event_to_log_severity(min_log_event), - event_to_log_severity(max_log_event), - control_event_logmsg); - else - change_callback_log_severity(LOG_ERR, LOG_ERR, - control_event_logmsg); -} - -/** Return true iff the event with code c is being sent to any current - * control connection. This is useful if the amount of work needed to prepare - * to call the appropriate control_event_...() function is high. - */ -int -control_event_is_interesting(int event) -{ - return EVENT_IS_INTERESTING(event); -} - -/** Return true if any event that needs to fire once a second is enabled. */ -int -control_any_per_second_event_enabled(void) -{ - return ANY_EVENT_IS_INTERESTING( - EVENT_MASK_(EVENT_BANDWIDTH_USED) | - EVENT_MASK_(EVENT_CELL_STATS) | - EVENT_MASK_(EVENT_CIRC_BANDWIDTH_USED) | - EVENT_MASK_(EVENT_CONN_BW) | - EVENT_MASK_(EVENT_STREAM_BANDWIDTH_USED) - ); -} - -/* The value of 'get_bytes_read()' the previous time that - * control_get_bytes_rw_last_sec() as called. */ -static uint64_t stats_prev_n_read = 0; -/* The value of 'get_bytes_written()' the previous time that - * control_get_bytes_rw_last_sec() as called. */ -static uint64_t stats_prev_n_written = 0; - -/** - * Set n_read and n_written to the total number of bytes read - * and written by Tor since the last call to this function. - * - * Call this only from the main thread. - */ -static void -control_get_bytes_rw_last_sec(uint64_t *n_read, - uint64_t *n_written) -{ - const uint64_t stats_n_bytes_read = get_bytes_read(); - const uint64_t stats_n_bytes_written = get_bytes_written(); - - *n_read = stats_n_bytes_read - stats_prev_n_read; - *n_written = stats_n_bytes_written - stats_prev_n_written; - stats_prev_n_read = stats_n_bytes_read; - stats_prev_n_written = stats_n_bytes_written; -} - -/** - * Run all the controller events (if any) that are scheduled to trigger once - * per second. - */ -void -control_per_second_events(void) -{ - if (!control_any_per_second_event_enabled()) - return; - - uint64_t bytes_read, bytes_written; - control_get_bytes_rw_last_sec(&bytes_read, &bytes_written); - control_event_bandwidth_used((uint32_t)bytes_read,(uint32_t)bytes_written); - - control_event_stream_bandwidth_used(); - control_event_conn_bandwidth_used(); - control_event_circ_bandwidth_used(); - control_event_circuit_cell_stats(); -} - -/** Append a NUL-terminated string s to the end of - * conn-\>outbuf. - */ -static inline void -connection_write_str_to_buf(const char *s, control_connection_t *conn) -{ - size_t len = strlen(s); - connection_buf_add(s, len, TO_CONN(conn)); -} - -/** Given a len-character string in data, made of lines - * terminated by CRLF, allocate a new string in *out, and copy the - * contents of data into *out, adding a period before any period - * that appears at the start of a line, and adding a period-CRLF line at - * the end. Replace all LF characters sequences with CRLF. Return the number - * of bytes in *out. - */ -STATIC size_t -write_escaped_data(const char *data, size_t len, char **out) -{ - tor_assert(len < SIZE_MAX - 9); - size_t sz_out = len+8+1; - char *outp; - const char *start = data, *end; - size_t i; - int start_of_line; - for (i=0; i < len; ++i) { - if (data[i] == '\n') { - sz_out += 2; /* Maybe add a CR; maybe add a dot. */ - if (sz_out >= SIZE_T_CEILING) { - log_warn(LD_BUG, "Input to write_escaped_data was too long"); - *out = tor_strdup(".\r\n"); - return 3; - } - } - } - *out = outp = tor_malloc(sz_out); - end = data+len; - start_of_line = 1; - while (data < end) { - if (*data == '\n') { - if (data > start && data[-1] != '\r') - *outp++ = '\r'; - start_of_line = 1; - } else if (*data == '.') { - if (start_of_line) { - start_of_line = 0; - *outp++ = '.'; - } - } else { - start_of_line = 0; - } - *outp++ = *data++; - } - if (outp < *out+2 || fast_memcmp(outp-2, "\r\n", 2)) { - *outp++ = '\r'; - *outp++ = '\n'; - } - *outp++ = '.'; - *outp++ = '\r'; - *outp++ = '\n'; - *outp = '\0'; /* NUL-terminate just in case. */ - tor_assert(outp >= *out); - tor_assert((size_t)(outp - *out) <= sz_out); - return outp - *out; -} - -/** Given a len-character string in data, made of lines - * terminated by CRLF, allocate a new string in *out, and copy - * the contents of data into *out, removing any period - * that appears at the start of a line, and replacing all CRLF sequences - * with LF. Return the number of - * bytes in *out. */ -STATIC size_t -read_escaped_data(const char *data, size_t len, char **out) -{ - char *outp; - const char *next; - const char *end; - - *out = outp = tor_malloc(len+1); - - end = data+len; - - while (data < end) { - /* we're at the start of a line. */ - if (*data == '.') - ++data; - next = memchr(data, '\n', end-data); - if (next) { - size_t n_to_copy = next-data; - /* Don't copy a CR that precedes this LF. */ - if (n_to_copy && *(next-1) == '\r') - --n_to_copy; - memcpy(outp, data, n_to_copy); - outp += n_to_copy; - data = next+1; /* This will point at the start of the next line, - * or the end of the string, or a period. */ - } else { - memcpy(outp, data, end-data); - outp += (end-data); - *outp = '\0'; - return outp - *out; - } - *outp++ = '\n'; - } - - *outp = '\0'; - return outp - *out; -} - -/** If the first in_len_max characters in start contain a - * double-quoted string with escaped characters, return the length of that - * string (as encoded, including quotes). Otherwise return -1. */ -static inline int -get_escaped_string_length(const char *start, size_t in_len_max, - int *chars_out) -{ - const char *cp, *end; - int chars = 0; - - if (*start != '\"') - return -1; - - cp = start+1; - end = start+in_len_max; - - /* Calculate length. */ - while (1) { - if (cp >= end) { - return -1; /* Too long. */ - } else if (*cp == '\\') { - if (++cp == end) - return -1; /* Can't escape EOS. */ - ++cp; - ++chars; - } else if (*cp == '\"') { - break; - } else { - ++cp; - ++chars; - } - } - if (chars_out) - *chars_out = chars; - return (int)(cp - start+1); -} - -/** As decode_escaped_string, but does not decode the string: copies the - * entire thing, including quotation marks. */ -static const char * -extract_escaped_string(const char *start, size_t in_len_max, - char **out, size_t *out_len) -{ - int length = get_escaped_string_length(start, in_len_max, NULL); - if (length<0) - return NULL; - *out_len = length; - *out = tor_strndup(start, *out_len); - return start+length; -} - -/** Given a pointer to a string starting at start containing - * in_len_max characters, decode a string beginning with one double - * quote, containing any number of non-quote characters or characters escaped - * with a backslash, and ending with a final double quote. Place the resulting - * string (unquoted, unescaped) into a newly allocated string in *out; - * store its length in out_len. On success, return a pointer to the - * character immediately following the escaped string. On failure, return - * NULL. */ -static const char * -decode_escaped_string(const char *start, size_t in_len_max, - char **out, size_t *out_len) -{ - const char *cp, *end; - char *outp; - int len, n_chars = 0; - - len = get_escaped_string_length(start, in_len_max, &n_chars); - if (len<0) - return NULL; - - end = start+len-1; /* Index of last quote. */ - tor_assert(*end == '\"'); - outp = *out = tor_malloc(len+1); - *out_len = n_chars; - - cp = start+1; - while (cp < end) { - if (*cp == '\\') - ++cp; - *outp++ = *cp++; - } - *outp = '\0'; - tor_assert((outp - *out) == (int)*out_len); - - return end+1; -} - /** Create and add a new controller connection on sock. If * CC_LOCAL_FD_IS_OWNER is set in flags, this Tor process should * exit when the connection closes. If CC_LOCAL_FD_IS_AUTHENTICATED @@ -716,29 +113,6 @@ control_connection_add_local_fd(tor_socket_t sock, unsigned flags) return 0; } -/** Acts like sprintf, but writes its formatted string to the end of - * conn-\>outbuf. */ -static void -connection_printf_to_buf(control_connection_t *conn, const char *format, ...) -{ - va_list ap; - char *buf = NULL; - int len; - - va_start(ap,format); - len = tor_vasprintf(&buf, format, ap); - va_end(ap); - - if (len < 0) { - log_err(LD_BUG, "Unable to format string for controller."); - tor_assert(0); - } - - connection_buf_add(buf, (size_t)len, TO_CONN(conn)); - - tor_free(buf); -} - /** Write all of the open control ports to ControlPortWriteToFile */ void control_ports_write_to_file(void) @@ -783,6178 +157,345 @@ control_ports_write_to_file(void) smartlist_free(lines); } -/** Send a "DONE" message down the control connection conn. */ -static void -send_control_done(control_connection_t *conn) +const struct signal_name_t signal_table[] = { + { SIGHUP, "RELOAD" }, + { SIGHUP, "HUP" }, + { SIGINT, "SHUTDOWN" }, + { SIGUSR1, "DUMP" }, + { SIGUSR1, "USR1" }, + { SIGUSR2, "DEBUG" }, + { SIGUSR2, "USR2" }, + { SIGTERM, "HALT" }, + { SIGTERM, "TERM" }, + { SIGTERM, "INT" }, + { SIGNEWNYM, "NEWNYM" }, + { SIGCLEARDNSCACHE, "CLEARDNSCACHE"}, + { SIGHEARTBEAT, "HEARTBEAT"}, + { SIGACTIVE, "ACTIVE" }, + { SIGDORMANT, "DORMANT" }, + { 0, NULL }, +}; + +/** Called when conn has no more bytes left on its outbuf. */ +int +connection_control_finished_flushing(control_connection_t *conn) { - connection_write_str_to_buf("250 OK\r\n", conn); + tor_assert(conn); + return 0; } -/** Represents an event that's queued to be sent to one or more - * controllers. */ -typedef struct queued_event_s { - uint16_t event; - char *msg; -} queued_event_t; - -/** Pointer to int. If this is greater than 0, we don't allow new events to be - * queued. */ -static tor_threadlocal_t block_event_queue_flag; - -/** Holds a smartlist of queued_event_t objects that may need to be sent - * to one or more controllers */ -static smartlist_t *queued_control_events = NULL; +/** Called when conn has gotten its socket closed. */ +int +connection_control_reached_eof(control_connection_t *conn) +{ + tor_assert(conn); -/** True if the flush_queued_events_event is pending. */ -static int flush_queued_event_pending = 0; + log_info(LD_CONTROL,"Control connection reached EOF. Closing."); + connection_mark_for_close(TO_CONN(conn)); + return 0; +} -/** Lock to protect the above fields. */ -static tor_mutex_t *queued_control_events_lock = NULL; +/** Shut down this Tor instance in the same way that SIGINT would, but + * with a log message appropriate for the loss of an owning controller. */ +static void +lost_owning_controller(const char *owner_type, const char *loss_manner) +{ + log_notice(LD_CONTROL, "Owning controller %s has %s -- exiting now.", + owner_type, loss_manner); -/** An event that should fire in order to flush the contents of - * queued_control_events. */ -static mainloop_event_t *flush_queued_events_event = NULL; + activate_signal(SIGTERM); +} +/** Called when conn is being freed. */ void -control_initialize_event_queue(void) +connection_control_closed(control_connection_t *conn) { - if (queued_control_events == NULL) { - queued_control_events = smartlist_new(); - } + tor_assert(conn); - if (flush_queued_events_event == NULL) { - struct event_base *b = tor_libevent_get_base(); - if (b) { - flush_queued_events_event = - mainloop_event_new(flush_queued_events_cb, NULL); - tor_assert(flush_queued_events_event); - } + conn->event_mask = 0; + control_update_global_event_mask(); + + /* Close all ephemeral Onion Services if any. + * The list and it's contents are scrubbed/freed in connection_free_. + */ + if (conn->ephemeral_onion_services) { + SMARTLIST_FOREACH_BEGIN(conn->ephemeral_onion_services, char *, cp) { + if (rend_valid_v2_service_id(cp)) { + rend_service_del_ephemeral(cp); + } else if (hs_address_is_valid(cp)) { + hs_service_del_ephemeral(cp); + } else { + /* An invalid .onion in our list should NEVER happen */ + tor_fragile_assert(); + } + } SMARTLIST_FOREACH_END(cp); } - if (queued_control_events_lock == NULL) { - queued_control_events_lock = tor_mutex_new(); - tor_threadlocal_init(&block_event_queue_flag); + if (conn->is_owning_control_connection) { + lost_owning_controller("connection", "closed"); } } -static int * -get_block_event_queue(void) +/** Return true iff cmd is allowable (or at least forgivable) at this + * stage of the protocol. */ +static int +is_valid_initial_command(control_connection_t *conn, const char *cmd) { - int *val = tor_threadlocal_get(&block_event_queue_flag); - if (PREDICT_UNLIKELY(val == NULL)) { - val = tor_malloc_zero(sizeof(int)); - tor_threadlocal_set(&block_event_queue_flag, val); - } - return val; + if (conn->base_.state == CONTROL_CONN_STATE_OPEN) + return 1; + if (!strcasecmp(cmd, "PROTOCOLINFO")) + return (!conn->have_sent_protocolinfo && + conn->safecookie_client_hash == NULL); + if (!strcasecmp(cmd, "AUTHCHALLENGE")) + return (conn->safecookie_client_hash == NULL); + if (!strcasecmp(cmd, "AUTHENTICATE") || + !strcasecmp(cmd, "QUIT")) + return 1; + return 0; } -/** Helper: inserts an event on the list of events queued to be sent to - * one or more controllers, and schedules the events to be flushed if needed. - * - * This function takes ownership of msg, and may free it. - * - * We queue these events rather than send them immediately in order to break - * the dependency in our callgraph from code that generates events for the - * controller, and the network layer at large. Otherwise, nearly every - * interesting part of Tor would potentially call every other interesting part - * of Tor. +/** Do not accept any control command of more than 1MB in length. Anything + * that needs to be anywhere near this long probably means that one of our + * interfaces is broken. */ +#define MAX_COMMAND_LINE_LENGTH (1024*1024) + +/** Wrapper around peek_buf_has_control0 command: presents the same + * interface as that underlying functions, but takes a connection_t intead of + * a buf_t. */ -MOCK_IMPL(STATIC void, -queue_control_event_string,(uint16_t event, char *msg)) +static int +peek_connection_has_control0_command(connection_t *conn) { - /* This is redundant with checks done elsewhere, but it's a last-ditch - * attempt to avoid queueing something we shouldn't have to queue. */ - if (PREDICT_UNLIKELY( ! EVENT_IS_INTERESTING(event) )) { - tor_free(msg); - return; - } + return peek_buf_has_control0_command(conn->inbuf); +} - int *block_event_queue = get_block_event_queue(); - if (*block_event_queue) { - tor_free(msg); - return; - } - - queued_event_t *ev = tor_malloc(sizeof(*ev)); - ev->event = event; - ev->msg = msg; - - /* No queueing an event while queueing an event */ - ++*block_event_queue; - - tor_mutex_acquire(queued_control_events_lock); - tor_assert(queued_control_events); - smartlist_add(queued_control_events, ev); - - int activate_event = 0; - if (! flush_queued_event_pending && in_main_thread()) { - activate_event = 1; - flush_queued_event_pending = 1; - } - - tor_mutex_release(queued_control_events_lock); - - --*block_event_queue; - - /* We just put an event on the queue; mark the queue to be - * flushed. We only do this from the main thread for now; otherwise, - * we'd need to incur locking overhead in Libevent or use a socket. - */ - if (activate_event) { - tor_assert(flush_queued_events_event); - mainloop_event_activate(flush_queued_events_event); - } -} - -#define queued_event_free(ev) \ - FREE_AND_NULL(queued_event_t, queued_event_free_, (ev)) - -/** Release all storage held by ev. */ -static void -queued_event_free_(queued_event_t *ev) -{ - if (ev == NULL) - return; - - tor_free(ev->msg); - tor_free(ev); -} - -/** Send every queued event to every controller that's interested in it, - * and remove the events from the queue. If force is true, - * then make all controllers send their data out immediately, since we - * may be about to shut down. */ -static void -queued_events_flush_all(int force) -{ - /* Make sure that we get all the pending log events, if there are any. */ - flush_pending_log_callbacks(); - - if (PREDICT_UNLIKELY(queued_control_events == NULL)) { - return; - } - smartlist_t *all_conns = get_connection_array(); - smartlist_t *controllers = smartlist_new(); - smartlist_t *queued_events; - - int *block_event_queue = get_block_event_queue(); - ++*block_event_queue; - - tor_mutex_acquire(queued_control_events_lock); - /* No queueing an event while flushing events. */ - flush_queued_event_pending = 0; - queued_events = queued_control_events; - queued_control_events = smartlist_new(); - tor_mutex_release(queued_control_events_lock); - - /* Gather all the controllers that will care... */ - SMARTLIST_FOREACH_BEGIN(all_conns, connection_t *, conn) { - if (conn->type == CONN_TYPE_CONTROL && - !conn->marked_for_close && - conn->state == CONTROL_CONN_STATE_OPEN) { - control_connection_t *control_conn = TO_CONTROL_CONN(conn); - - smartlist_add(controllers, control_conn); - } - } SMARTLIST_FOREACH_END(conn); - - SMARTLIST_FOREACH_BEGIN(queued_events, queued_event_t *, ev) { - const event_mask_t bit = ((event_mask_t)1) << ev->event; - const size_t msg_len = strlen(ev->msg); - SMARTLIST_FOREACH_BEGIN(controllers, control_connection_t *, - control_conn) { - if (control_conn->event_mask & bit) { - connection_buf_add(ev->msg, msg_len, TO_CONN(control_conn)); - } - } SMARTLIST_FOREACH_END(control_conn); - - queued_event_free(ev); - } SMARTLIST_FOREACH_END(ev); - - if (force) { - SMARTLIST_FOREACH_BEGIN(controllers, control_connection_t *, - control_conn) { - connection_flush(TO_CONN(control_conn)); - } SMARTLIST_FOREACH_END(control_conn); - } - - smartlist_free(queued_events); - smartlist_free(controllers); - - --*block_event_queue; -} - -/** Libevent callback: Flushes pending events to controllers that are - * interested in them. */ -static void -flush_queued_events_cb(mainloop_event_t *event, void *arg) -{ - (void) event; - (void) arg; - queued_events_flush_all(0); -} - -/** Send an event to all v1 controllers that are listening for code - * event. The event's body is given by msg. - * - * The EXTENDED_FORMAT and NONEXTENDED_FORMAT flags behave similarly with - * respect to the EXTENDED_EVENTS feature. */ -MOCK_IMPL(STATIC void, -send_control_event_string,(uint16_t event, - const char *msg)) -{ - tor_assert(event >= EVENT_MIN_ && event <= EVENT_MAX_); - queue_control_event_string(event, tor_strdup(msg)); -} - -/** Helper for send_control_event and control_event_status: - * Send an event to all v1 controllers that are listening for code - * event. The event's body is created by the printf-style format in - * format, and other arguments as provided. */ -static void -send_control_event_impl(uint16_t event, - const char *format, va_list ap) -{ - char *buf = NULL; - int len; - - len = tor_vasprintf(&buf, format, ap); - if (len < 0) { - log_warn(LD_BUG, "Unable to format event for controller."); - return; - } - - queue_control_event_string(event, buf); -} - -/** Send an event to all v1 controllers that are listening for code - * event. The event's body is created by the printf-style format in - * format, and other arguments as provided. */ -static void -send_control_event(uint16_t event, - const char *format, ...) -{ - va_list ap; - va_start(ap, format); - send_control_event_impl(event, format, ap); - va_end(ap); -} - -/** Given a text circuit id, return the corresponding circuit. */ -static origin_circuit_t * -get_circ(const char *id) -{ - uint32_t n_id; - int ok; - n_id = (uint32_t) tor_parse_ulong(id, 10, 0, UINT32_MAX, &ok, NULL); - if (!ok) - return NULL; - return circuit_get_by_global_id(n_id); -} - -/** Given a text stream id, return the corresponding AP connection. */ -static entry_connection_t * -get_stream(const char *id) -{ - uint64_t n_id; - int ok; - connection_t *conn; - n_id = tor_parse_uint64(id, 10, 0, UINT64_MAX, &ok, NULL); - if (!ok) - return NULL; - conn = connection_get_by_global_id(n_id); - if (!conn || conn->type != CONN_TYPE_AP || conn->marked_for_close) - return NULL; - return TO_ENTRY_CONN(conn); -} - -/** Helper for setconf and resetconf. Acts like setconf, except - * it passes use_defaults on to options_trial_assign(). Modifies the - * contents of body. - */ -static int -control_setconf_helper(control_connection_t *conn, uint32_t len, char *body, - int use_defaults) -{ - setopt_err_t opt_err; - config_line_t *lines=NULL; - char *start = body; - char *errstring = NULL; - const unsigned flags = - CAL_CLEAR_FIRST | (use_defaults ? CAL_USE_DEFAULTS : 0); - - char *config; - smartlist_t *entries = smartlist_new(); - - /* We have a string, "body", of the format '(key(=val|="val")?)' entries - * separated by space. break it into a list of configuration entries. */ - while (*body) { - char *eq = body; - char *key; - char *entry; - while (!TOR_ISSPACE(*eq) && *eq != '=') - ++eq; - key = tor_strndup(body, eq-body); - body = eq+1; - if (*eq == '=') { - char *val=NULL; - size_t val_len=0; - if (*body != '\"') { - char *val_start = body; - while (!TOR_ISSPACE(*body)) - body++; - val = tor_strndup(val_start, body-val_start); - val_len = strlen(val); - } else { - body = (char*)extract_escaped_string(body, (len - (body-start)), - &val, &val_len); - if (!body) { - connection_write_str_to_buf("551 Couldn't parse string\r\n", conn); - SMARTLIST_FOREACH(entries, char *, cp, tor_free(cp)); - smartlist_free(entries); - tor_free(key); - return 0; - } - } - tor_asprintf(&entry, "%s %s", key, val); - tor_free(key); - tor_free(val); - } else { - entry = key; - } - smartlist_add(entries, entry); - while (TOR_ISSPACE(*body)) - ++body; - } - - smartlist_add_strdup(entries, ""); - config = smartlist_join_strings(entries, "\n", 0, NULL); - SMARTLIST_FOREACH(entries, char *, cp, tor_free(cp)); - smartlist_free(entries); - - if (config_get_lines(config, &lines, 0) < 0) { - log_warn(LD_CONTROL,"Controller gave us config lines we can't parse."); - connection_write_str_to_buf("551 Couldn't parse configuration\r\n", - conn); - tor_free(config); - return 0; - } - tor_free(config); - - opt_err = options_trial_assign(lines, flags, &errstring); - { - const char *msg; - switch (opt_err) { - case SETOPT_ERR_MISC: - msg = "552 Unrecognized option"; - break; - case SETOPT_ERR_PARSE: - msg = "513 Unacceptable option value"; - break; - case SETOPT_ERR_TRANSITION: - msg = "553 Transition not allowed"; - break; - case SETOPT_ERR_SETTING: - default: - msg = "553 Unable to set option"; - break; - case SETOPT_OK: - config_free_lines(lines); - send_control_done(conn); - return 0; - } - log_warn(LD_CONTROL, - "Controller gave us config lines that didn't validate: %s", - errstring); - connection_printf_to_buf(conn, "%s: %s\r\n", msg, errstring); - config_free_lines(lines); - tor_free(errstring); - return 0; - } -} - -/** Called when we receive a SETCONF message: parse the body and try - * to update our configuration. Reply with a DONE or ERROR message. - * Modifies the contents of body.*/ -static int -handle_control_setconf(control_connection_t *conn, uint32_t len, char *body) -{ - return control_setconf_helper(conn, len, body, 0); -} - -/** Called when we receive a RESETCONF message: parse the body and try - * to update our configuration. Reply with a DONE or ERROR message. - * Modifies the contents of body. */ -static int -handle_control_resetconf(control_connection_t *conn, uint32_t len, char *body) -{ - return control_setconf_helper(conn, len, body, 1); -} - -/** Called when we receive a GETCONF message. Parse the request, and - * reply with a CONFVALUE or an ERROR message */ -static int -handle_control_getconf(control_connection_t *conn, uint32_t body_len, - const char *body) -{ - smartlist_t *questions = smartlist_new(); - 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; - - (void) body_len; /* body is NUL-terminated; so we can ignore len. */ - smartlist_split_string(questions, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - SMARTLIST_FOREACH_BEGIN(questions, const char *, q) { - if (!option_is_recognized(q)) { - smartlist_add(unrecognized, (char*) 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); - } - - while (answer) { - config_line_t *next; - smartlist_add_asprintf(answers, "250-%s=%s\r\n", - answer->key, answer->value); - - next = answer->next; - tor_free(answer->key); - tor_free(answer->value); - tor_free(answer); - answer = next; - } - } - } SMARTLIST_FOREACH_END(q); - - if ((len = smartlist_len(unrecognized))) { - for (i=0; i < len-1; ++i) - connection_printf_to_buf(conn, - "552-Unrecognized configuration key \"%s\"\r\n", - (char*)smartlist_get(unrecognized, i)); - connection_printf_to_buf(conn, - "552 Unrecognized configuration key \"%s\"\r\n", - (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)); - } else { - connection_write_str_to_buf("250 OK\r\n", conn); - } - - SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp)); - smartlist_free(answers); - SMARTLIST_FOREACH(questions, char *, cp, tor_free(cp)); - smartlist_free(questions); - smartlist_free(unrecognized); - - tor_free(msg); - - return 0; -} - -/** Called when we get a +LOADCONF message. */ -static int -handle_control_loadconf(control_connection_t *conn, uint32_t len, - const char *body) -{ - setopt_err_t retval; - char *errstring = NULL; - const char *msg = NULL; - (void) len; - - retval = options_init_from_string(NULL, body, CMD_RUN_TOR, NULL, &errstring); - - if (retval != SETOPT_OK) - log_warn(LD_CONTROL, - "Controller gave us config file that didn't validate: %s", - errstring); - - switch (retval) { - case SETOPT_ERR_PARSE: - msg = "552 Invalid config file"; - break; - case SETOPT_ERR_TRANSITION: - msg = "553 Transition not allowed"; - break; - case SETOPT_ERR_SETTING: - msg = "553 Unable to set option"; - break; - case SETOPT_ERR_MISC: - default: - msg = "550 Unable to load config"; - break; - case SETOPT_OK: - break; - } - if (msg) { - if (errstring) - connection_printf_to_buf(conn, "%s: %s\r\n", msg, errstring); - else - connection_printf_to_buf(conn, "%s\r\n", msg); - } else { - send_control_done(conn); - } - tor_free(errstring); - return 0; -} - -/** Helper structure: maps event values to their names. */ -struct control_event_t { - uint16_t event_code; - const char *event_name; -}; -/** Table mapping event values to their names. Used to implement SETEVENTS - * and GETINFO events/names, and to keep they in sync. */ -static const struct control_event_t control_event_table[] = { - { EVENT_CIRCUIT_STATUS, "CIRC" }, - { EVENT_CIRCUIT_STATUS_MINOR, "CIRC_MINOR" }, - { EVENT_STREAM_STATUS, "STREAM" }, - { EVENT_OR_CONN_STATUS, "ORCONN" }, - { EVENT_BANDWIDTH_USED, "BW" }, - { EVENT_DEBUG_MSG, "DEBUG" }, - { EVENT_INFO_MSG, "INFO" }, - { EVENT_NOTICE_MSG, "NOTICE" }, - { EVENT_WARN_MSG, "WARN" }, - { EVENT_ERR_MSG, "ERR" }, - { EVENT_NEW_DESC, "NEWDESC" }, - { EVENT_ADDRMAP, "ADDRMAP" }, - { EVENT_DESCCHANGED, "DESCCHANGED" }, - { EVENT_NS, "NS" }, - { EVENT_STATUS_GENERAL, "STATUS_GENERAL" }, - { EVENT_STATUS_CLIENT, "STATUS_CLIENT" }, - { EVENT_STATUS_SERVER, "STATUS_SERVER" }, - { EVENT_GUARD, "GUARD" }, - { EVENT_STREAM_BANDWIDTH_USED, "STREAM_BW" }, - { EVENT_CLIENTS_SEEN, "CLIENTS_SEEN" }, - { EVENT_NEWCONSENSUS, "NEWCONSENSUS" }, - { EVENT_BUILDTIMEOUT_SET, "BUILDTIMEOUT_SET" }, - { EVENT_GOT_SIGNAL, "SIGNAL" }, - { EVENT_CONF_CHANGED, "CONF_CHANGED"}, - { EVENT_CONN_BW, "CONN_BW" }, - { EVENT_CELL_STATS, "CELL_STATS" }, - { EVENT_CIRC_BANDWIDTH_USED, "CIRC_BW" }, - { EVENT_TRANSPORT_LAUNCHED, "TRANSPORT_LAUNCHED" }, - { EVENT_HS_DESC, "HS_DESC" }, - { EVENT_HS_DESC_CONTENT, "HS_DESC_CONTENT" }, - { EVENT_NETWORK_LIVENESS, "NETWORK_LIVENESS" }, - { 0, NULL }, -}; - -/** Called when we get a SETEVENTS message: update conn->event_mask, - * and reply with DONE or ERROR. */ -static int -handle_control_setevents(control_connection_t *conn, uint32_t len, - const char *body) -{ - int event_code; - event_mask_t event_mask = 0; - smartlist_t *events = smartlist_new(); - - (void) len; - - smartlist_split_string(events, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - SMARTLIST_FOREACH_BEGIN(events, const char *, ev) - { - if (!strcasecmp(ev, "EXTENDED") || - !strcasecmp(ev, "AUTHDIR_NEWDESCS")) { - log_warn(LD_CONTROL, "The \"%s\" SETEVENTS argument is no longer " - "supported.", ev); - continue; - } else { - int i; - event_code = -1; - - for (i = 0; control_event_table[i].event_name != NULL; ++i) { - if (!strcasecmp(ev, control_event_table[i].event_name)) { - event_code = control_event_table[i].event_code; - break; - } - } - - if (event_code == -1) { - connection_printf_to_buf(conn, "552 Unrecognized event \"%s\"\r\n", - ev); - SMARTLIST_FOREACH(events, char *, e, tor_free(e)); - smartlist_free(events); - return 0; - } - } - event_mask |= (((event_mask_t)1) << event_code); - } - SMARTLIST_FOREACH_END(ev); - SMARTLIST_FOREACH(events, char *, e, tor_free(e)); - smartlist_free(events); - - conn->event_mask = event_mask; - - control_update_global_event_mask(); - send_control_done(conn); - return 0; -} - -/** Decode the hashed, base64'd passwords stored in passwords. - * Return a smartlist of acceptable passwords (unterminated strings of - * length S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) on success, or NULL on - * failure. - */ -smartlist_t * -decode_hashed_passwords(config_line_t *passwords) -{ - char decoded[64]; - config_line_t *cl; - smartlist_t *sl = smartlist_new(); - - tor_assert(passwords); - - for (cl = passwords; cl; cl = cl->next) { - const char *hashed = cl->value; - - if (!strcmpstart(hashed, "16:")) { - if (base16_decode(decoded, sizeof(decoded), hashed+3, strlen(hashed+3)) - != S2K_RFC2440_SPECIFIER_LEN + DIGEST_LEN - || strlen(hashed+3) != (S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN)*2) { - goto err; - } - } else { - if (base64_decode(decoded, sizeof(decoded), hashed, strlen(hashed)) - != S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) { - goto err; - } - } - smartlist_add(sl, - tor_memdup(decoded, S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN)); - } - - return sl; - - err: - SMARTLIST_FOREACH(sl, char*, cp, tor_free(cp)); - smartlist_free(sl); - return NULL; -} - -/** Called when we get an AUTHENTICATE message. Check whether the - * authentication is valid, and if so, update the connection's state to - * OPEN. Reply with DONE or ERROR. - */ -static int -handle_control_authenticate(control_connection_t *conn, uint32_t len, - const char *body) -{ - int used_quoted_string = 0; - const or_options_t *options = get_options(); - const char *errstr = "Unknown error"; - char *password; - size_t password_len; - const char *cp; - int i; - int bad_cookie=0, bad_password=0; - smartlist_t *sl = NULL; - - if (!len) { - password = tor_strdup(""); - password_len = 0; - } else if (TOR_ISXDIGIT(body[0])) { - cp = body; - while (TOR_ISXDIGIT(*cp)) - ++cp; - i = (int)(cp - body); - tor_assert(i>0); - password_len = i/2; - password = tor_malloc(password_len + 1); - if (base16_decode(password, password_len+1, body, i) - != (int) password_len) { - connection_write_str_to_buf( - "551 Invalid hexadecimal encoding. Maybe you tried a plain text " - "password? If so, the standard requires that you put it in " - "double quotes.\r\n", conn); - connection_mark_for_close(TO_CONN(conn)); - tor_free(password); - return 0; - } - } else { - if (!decode_escaped_string(body, len, &password, &password_len)) { - connection_write_str_to_buf("551 Invalid quoted string. You need " - "to put the password in double quotes.\r\n", conn); - connection_mark_for_close(TO_CONN(conn)); - return 0; - } - used_quoted_string = 1; - } - - if (conn->safecookie_client_hash != NULL) { - /* The controller has chosen safe cookie authentication; the only - * acceptable authentication value is the controller-to-server - * response. */ - - tor_assert(authentication_cookie_is_set); - - if (password_len != DIGEST256_LEN) { - log_warn(LD_CONTROL, - "Got safe cookie authentication response with wrong length " - "(%d)", (int)password_len); - errstr = "Wrong length for safe cookie response."; - goto err; - } - - if (tor_memneq(conn->safecookie_client_hash, password, DIGEST256_LEN)) { - log_warn(LD_CONTROL, - "Got incorrect safe cookie authentication response"); - errstr = "Safe cookie response did not match expected value."; - goto err; - } - - tor_free(conn->safecookie_client_hash); - goto ok; - } - - if (!options->CookieAuthentication && !options->HashedControlPassword && - !options->HashedControlSessionPassword) { - /* if Tor doesn't demand any stronger authentication, then - * the controller can get in with anything. */ - goto ok; - } - - if (options->CookieAuthentication) { - int also_password = options->HashedControlPassword != NULL || - options->HashedControlSessionPassword != NULL; - if (password_len != AUTHENTICATION_COOKIE_LEN) { - if (!also_password) { - log_warn(LD_CONTROL, "Got authentication cookie with wrong length " - "(%d)", (int)password_len); - errstr = "Wrong length on authentication cookie."; - goto err; - } - bad_cookie = 1; - } else if (tor_memneq(authentication_cookie, password, password_len)) { - if (!also_password) { - log_warn(LD_CONTROL, "Got mismatched authentication cookie"); - errstr = "Authentication cookie did not match expected value."; - goto err; - } - bad_cookie = 1; - } else { - goto ok; - } - } - - if (options->HashedControlPassword || - options->HashedControlSessionPassword) { - int bad = 0; - smartlist_t *sl_tmp; - char received[DIGEST_LEN]; - int also_cookie = options->CookieAuthentication; - sl = smartlist_new(); - if (options->HashedControlPassword) { - sl_tmp = decode_hashed_passwords(options->HashedControlPassword); - if (!sl_tmp) - bad = 1; - else { - smartlist_add_all(sl, sl_tmp); - smartlist_free(sl_tmp); - } - } - if (options->HashedControlSessionPassword) { - sl_tmp = decode_hashed_passwords(options->HashedControlSessionPassword); - if (!sl_tmp) - bad = 1; - else { - smartlist_add_all(sl, sl_tmp); - smartlist_free(sl_tmp); - } - } - if (bad) { - if (!also_cookie) { - log_warn(LD_BUG, - "Couldn't decode HashedControlPassword: invalid base16"); - errstr="Couldn't decode HashedControlPassword value in configuration."; - goto err; - } - bad_password = 1; - SMARTLIST_FOREACH(sl, char *, str, tor_free(str)); - smartlist_free(sl); - sl = NULL; - } else { - SMARTLIST_FOREACH(sl, char *, expected, - { - secret_to_key_rfc2440(received,DIGEST_LEN, - password,password_len,expected); - if (tor_memeq(expected + S2K_RFC2440_SPECIFIER_LEN, - received, DIGEST_LEN)) - goto ok; - }); - SMARTLIST_FOREACH(sl, char *, str, tor_free(str)); - smartlist_free(sl); - sl = NULL; - - if (used_quoted_string) - errstr = "Password did not match HashedControlPassword value from " - "configuration"; - else - errstr = "Password did not match HashedControlPassword value from " - "configuration. Maybe you tried a plain text password? " - "If so, the standard requires that you put it in double quotes."; - bad_password = 1; - if (!also_cookie) - goto err; - } - } - - /** We only get here if both kinds of authentication failed. */ - tor_assert(bad_password && bad_cookie); - log_warn(LD_CONTROL, "Bad password or authentication cookie on controller."); - errstr = "Password did not match HashedControlPassword *or* authentication " - "cookie."; - - err: - tor_free(password); - connection_printf_to_buf(conn, "515 Authentication failed: %s\r\n", errstr); - connection_mark_for_close(TO_CONN(conn)); - if (sl) { /* clean up */ - SMARTLIST_FOREACH(sl, char *, str, tor_free(str)); - smartlist_free(sl); - } - return 0; - ok: - log_info(LD_CONTROL, "Authenticated control connection ("TOR_SOCKET_T_FORMAT - ")", conn->base_.s); - send_control_done(conn); - conn->base_.state = CONTROL_CONN_STATE_OPEN; - tor_free(password); - if (sl) { /* clean up */ - SMARTLIST_FOREACH(sl, char *, str, tor_free(str)); - smartlist_free(sl); - } - return 0; -} - -/** Called when we get a SAVECONF command. Try to flush the current options to - * disk, and report success or failure. */ -static int -handle_control_saveconf(control_connection_t *conn, uint32_t len, - const char *body) -{ - (void) len; - - int force = !strcmpstart(body, "FORCE"); - const or_options_t *options = get_options(); - if ((!force && options->IncludeUsed) || options_save_current() < 0) { - connection_write_str_to_buf( - "551 Unable to write configuration to disk.\r\n", conn); - } else { - send_control_done(conn); - } - return 0; -} - -struct signal_t { - int sig; - const char *signal_name; -}; - -static const struct signal_t signal_table[] = { - { SIGHUP, "RELOAD" }, - { SIGHUP, "HUP" }, - { SIGINT, "SHUTDOWN" }, - { SIGUSR1, "DUMP" }, - { SIGUSR1, "USR1" }, - { SIGUSR2, "DEBUG" }, - { SIGUSR2, "USR2" }, - { SIGTERM, "HALT" }, - { SIGTERM, "TERM" }, - { SIGTERM, "INT" }, - { SIGNEWNYM, "NEWNYM" }, - { SIGCLEARDNSCACHE, "CLEARDNSCACHE"}, - { SIGHEARTBEAT, "HEARTBEAT"}, - { SIGACTIVE, "ACTIVE" }, - { SIGDORMANT, "DORMANT" }, - { 0, NULL }, -}; - -/** Called when we get a SIGNAL command. React to the provided signal, and - * report success or failure. (If the signal results in a shutdown, success - * may not be reported.) */ -static int -handle_control_signal(control_connection_t *conn, uint32_t len, - const char *body) -{ - int sig = -1; - int i; - int n = 0; - char *s; - - (void) len; - - while (body[n] && ! TOR_ISSPACE(body[n])) - ++n; - s = tor_strndup(body, n); - - for (i = 0; signal_table[i].signal_name != NULL; ++i) { - if (!strcasecmp(s, signal_table[i].signal_name)) { - sig = signal_table[i].sig; - break; - } - } - - if (sig < 0) - connection_printf_to_buf(conn, "552 Unrecognized signal code \"%s\"\r\n", - s); - tor_free(s); - if (sig < 0) - return 0; - - send_control_done(conn); - /* Flush the "done" first if the signal might make us shut down. */ - if (sig == SIGTERM || sig == SIGINT) - connection_flush(TO_CONN(conn)); - - activate_signal(sig); - - return 0; -} - -/** Called when we get a TAKEOWNERSHIP command. Mark this connection - * as an owning connection, so that we will exit if the connection - * closes. */ -static int -handle_control_takeownership(control_connection_t *conn, uint32_t len, - const char *body) -{ - (void)len; - (void)body; - - conn->is_owning_control_connection = 1; - - log_info(LD_CONTROL, "Control connection %d has taken ownership of this " - "Tor instance.", - (int)(conn->base_.s)); - - send_control_done(conn); - return 0; -} - -/** Called when we get a DROPOWNERSHIP command. Mark this connection - * as a non-owning connection, so that we will not exit if the connection - * closes. */ -static int -handle_control_dropownership(control_connection_t *conn, uint32_t len, - const char *body) -{ - (void)len; - (void)body; - - conn->is_owning_control_connection = 0; - - log_info(LD_CONTROL, "Control connection %d has dropped ownership of this " - "Tor instance.", - (int)(conn->base_.s)); - - send_control_done(conn); - return 0; -} - -/** Return true iff addr is unusable as a mapaddress target because of - * containing funny characters. */ -static int -address_is_invalid_mapaddress_target(const char *addr) -{ - if (!strcmpstart(addr, "*.")) - return address_is_invalid_destination(addr+2, 1); - else - return address_is_invalid_destination(addr, 1); -} - -/** Called when we get a MAPADDRESS command; try to bind all listed addresses, - * and report success or failure. */ -static int -handle_control_mapaddress(control_connection_t *conn, uint32_t len, - const char *body) -{ - smartlist_t *elts; - smartlist_t *lines; - smartlist_t *reply; - char *r; - size_t sz; - (void) len; /* body is NUL-terminated, so it's safe to ignore the length. */ - - lines = smartlist_new(); - elts = smartlist_new(); - reply = smartlist_new(); - smartlist_split_string(lines, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - SMARTLIST_FOREACH_BEGIN(lines, char *, line) { - tor_strlower(line); - smartlist_split_string(elts, line, "=", 0, 2); - if (smartlist_len(elts) == 2) { - const char *from = smartlist_get(elts,0); - const char *to = smartlist_get(elts,1); - if (address_is_invalid_mapaddress_target(to)) { - smartlist_add_asprintf(reply, - "512-syntax error: invalid address '%s'", to); - log_warn(LD_CONTROL, - "Skipping invalid argument '%s' in MapAddress msg", to); - } else if (!strcmp(from, ".") || !strcmp(from, "0.0.0.0") || - !strcmp(from, "::")) { - const char type = - !strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME : - (!strcmp(from, "0.0.0.0") ? RESOLVED_TYPE_IPV4 : RESOLVED_TYPE_IPV6); - const char *address = addressmap_register_virtual_address( - type, tor_strdup(to)); - if (!address) { - smartlist_add_asprintf(reply, - "451-resource exhausted: skipping '%s'", line); - log_warn(LD_CONTROL, - "Unable to allocate address for '%s' in MapAddress msg", - safe_str_client(line)); - } else { - smartlist_add_asprintf(reply, "250-%s=%s", address, to); - } - } else { - const char *msg; - if (addressmap_register_auto(from, to, 1, - ADDRMAPSRC_CONTROLLER, &msg) < 0) { - smartlist_add_asprintf(reply, - "512-syntax error: invalid address mapping " - " '%s': %s", line, msg); - log_warn(LD_CONTROL, - "Skipping invalid argument '%s' in MapAddress msg: %s", - line, msg); - } else { - smartlist_add_asprintf(reply, "250-%s", line); - } - } - } else { - smartlist_add_asprintf(reply, "512-syntax error: mapping '%s' is " - "not of expected form 'foo=bar'.", line); - log_info(LD_CONTROL, "Skipping MapAddress '%s': wrong " - "number of items.", - safe_str_client(line)); - } - SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); - smartlist_clear(elts); - } SMARTLIST_FOREACH_END(line); - SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); - smartlist_free(lines); - smartlist_free(elts); - - if (smartlist_len(reply)) { - ((char*)smartlist_get(reply,smartlist_len(reply)-1))[3] = ' '; - r = smartlist_join_strings(reply, "\r\n", 1, &sz); - connection_buf_add(r, sz, TO_CONN(conn)); - tor_free(r); - } else { - const char *response = - "512 syntax error: not enough arguments to mapaddress.\r\n"; - connection_buf_add(response, strlen(response), TO_CONN(conn)); - } - - SMARTLIST_FOREACH(reply, char *, cp, tor_free(cp)); - smartlist_free(reply); - return 0; -} - -/** Implementation helper for GETINFO: knows the answers for various - * trivial-to-implement questions. */ -static int -getinfo_helper_misc(control_connection_t *conn, const char *question, - char **answer, const char **errmsg) -{ - (void) conn; - if (!strcmp(question, "version")) { - *answer = tor_strdup(get_version()); - } else if (!strcmp(question, "bw-event-cache")) { - *answer = get_bw_samples(); - } else if (!strcmp(question, "config-file")) { - const char *a = get_torrc_fname(0); - if (a) - *answer = tor_strdup(a); - } else if (!strcmp(question, "config-defaults-file")) { - const char *a = get_torrc_fname(1); - if (a) - *answer = tor_strdup(a); - } else if (!strcmp(question, "config-text")) { - *answer = options_dump(get_options(), OPTIONS_DUMP_MINIMAL); - } else if (!strcmp(question, "config-can-saveconf")) { - *answer = tor_strdup(get_options()->IncludeUsed ? "0" : "1"); - } else if (!strcmp(question, "info/names")) { - *answer = list_getinfo_options(); - } else if (!strcmp(question, "dormant")) { - int dormant = rep_hist_circbuilding_dormant(time(NULL)); - *answer = tor_strdup(dormant ? "1" : "0"); - } else if (!strcmp(question, "events/names")) { - int i; - smartlist_t *event_names = smartlist_new(); - - for (i = 0; control_event_table[i].event_name != NULL; ++i) { - smartlist_add(event_names, (char *)control_event_table[i].event_name); - } - - *answer = smartlist_join_strings(event_names, " ", 0, NULL); - - smartlist_free(event_names); - } else if (!strcmp(question, "signal/names")) { - smartlist_t *signal_names = smartlist_new(); - int j; - for (j = 0; signal_table[j].signal_name != NULL; ++j) { - smartlist_add(signal_names, (char*)signal_table[j].signal_name); - } - - *answer = smartlist_join_strings(signal_names, " ", 0, NULL); - - smartlist_free(signal_names); - } else if (!strcmp(question, "features/names")) { - *answer = tor_strdup("VERBOSE_NAMES EXTENDED_EVENTS"); - } else if (!strcmp(question, "address")) { - uint32_t addr; - if (router_pick_published_address(get_options(), &addr, 0) < 0) { - *errmsg = "Address unknown"; - return -1; - } - *answer = tor_dup_ip(addr); - } else if (!strcmp(question, "traffic/read")) { - tor_asprintf(answer, "%"PRIu64, (get_bytes_read())); - } else if (!strcmp(question, "traffic/written")) { - tor_asprintf(answer, "%"PRIu64, (get_bytes_written())); - } else if (!strcmp(question, "uptime")) { - long uptime_secs = get_uptime(); - tor_asprintf(answer, "%ld", uptime_secs); - } else if (!strcmp(question, "process/pid")) { - int myPid = -1; - -#ifdef _WIN32 - myPid = _getpid(); -#else - myPid = getpid(); -#endif - - tor_asprintf(answer, "%d", myPid); - } else if (!strcmp(question, "process/uid")) { -#ifdef _WIN32 - *answer = tor_strdup("-1"); -#else - int myUid = geteuid(); - tor_asprintf(answer, "%d", myUid); -#endif /* defined(_WIN32) */ - } else if (!strcmp(question, "process/user")) { -#ifdef _WIN32 - *answer = tor_strdup(""); -#else - int myUid = geteuid(); - const struct passwd *myPwEntry = tor_getpwuid(myUid); - - if (myPwEntry) { - *answer = tor_strdup(myPwEntry->pw_name); - } else { - *answer = tor_strdup(""); - } -#endif /* defined(_WIN32) */ - } else if (!strcmp(question, "process/descriptor-limit")) { - int max_fds = get_max_sockets(); - tor_asprintf(answer, "%d", max_fds); - } else if (!strcmp(question, "limits/max-mem-in-queues")) { - tor_asprintf(answer, "%"PRIu64, - (get_options()->MaxMemInQueues)); - } else if (!strcmp(question, "fingerprint")) { - crypto_pk_t *server_key; - if (!server_mode(get_options())) { - *errmsg = "Not running in server mode"; - return -1; - } - server_key = get_server_identity_key(); - *answer = tor_malloc(HEX_DIGEST_LEN+1); - crypto_pk_get_fingerprint(server_key, *answer, 0); - } - return 0; -} - -/** Awful hack: return a newly allocated string based on a routerinfo and - * (possibly) an extrainfo, sticking the read-history and write-history from - * ei into the resulting string. The thing you get back won't - * necessarily have a valid signature. - * - * New code should never use this; it's for backward compatibility. - * - * NOTE: ri_body is as returned by signed_descriptor_get_body: it might - * not be NUL-terminated. */ -static char * -munge_extrainfo_into_routerinfo(const char *ri_body, - const signed_descriptor_t *ri, - const signed_descriptor_t *ei) -{ - char *out = NULL, *outp; - int i; - const char *router_sig; - const char *ei_body = signed_descriptor_get_body(ei); - size_t ri_len = ri->signed_descriptor_len; - size_t ei_len = ei->signed_descriptor_len; - if (!ei_body) - goto bail; - - outp = out = tor_malloc(ri_len+ei_len+1); - if (!(router_sig = tor_memstr(ri_body, ri_len, "\nrouter-signature"))) - goto bail; - ++router_sig; - memcpy(out, ri_body, router_sig-ri_body); - outp += router_sig-ri_body; - - for (i=0; i < 2; ++i) { - const char *kwd = i ? "\nwrite-history " : "\nread-history "; - const char *cp, *eol; - if (!(cp = tor_memstr(ei_body, ei_len, kwd))) - continue; - ++cp; - if (!(eol = memchr(cp, '\n', ei_len - (cp-ei_body)))) - continue; - memcpy(outp, cp, eol-cp+1); - outp += eol-cp+1; - } - memcpy(outp, router_sig, ri_len - (router_sig-ri_body)); - *outp++ = '\0'; - tor_assert(outp-out < (int)(ri_len+ei_len+1)); - - return out; - bail: - tor_free(out); - return tor_strndup(ri_body, ri->signed_descriptor_len); -} - -/** Implementation helper for GETINFO: answers requests for information about - * which ports are bound. */ -static int -getinfo_helper_listeners(control_connection_t *control_conn, - const char *question, - char **answer, const char **errmsg) -{ - int type; - smartlist_t *res; - - (void)control_conn; - (void)errmsg; - - 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")) - type = CONN_TYPE_AP_LISTENER; - else if (!strcmp(question, "net/listeners/trans")) - 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")) - type = CONN_TYPE_CONTROL_LISTENER; - else - return 0; /* unknown key */ - - res = smartlist_new(); - SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { - struct sockaddr_storage ss; - socklen_t ss_len = sizeof(ss); - - if (conn->type != type || conn->marked_for_close || !SOCKET_OK(conn->s)) - continue; - - if (getsockname(conn->s, (struct sockaddr *)&ss, &ss_len) < 0) { - smartlist_add_asprintf(res, "%s:%d", conn->address, (int)conn->port); - } else { - char *tmp = tor_sockaddr_to_str((struct sockaddr *)&ss); - smartlist_add(res, esc_for_log(tmp)); - tor_free(tmp); - } - - } SMARTLIST_FOREACH_END(conn); - - *answer = smartlist_join_strings(res, " ", 0, NULL); - - SMARTLIST_FOREACH(res, char *, cp, tor_free(cp)); - smartlist_free(res); - return 0; -} - -/** Implementation helper for GETINFO: answers requests for information about - * the current time in both local and UTC forms. */ -STATIC int -getinfo_helper_current_time(control_connection_t *control_conn, - const char *question, - char **answer, const char **errmsg) -{ - (void)control_conn; - (void)errmsg; - - struct timeval now; - tor_gettimeofday(&now); - char timebuf[ISO_TIME_LEN+1]; - - if (!strcmp(question, "current-time/local")) - format_local_iso_time_nospace(timebuf, (time_t)now.tv_sec); - else if (!strcmp(question, "current-time/utc")) - format_iso_time_nospace(timebuf, (time_t)now.tv_sec); - else - return 0; - - *answer = tor_strdup(timebuf); - return 0; -} - -/** Implementation helper for GETINFO: knows the answers for questions about - * directory information. */ -STATIC int -getinfo_helper_dir(control_connection_t *control_conn, - const char *question, char **answer, - const char **errmsg) -{ - (void) control_conn; - if (!strcmpstart(question, "desc/id/")) { - const routerinfo_t *ri = NULL; - const node_t *node = node_get_by_hex_id(question+strlen("desc/id/"), 0); - if (node) - ri = node->ri; - if (ri) { - const char *body = signed_descriptor_get_body(&ri->cache_info); - if (body) - *answer = tor_strndup(body, ri->cache_info.signed_descriptor_len); - } else if (! we_fetch_router_descriptors(get_options())) { - /* Descriptors won't be available, provide proper error */ - *errmsg = "We fetch microdescriptors, not router " - "descriptors. You'll need to use md/id/* " - "instead of desc/id/*."; - return 0; - } - } else if (!strcmpstart(question, "desc/name/")) { - const routerinfo_t *ri = NULL; - /* XXX Setting 'warn_if_unnamed' here is a bit silly -- the - * warning goes to the user, not to the controller. */ - const node_t *node = - node_get_by_nickname(question+strlen("desc/name/"), 0); - if (node) - ri = node->ri; - if (ri) { - const char *body = signed_descriptor_get_body(&ri->cache_info); - if (body) - *answer = tor_strndup(body, ri->cache_info.signed_descriptor_len); - } else if (! we_fetch_router_descriptors(get_options())) { - /* Descriptors won't be available, provide proper error */ - *errmsg = "We fetch microdescriptors, not router " - "descriptors. You'll need to use md/name/* " - "instead of desc/name/*."; - return 0; - } - } else if (!strcmp(question, "desc/download-enabled")) { - int r = we_fetch_router_descriptors(get_options()); - tor_asprintf(answer, "%d", !!r); - } else if (!strcmp(question, "desc/all-recent")) { - routerlist_t *routerlist = router_get_routerlist(); - smartlist_t *sl = smartlist_new(); - if (routerlist && routerlist->routers) { - SMARTLIST_FOREACH(routerlist->routers, const routerinfo_t *, ri, - { - const char *body = signed_descriptor_get_body(&ri->cache_info); - if (body) - smartlist_add(sl, - tor_strndup(body, ri->cache_info.signed_descriptor_len)); - }); - } - *answer = smartlist_join_strings(sl, "", 0, NULL); - SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); - smartlist_free(sl); - } else if (!strcmp(question, "desc/all-recent-extrainfo-hack")) { - /* XXXX Remove this once Torstat asks for extrainfos. */ - routerlist_t *routerlist = router_get_routerlist(); - smartlist_t *sl = smartlist_new(); - if (routerlist && routerlist->routers) { - SMARTLIST_FOREACH_BEGIN(routerlist->routers, const routerinfo_t *, ri) { - const char *body = signed_descriptor_get_body(&ri->cache_info); - signed_descriptor_t *ei = extrainfo_get_by_descriptor_digest( - ri->cache_info.extra_info_digest); - if (ei && body) { - smartlist_add(sl, munge_extrainfo_into_routerinfo(body, - &ri->cache_info, ei)); - } else if (body) { - smartlist_add(sl, - tor_strndup(body, ri->cache_info.signed_descriptor_len)); - } - } SMARTLIST_FOREACH_END(ri); - } - *answer = smartlist_join_strings(sl, "", 0, NULL); - SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); - smartlist_free(sl); - } else if (!strcmpstart(question, "hs/client/desc/id/")) { - hostname_type_t addr_type; - - question += strlen("hs/client/desc/id/"); - if (rend_valid_v2_service_id(question)) { - addr_type = ONION_V2_HOSTNAME; - } else if (hs_address_is_valid(question)) { - addr_type = ONION_V3_HOSTNAME; - } else { - *errmsg = "Invalid address"; - return -1; - } - - if (addr_type == ONION_V2_HOSTNAME) { - rend_cache_entry_t *e = NULL; - if (!rend_cache_lookup_entry(question, -1, &e)) { - /* Descriptor found in cache */ - *answer = tor_strdup(e->desc); - } else { - *errmsg = "Not found in cache"; - return -1; - } - } else { - ed25519_public_key_t service_pk; - const char *desc; - - /* The check before this if/else makes sure of this. */ - tor_assert(addr_type == ONION_V3_HOSTNAME); - - if (hs_parse_address(question, &service_pk, NULL, NULL) < 0) { - *errmsg = "Invalid v3 address"; - return -1; - } - - desc = hs_cache_lookup_encoded_as_client(&service_pk); - if (desc) { - *answer = tor_strdup(desc); - } else { - *errmsg = "Not found in cache"; - return -1; - } - } - } else if (!strcmpstart(question, "hs/service/desc/id/")) { - hostname_type_t addr_type; - - question += strlen("hs/service/desc/id/"); - if (rend_valid_v2_service_id(question)) { - addr_type = ONION_V2_HOSTNAME; - } else if (hs_address_is_valid(question)) { - addr_type = ONION_V3_HOSTNAME; - } else { - *errmsg = "Invalid address"; - return -1; - } - rend_cache_entry_t *e = NULL; - - if (addr_type == ONION_V2_HOSTNAME) { - if (!rend_cache_lookup_v2_desc_as_service(question, &e)) { - /* Descriptor found in cache */ - *answer = tor_strdup(e->desc); - } else { - *errmsg = "Not found in cache"; - return -1; - } - } else { - ed25519_public_key_t service_pk; - char *desc; - - /* The check before this if/else makes sure of this. */ - tor_assert(addr_type == ONION_V3_HOSTNAME); - - if (hs_parse_address(question, &service_pk, NULL, NULL) < 0) { - *errmsg = "Invalid v3 address"; - return -1; - } - - desc = hs_service_lookup_current_desc(&service_pk); - if (desc) { - /* Newly allocated string, we have ownership. */ - *answer = desc; - } else { - *errmsg = "Not found in cache"; - return -1; - } - } - } else if (!strcmp(question, "md/all")) { - const smartlist_t *nodes = nodelist_get_list(); - tor_assert(nodes); - - if (smartlist_len(nodes) == 0) { - *answer = tor_strdup(""); - return 0; - } - - smartlist_t *microdescs = smartlist_new(); - - SMARTLIST_FOREACH_BEGIN(nodes, node_t *, n) { - if (n->md && n->md->body) { - char *copy = tor_strndup(n->md->body, n->md->bodylen); - smartlist_add(microdescs, copy); - } - } SMARTLIST_FOREACH_END(n); - - *answer = smartlist_join_strings(microdescs, "", 0, NULL); - SMARTLIST_FOREACH(microdescs, char *, md, tor_free(md)); - smartlist_free(microdescs); - } else if (!strcmpstart(question, "md/id/")) { - const node_t *node = node_get_by_hex_id(question+strlen("md/id/"), 0); - const microdesc_t *md = NULL; - if (node) md = node->md; - if (md && md->body) { - *answer = tor_strndup(md->body, md->bodylen); - } - } else if (!strcmpstart(question, "md/name/")) { - /* XXX Setting 'warn_if_unnamed' here is a bit silly -- the - * warning goes to the user, not to the controller. */ - const node_t *node = node_get_by_nickname(question+strlen("md/name/"), 0); - /* XXXX duplicated code */ - const microdesc_t *md = NULL; - if (node) md = node->md; - if (md && md->body) { - *answer = tor_strndup(md->body, md->bodylen); - } - } else if (!strcmp(question, "md/download-enabled")) { - int r = we_fetch_microdescriptors(get_options()); - tor_asprintf(answer, "%d", !!r); - } else if (!strcmpstart(question, "desc-annotations/id/")) { - const routerinfo_t *ri = NULL; - const node_t *node = - node_get_by_hex_id(question+strlen("desc-annotations/id/"), 0); - if (node) - ri = node->ri; - if (ri) { - const char *annotations = - signed_descriptor_get_annotations(&ri->cache_info); - if (annotations) - *answer = tor_strndup(annotations, - ri->cache_info.annotations_len); - } - } else if (!strcmpstart(question, "dir/server/")) { - size_t answer_len = 0; - char *url = NULL; - smartlist_t *descs = smartlist_new(); - const char *msg; - int res; - char *cp; - tor_asprintf(&url, "/tor/%s", question+4); - res = dirserv_get_routerdescs(descs, url, &msg); - if (res) { - log_warn(LD_CONTROL, "getinfo '%s': %s", question, msg); - smartlist_free(descs); - tor_free(url); - *errmsg = msg; - return -1; - } - SMARTLIST_FOREACH(descs, signed_descriptor_t *, sd, - answer_len += sd->signed_descriptor_len); - cp = *answer = tor_malloc(answer_len+1); - SMARTLIST_FOREACH(descs, signed_descriptor_t *, sd, - { - memcpy(cp, signed_descriptor_get_body(sd), - sd->signed_descriptor_len); - cp += sd->signed_descriptor_len; - }); - *cp = '\0'; - tor_free(url); - smartlist_free(descs); - } else if (!strcmpstart(question, "dir/status/")) { - *answer = tor_strdup(""); - } else if (!strcmp(question, "dir/status-vote/current/consensus")) { /* v3 */ - if (we_want_to_fetch_flavor(get_options(), FLAV_NS)) { - const cached_dir_t *consensus = dirserv_get_consensus("ns"); - if (consensus) - *answer = tor_strdup(consensus->dir); - } - if (!*answer) { /* try loading it from disk */ - tor_mmap_t *mapped = networkstatus_map_cached_consensus("ns"); - if (mapped) { - *answer = tor_memdup_nulterm(mapped->data, mapped->size); - tor_munmap_file(mapped); - } - if (!*answer) { /* generate an error */ - *errmsg = "Could not open cached consensus. " - "Make sure FetchUselessDescriptors is set to 1."; - return -1; - } - } - } else if (!strcmp(question, "network-status")) { /* v1 */ - static int network_status_warned = 0; - if (!network_status_warned) { - log_warn(LD_CONTROL, "GETINFO network-status is deprecated; it will " - "go away in a future version of Tor."); - network_status_warned = 1; - } - routerlist_t *routerlist = router_get_routerlist(); - if (!routerlist || !routerlist->routers || - list_server_status_v1(routerlist->routers, answer, 1) < 0) { - return -1; - } - } else if (!strcmpstart(question, "extra-info/digest/")) { - question += strlen("extra-info/digest/"); - if (strlen(question) == HEX_DIGEST_LEN) { - char d[DIGEST_LEN]; - signed_descriptor_t *sd = NULL; - if (base16_decode(d, sizeof(d), question, strlen(question)) - == sizeof(d)) { - /* XXXX this test should move into extrainfo_get_by_descriptor_digest, - * but I don't want to risk affecting other parts of the code, - * especially since the rules for using our own extrainfo (including - * when it might be freed) are different from those for using one - * we have downloaded. */ - if (router_extrainfo_digest_is_me(d)) - sd = &(router_get_my_extrainfo()->cache_info); - else - sd = extrainfo_get_by_descriptor_digest(d); - } - if (sd) { - const char *body = signed_descriptor_get_body(sd); - if (body) - *answer = tor_strndup(body, sd->signed_descriptor_len); - } - } - } - - return 0; -} - -/** Given a smartlist of 20-byte digests, return a newly allocated string - * containing each of those digests in order, formatted in HEX, and terminated - * with a newline. */ -static char * -digest_list_to_string(const smartlist_t *sl) -{ - int len; - char *result, *s; - - /* Allow for newlines, and a \0 at the end */ - len = smartlist_len(sl) * (HEX_DIGEST_LEN + 1) + 1; - result = tor_malloc_zero(len); - - s = result; - SMARTLIST_FOREACH_BEGIN(sl, const char *, digest) { - base16_encode(s, HEX_DIGEST_LEN + 1, digest, DIGEST_LEN); - s[HEX_DIGEST_LEN] = '\n'; - s += HEX_DIGEST_LEN + 1; - } SMARTLIST_FOREACH_END(digest); - *s = '\0'; - - return result; -} - -/** Turn a download_status_t into a human-readable description in a newly - * allocated string. The format is specified in control-spec.txt, under - * the documentation for "GETINFO download/..." . */ -static char * -download_status_to_string(const download_status_t *dl) -{ - char *rv = NULL; - char tbuf[ISO_TIME_LEN+1]; - const char *schedule_str, *want_authority_str; - const char *increment_on_str, *backoff_str; - - if (dl) { - /* Get some substrings of the eventual output ready */ - format_iso_time(tbuf, download_status_get_next_attempt_at(dl)); - - switch (dl->schedule) { - case DL_SCHED_GENERIC: - schedule_str = "DL_SCHED_GENERIC"; - break; - case DL_SCHED_CONSENSUS: - schedule_str = "DL_SCHED_CONSENSUS"; - break; - case DL_SCHED_BRIDGE: - schedule_str = "DL_SCHED_BRIDGE"; - break; - default: - schedule_str = "unknown"; - break; - } - - switch (dl->want_authority) { - case DL_WANT_ANY_DIRSERVER: - want_authority_str = "DL_WANT_ANY_DIRSERVER"; - break; - case DL_WANT_AUTHORITY: - want_authority_str = "DL_WANT_AUTHORITY"; - break; - default: - want_authority_str = "unknown"; - break; - } - - switch (dl->increment_on) { - case DL_SCHED_INCREMENT_FAILURE: - increment_on_str = "DL_SCHED_INCREMENT_FAILURE"; - break; - case DL_SCHED_INCREMENT_ATTEMPT: - increment_on_str = "DL_SCHED_INCREMENT_ATTEMPT"; - break; - default: - increment_on_str = "unknown"; - break; - } - - backoff_str = "DL_SCHED_RANDOM_EXPONENTIAL"; - - /* Now assemble them */ - tor_asprintf(&rv, - "next-attempt-at %s\n" - "n-download-failures %u\n" - "n-download-attempts %u\n" - "schedule %s\n" - "want-authority %s\n" - "increment-on %s\n" - "backoff %s\n" - "last-backoff-position %u\n" - "last-delay-used %d\n", - tbuf, - dl->n_download_failures, - dl->n_download_attempts, - schedule_str, - want_authority_str, - increment_on_str, - backoff_str, - dl->last_backoff_position, - dl->last_delay_used); - } - - return rv; -} - -/** Handle the consensus download cases for getinfo_helper_downloads() */ -STATIC void -getinfo_helper_downloads_networkstatus(const char *flavor, - download_status_t **dl_to_emit, - const char **errmsg) -{ - /* - * We get the one for the current bootstrapped status by default, or - * take an extra /bootstrap or /running suffix - */ - if (strcmp(flavor, "ns") == 0) { - *dl_to_emit = networkstatus_get_dl_status_by_flavor(FLAV_NS); - } else if (strcmp(flavor, "ns/bootstrap") == 0) { - *dl_to_emit = networkstatus_get_dl_status_by_flavor_bootstrap(FLAV_NS); - } else if (strcmp(flavor, "ns/running") == 0 ) { - *dl_to_emit = networkstatus_get_dl_status_by_flavor_running(FLAV_NS); - } else if (strcmp(flavor, "microdesc") == 0) { - *dl_to_emit = networkstatus_get_dl_status_by_flavor(FLAV_MICRODESC); - } else if (strcmp(flavor, "microdesc/bootstrap") == 0) { - *dl_to_emit = - networkstatus_get_dl_status_by_flavor_bootstrap(FLAV_MICRODESC); - } else if (strcmp(flavor, "microdesc/running") == 0) { - *dl_to_emit = - networkstatus_get_dl_status_by_flavor_running(FLAV_MICRODESC); - } else { - *errmsg = "Unknown flavor"; - } -} - -/** Handle the cert download cases for getinfo_helper_downloads() */ -STATIC void -getinfo_helper_downloads_cert(const char *fp_sk_req, - download_status_t **dl_to_emit, - smartlist_t **digest_list, - const char **errmsg) -{ - const char *sk_req; - char id_digest[DIGEST_LEN]; - char sk_digest[DIGEST_LEN]; - - /* - * We have to handle four cases; fp_sk_req is the request with - * a prefix of "downloads/cert/" snipped off. - * - * Case 1: fp_sk_req = "fps" - * - We should emit a digest_list with a list of all the identity - * fingerprints that can be queried for certificate download status; - * get it by calling list_authority_ids_with_downloads(). - * - * Case 2: fp_sk_req = "fp/" for some fingerprint fp - * - We want the default certificate for this identity fingerprint's - * download status; this is the download we get from URLs starting - * in /fp/ on the directory server. We can get it with - * id_only_download_status_for_authority_id(). - * - * Case 3: fp_sk_req = "fp//sks" for some fingerprint fp - * - We want a list of all signing key digests for this identity - * fingerprint which can be queried for certificate download status. - * Get it with list_sk_digests_for_authority_id(). - * - * Case 4: fp_sk_req = "fp//" for some fingerprint fp and - * signing key digest sk - * - We want the download status for the certificate for this specific - * signing key and fingerprint. These correspond to the ones we get - * from URLs starting in /fp-sk/ on the directory server. Get it with - * list_sk_digests_for_authority_id(). - */ - - if (strcmp(fp_sk_req, "fps") == 0) { - *digest_list = list_authority_ids_with_downloads(); - if (!(*digest_list)) { - *errmsg = "Failed to get list of authority identity digests (!)"; - } - } else if (!strcmpstart(fp_sk_req, "fp/")) { - fp_sk_req += strlen("fp/"); - /* Okay, look for another / to tell the fp from fp-sk cases */ - sk_req = strchr(fp_sk_req, '/'); - if (sk_req) { - /* okay, split it here and try to parse */ - if (base16_decode(id_digest, DIGEST_LEN, - fp_sk_req, sk_req - fp_sk_req) == DIGEST_LEN) { - /* Skip past the '/' */ - ++sk_req; - if (strcmp(sk_req, "sks") == 0) { - /* We're asking for the list of signing key fingerprints */ - *digest_list = list_sk_digests_for_authority_id(id_digest); - if (!(*digest_list)) { - *errmsg = "Failed to get list of signing key digests for this " - "authority identity digest"; - } - } else { - /* We've got a signing key digest */ - if (base16_decode(sk_digest, DIGEST_LEN, - sk_req, strlen(sk_req)) == DIGEST_LEN) { - *dl_to_emit = - download_status_for_authority_id_and_sk(id_digest, sk_digest); - if (!(*dl_to_emit)) { - *errmsg = "Failed to get download status for this identity/" - "signing key digest pair"; - } - } else { - *errmsg = "That didn't look like a signing key digest"; - } - } - } else { - *errmsg = "That didn't look like an identity digest"; - } - } else { - /* We're either in downloads/certs/fp/, or we can't parse */ - if (strlen(fp_sk_req) == HEX_DIGEST_LEN) { - if (base16_decode(id_digest, DIGEST_LEN, - fp_sk_req, strlen(fp_sk_req)) == DIGEST_LEN) { - *dl_to_emit = id_only_download_status_for_authority_id(id_digest); - if (!(*dl_to_emit)) { - *errmsg = "Failed to get download status for this authority " - "identity digest"; - } - } else { - *errmsg = "That didn't look like a digest"; - } - } else { - *errmsg = "That didn't look like a digest"; - } - } - } else { - *errmsg = "Unknown certificate download status query"; - } -} - -/** Handle the routerdesc download cases for getinfo_helper_downloads() */ -STATIC void -getinfo_helper_downloads_desc(const char *desc_req, - download_status_t **dl_to_emit, - smartlist_t **digest_list, - const char **errmsg) -{ - char desc_digest[DIGEST_LEN]; - /* - * Two cases to handle here: - * - * Case 1: desc_req = "descs" - * - Emit a list of all router descriptor digests, which we get by - * calling router_get_descriptor_digests(); this can return NULL - * if we have no current ns-flavor consensus. - * - * Case 2: desc_req = - * - Check on the specified fingerprint and emit its download_status_t - * using router_get_dl_status_by_descriptor_digest(). - */ - - if (strcmp(desc_req, "descs") == 0) { - *digest_list = router_get_descriptor_digests(); - if (!(*digest_list)) { - *errmsg = "We don't seem to have a networkstatus-flavored consensus"; - } - /* - * Microdescs don't use the download_status_t mechanism, so we don't - * answer queries about their downloads here; see microdesc.c. - */ - } else if (strlen(desc_req) == HEX_DIGEST_LEN) { - if (base16_decode(desc_digest, DIGEST_LEN, - desc_req, strlen(desc_req)) == DIGEST_LEN) { - /* Okay we got a digest-shaped thing; try asking for it */ - *dl_to_emit = router_get_dl_status_by_descriptor_digest(desc_digest); - if (!(*dl_to_emit)) { - *errmsg = "No such descriptor digest found"; - } - } else { - *errmsg = "That didn't look like a digest"; - } - } else { - *errmsg = "Unknown router descriptor download status query"; - } -} - -/** Handle the bridge download cases for getinfo_helper_downloads() */ -STATIC void -getinfo_helper_downloads_bridge(const char *bridge_req, - download_status_t **dl_to_emit, - smartlist_t **digest_list, - const char **errmsg) -{ - char bridge_digest[DIGEST_LEN]; - /* - * Two cases to handle here: - * - * Case 1: bridge_req = "bridges" - * - Emit a list of all bridge identity digests, which we get by - * calling list_bridge_identities(); this can return NULL if we are - * not using bridges. - * - * Case 2: bridge_req = - * - Check on the specified fingerprint and emit its download_status_t - * using get_bridge_dl_status_by_id(). - */ - - if (strcmp(bridge_req, "bridges") == 0) { - *digest_list = list_bridge_identities(); - if (!(*digest_list)) { - *errmsg = "We don't seem to be using bridges"; - } - } else if (strlen(bridge_req) == HEX_DIGEST_LEN) { - if (base16_decode(bridge_digest, DIGEST_LEN, - bridge_req, strlen(bridge_req)) == DIGEST_LEN) { - /* Okay we got a digest-shaped thing; try asking for it */ - *dl_to_emit = get_bridge_dl_status_by_id(bridge_digest); - if (!(*dl_to_emit)) { - *errmsg = "No such bridge identity digest found"; - } - } else { - *errmsg = "That didn't look like a digest"; - } - } else { - *errmsg = "Unknown bridge descriptor download status query"; - } -} - -/** Implementation helper for GETINFO: knows the answers for questions about - * download status information. */ -STATIC int -getinfo_helper_downloads(control_connection_t *control_conn, - const char *question, char **answer, - const char **errmsg) -{ - download_status_t *dl_to_emit = NULL; - smartlist_t *digest_list = NULL; - - /* Assert args are sane */ - tor_assert(control_conn != NULL); - tor_assert(question != NULL); - tor_assert(answer != NULL); - tor_assert(errmsg != NULL); - - /* We check for this later to see if we should supply a default */ - *errmsg = NULL; - - /* Are we after networkstatus downloads? */ - if (!strcmpstart(question, "downloads/networkstatus/")) { - getinfo_helper_downloads_networkstatus( - question + strlen("downloads/networkstatus/"), - &dl_to_emit, errmsg); - /* Certificates? */ - } else if (!strcmpstart(question, "downloads/cert/")) { - getinfo_helper_downloads_cert( - question + strlen("downloads/cert/"), - &dl_to_emit, &digest_list, errmsg); - /* Router descriptors? */ - } else if (!strcmpstart(question, "downloads/desc/")) { - getinfo_helper_downloads_desc( - question + strlen("downloads/desc/"), - &dl_to_emit, &digest_list, errmsg); - /* Bridge descriptors? */ - } else if (!strcmpstart(question, "downloads/bridge/")) { - getinfo_helper_downloads_bridge( - question + strlen("downloads/bridge/"), - &dl_to_emit, &digest_list, errmsg); - } else { - *errmsg = "Unknown download status query"; - } - - if (dl_to_emit) { - *answer = download_status_to_string(dl_to_emit); - - return 0; - } else if (digest_list) { - *answer = digest_list_to_string(digest_list); - SMARTLIST_FOREACH(digest_list, void *, s, tor_free(s)); - smartlist_free(digest_list); - - return 0; - } else { - if (!(*errmsg)) { - *errmsg = "Unknown error"; - } - - return -1; - } -} - -/** Allocate and return a description of circ's current status, - * including its path (if any). */ -static char * -circuit_describe_status_for_controller(origin_circuit_t *circ) -{ - char *rv; - smartlist_t *descparts = smartlist_new(); - - { - char *vpath = circuit_list_path_for_controller(circ); - if (*vpath) { - smartlist_add(descparts, vpath); - } else { - tor_free(vpath); /* empty path; don't put an extra space in the result */ - } - } - - { - cpath_build_state_t *build_state = circ->build_state; - smartlist_t *flaglist = smartlist_new(); - char *flaglist_joined; - - if (build_state->onehop_tunnel) - smartlist_add(flaglist, (void *)"ONEHOP_TUNNEL"); - if (build_state->is_internal) - smartlist_add(flaglist, (void *)"IS_INTERNAL"); - if (build_state->need_capacity) - smartlist_add(flaglist, (void *)"NEED_CAPACITY"); - if (build_state->need_uptime) - smartlist_add(flaglist, (void *)"NEED_UPTIME"); - - /* Only emit a BUILD_FLAGS argument if it will have a non-empty value. */ - if (smartlist_len(flaglist)) { - flaglist_joined = smartlist_join_strings(flaglist, ",", 0, NULL); - - smartlist_add_asprintf(descparts, "BUILD_FLAGS=%s", flaglist_joined); - - tor_free(flaglist_joined); - } - - smartlist_free(flaglist); - } - - smartlist_add_asprintf(descparts, "PURPOSE=%s", - circuit_purpose_to_controller_string(circ->base_.purpose)); - - { - const char *hs_state = - circuit_purpose_to_controller_hs_state_string(circ->base_.purpose); - - if (hs_state != NULL) { - smartlist_add_asprintf(descparts, "HS_STATE=%s", hs_state); - } - } - - if (circ->rend_data != NULL || circ->hs_ident != NULL) { - char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1]; - const char *onion_address; - if (circ->rend_data) { - onion_address = rend_data_get_address(circ->rend_data); - } else { - hs_build_address(&circ->hs_ident->identity_pk, HS_VERSION_THREE, addr); - onion_address = addr; - } - smartlist_add_asprintf(descparts, "REND_QUERY=%s", onion_address); - } - - { - char tbuf[ISO_TIME_USEC_LEN+1]; - format_iso_time_nospace_usec(tbuf, &circ->base_.timestamp_created); - - smartlist_add_asprintf(descparts, "TIME_CREATED=%s", tbuf); - } - - // Show username and/or password if available. - if (circ->socks_username_len > 0) { - char* socks_username_escaped = esc_for_log_len(circ->socks_username, - (size_t) circ->socks_username_len); - smartlist_add_asprintf(descparts, "SOCKS_USERNAME=%s", - socks_username_escaped); - tor_free(socks_username_escaped); - } - if (circ->socks_password_len > 0) { - char* socks_password_escaped = esc_for_log_len(circ->socks_password, - (size_t) circ->socks_password_len); - smartlist_add_asprintf(descparts, "SOCKS_PASSWORD=%s", - socks_password_escaped); - tor_free(socks_password_escaped); - } - - rv = smartlist_join_strings(descparts, " ", 0, NULL); - - SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp)); - smartlist_free(descparts); - - return rv; -} - -/** Implementation helper for GETINFO: knows how to generate summaries of the - * current states of things we send events about. */ -static int -getinfo_helper_events(control_connection_t *control_conn, - const char *question, char **answer, - const char **errmsg) -{ - const or_options_t *options = get_options(); - (void) control_conn; - if (!strcmp(question, "circuit-status")) { - smartlist_t *status = smartlist_new(); - SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ_) { - origin_circuit_t *circ; - char *circdesc; - const char *state; - if (! CIRCUIT_IS_ORIGIN(circ_) || circ_->marked_for_close) - continue; - circ = TO_ORIGIN_CIRCUIT(circ_); - - if (circ->base_.state == CIRCUIT_STATE_OPEN) - state = "BUILT"; - else if (circ->base_.state == CIRCUIT_STATE_GUARD_WAIT) - state = "GUARD_WAIT"; - else if (circ->cpath) - state = "EXTENDED"; - else - state = "LAUNCHED"; - - circdesc = circuit_describe_status_for_controller(circ); - - smartlist_add_asprintf(status, "%lu %s%s%s", - (unsigned long)circ->global_identifier, - state, *circdesc ? " " : "", circdesc); - tor_free(circdesc); - } - SMARTLIST_FOREACH_END(circ_); - *answer = smartlist_join_strings(status, "\r\n", 0, NULL); - SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); - smartlist_free(status); - } else if (!strcmp(question, "stream-status")) { - smartlist_t *conns = get_connection_array(); - smartlist_t *status = smartlist_new(); - char buf[256]; - SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { - const char *state; - entry_connection_t *conn; - circuit_t *circ; - origin_circuit_t *origin_circ = NULL; - if (base_conn->type != CONN_TYPE_AP || - base_conn->marked_for_close || - base_conn->state == AP_CONN_STATE_SOCKS_WAIT || - base_conn->state == AP_CONN_STATE_NATD_WAIT) - continue; - conn = TO_ENTRY_CONN(base_conn); - switch (base_conn->state) - { - case AP_CONN_STATE_CONTROLLER_WAIT: - case AP_CONN_STATE_CIRCUIT_WAIT: - if (conn->socks_request && - SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) - state = "NEWRESOLVE"; - else - state = "NEW"; - break; - case AP_CONN_STATE_RENDDESC_WAIT: - case AP_CONN_STATE_CONNECT_WAIT: - state = "SENTCONNECT"; break; - case AP_CONN_STATE_RESOLVE_WAIT: - state = "SENTRESOLVE"; break; - case AP_CONN_STATE_OPEN: - state = "SUCCEEDED"; break; - default: - log_warn(LD_BUG, "Asked for stream in unknown state %d", - base_conn->state); - continue; - } - circ = circuit_get_by_edge_conn(ENTRY_TO_EDGE_CONN(conn)); - if (circ && CIRCUIT_IS_ORIGIN(circ)) - origin_circ = TO_ORIGIN_CIRCUIT(circ); - write_stream_target_to_buf(conn, buf, sizeof(buf)); - smartlist_add_asprintf(status, "%lu %s %lu %s", - (unsigned long) base_conn->global_identifier,state, - origin_circ? - (unsigned long)origin_circ->global_identifier : 0ul, - buf); - } SMARTLIST_FOREACH_END(base_conn); - *answer = smartlist_join_strings(status, "\r\n", 0, NULL); - SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); - smartlist_free(status); - } else if (!strcmp(question, "orconn-status")) { - smartlist_t *conns = get_connection_array(); - smartlist_t *status = smartlist_new(); - SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { - const char *state; - char name[128]; - or_connection_t *conn; - if (base_conn->type != CONN_TYPE_OR || base_conn->marked_for_close) - continue; - conn = TO_OR_CONN(base_conn); - if (conn->base_.state == OR_CONN_STATE_OPEN) - state = "CONNECTED"; - else if (conn->nickname) - state = "LAUNCHED"; - else - state = "NEW"; - orconn_target_get_name(name, sizeof(name), conn); - smartlist_add_asprintf(status, "%s %s", name, state); - } SMARTLIST_FOREACH_END(base_conn); - *answer = smartlist_join_strings(status, "\r\n", 0, NULL); - SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); - smartlist_free(status); - } else if (!strcmpstart(question, "address-mappings/")) { - time_t min_e, max_e; - smartlist_t *mappings; - question += strlen("address-mappings/"); - if (!strcmp(question, "all")) { - min_e = 0; max_e = TIME_MAX; - } else if (!strcmp(question, "cache")) { - min_e = 2; max_e = TIME_MAX; - } else if (!strcmp(question, "config")) { - min_e = 0; max_e = 0; - } else if (!strcmp(question, "control")) { - min_e = 1; max_e = 1; - } else { - return 0; - } - mappings = smartlist_new(); - addressmap_get_mappings(mappings, min_e, max_e, 1); - *answer = smartlist_join_strings(mappings, "\r\n", 0, NULL); - SMARTLIST_FOREACH(mappings, char *, cp, tor_free(cp)); - smartlist_free(mappings); - } else if (!strcmpstart(question, "status/")) { - /* Note that status/ is not a catch-all for events; there's only supposed - * to be a status GETINFO if there's a corresponding STATUS event. */ - if (!strcmp(question, "status/circuit-established")) { - *answer = tor_strdup(have_completed_a_circuit() ? "1" : "0"); - } else if (!strcmp(question, "status/enough-dir-info")) { - *answer = tor_strdup(router_have_minimum_dir_info() ? "1" : "0"); - } else if (!strcmp(question, "status/good-server-descriptor") || - !strcmp(question, "status/accepted-server-descriptor")) { - /* They're equivalent for now, until we can figure out how to make - * good-server-descriptor be what we want. See comment in - * control-spec.txt. */ - *answer = tor_strdup(directories_have_accepted_server_descriptor() - ? "1" : "0"); - } else if (!strcmp(question, "status/reachability-succeeded/or")) { - *answer = tor_strdup(check_whether_orport_reachable(options) ? - "1" : "0"); - } else if (!strcmp(question, "status/reachability-succeeded/dir")) { - *answer = tor_strdup(check_whether_dirport_reachable(options) ? - "1" : "0"); - } else if (!strcmp(question, "status/reachability-succeeded")) { - tor_asprintf(answer, "OR=%d DIR=%d", - check_whether_orport_reachable(options) ? 1 : 0, - check_whether_dirport_reachable(options) ? 1 : 0); - } else if (!strcmp(question, "status/bootstrap-phase")) { - *answer = control_event_boot_last_msg(); - } else if (!strcmpstart(question, "status/version/")) { - int is_server = server_mode(options); - networkstatus_t *c = networkstatus_get_latest_consensus(); - version_status_t status; - const char *recommended; - if (c) { - recommended = is_server ? c->server_versions : c->client_versions; - status = tor_version_is_obsolete(VERSION, recommended); - } else { - recommended = "?"; - status = VS_UNKNOWN; - } - - if (!strcmp(question, "status/version/recommended")) { - *answer = tor_strdup(recommended); - return 0; - } - if (!strcmp(question, "status/version/current")) { - switch (status) - { - case VS_RECOMMENDED: *answer = tor_strdup("recommended"); break; - case VS_OLD: *answer = tor_strdup("obsolete"); break; - case VS_NEW: *answer = tor_strdup("new"); break; - case VS_NEW_IN_SERIES: *answer = tor_strdup("new in series"); break; - case VS_UNRECOMMENDED: *answer = tor_strdup("unrecommended"); break; - case VS_EMPTY: *answer = tor_strdup("none recommended"); break; - case VS_UNKNOWN: *answer = tor_strdup("unknown"); break; - default: tor_fragile_assert(); - } - } - } else if (!strcmp(question, "status/clients-seen")) { - char *bridge_stats = geoip_get_bridge_stats_controller(time(NULL)); - if (!bridge_stats) { - *errmsg = "No bridge-client stats available"; - return -1; - } - *answer = bridge_stats; - } else if (!strcmp(question, "status/fresh-relay-descs")) { - if (!server_mode(options)) { - *errmsg = "Only relays have descriptors"; - return -1; - } - routerinfo_t *r; - extrainfo_t *e; - if (router_build_fresh_descriptor(&r, &e) < 0) { - *errmsg = "Error generating descriptor"; - return -1; - } - size_t size = r->cache_info.signed_descriptor_len + 1; - if (e) { - size += e->cache_info.signed_descriptor_len + 1; - } - tor_assert(r->cache_info.signed_descriptor_len); - char *descs = tor_malloc(size); - char *cp = descs; - memcpy(cp, signed_descriptor_get_body(&r->cache_info), - r->cache_info.signed_descriptor_len); - cp += r->cache_info.signed_descriptor_len - 1; - if (e) { - if (cp[0] == '\0') { - cp[0] = '\n'; - } else if (cp[0] != '\n') { - cp[1] = '\n'; - cp++; - } - memcpy(cp, signed_descriptor_get_body(&e->cache_info), - e->cache_info.signed_descriptor_len); - cp += e->cache_info.signed_descriptor_len - 1; - } - if (cp[0] == '\n') { - cp[0] = '\0'; - } else if (cp[0] != '\0') { - cp[1] = '\0'; - } - *answer = descs; - routerinfo_free(r); - extrainfo_free(e); - } else { - return 0; - } - } - return 0; -} - -/** Implementation helper for GETINFO: knows how to enumerate hidden services - * created via the control port. */ -STATIC int -getinfo_helper_onions(control_connection_t *control_conn, - const char *question, char **answer, - const char **errmsg) -{ - smartlist_t *onion_list = NULL; - (void) errmsg; /* no errors from this method */ - - if (control_conn && !strcmp(question, "onions/current")) { - onion_list = control_conn->ephemeral_onion_services; - } else if (!strcmp(question, "onions/detached")) { - onion_list = detached_onion_services; - } else { - return 0; - } - if (!onion_list || smartlist_len(onion_list) == 0) { - if (answer) { - *answer = tor_strdup(""); - } - } else { - if (answer) { - *answer = smartlist_join_strings(onion_list, "\r\n", 0, NULL); - } - } - - return 0; -} - -/** Implementation helper for GETINFO: answers queries about network - * liveness. */ -static int -getinfo_helper_liveness(control_connection_t *control_conn, - const char *question, char **answer, - const char **errmsg) -{ - (void)control_conn; - (void)errmsg; - if (strcmp(question, "network-liveness") == 0) { - if (get_cached_network_liveness()) { - *answer = tor_strdup("up"); - } else { - *answer = tor_strdup("down"); - } - } - - return 0; -} - -/** Implementation helper for GETINFO: answers queries about shared random - * value. */ -static int -getinfo_helper_sr(control_connection_t *control_conn, - const char *question, char **answer, - const char **errmsg) -{ - (void) control_conn; - (void) errmsg; - - if (!strcmp(question, "sr/current")) { - *answer = sr_get_current_for_control(); - } else if (!strcmp(question, "sr/previous")) { - *answer = sr_get_previous_for_control(); - } - /* Else statement here is unrecognized key so do nothing. */ - - return 0; -} - -/** Callback function for GETINFO: on a given control connection, try to - * answer the question q and store the newly-allocated answer in - * *a. If an internal error occurs, return -1 and optionally set - * *error_out to point to an error message to be delivered to the - * controller. On success, _or if the key is not recognized_, return 0. Do not - * set a if the key is not recognized but you may set error_out - * to improve the error message. - */ -typedef int (*getinfo_helper_t)(control_connection_t *, - const char *q, char **a, - const char **error_out); - -/** A single item for the GETINFO question-to-answer-function table. */ -typedef struct getinfo_item_t { - const char *varname; /**< The value (or prefix) of the question. */ - getinfo_helper_t fn; /**< The function that knows the answer: NULL if - * this entry is documentation-only. */ - const char *desc; /**< Description of the variable. */ - int is_prefix; /** Must varname match exactly, or must it be a prefix? */ -} getinfo_item_t; - -#define ITEM(name, fn, desc) { name, getinfo_helper_##fn, desc, 0 } -#define PREFIX(name, fn, desc) { name, getinfo_helper_##fn, desc, 1 } -#define DOC(name, desc) { name, NULL, desc, 0 } - -/** Table mapping questions accepted by GETINFO to the functions that know how - * to answer them. */ -static const getinfo_item_t getinfo_items[] = { - ITEM("version", misc, "The current version of Tor."), - ITEM("bw-event-cache", misc, "Cached BW events for a short interval."), - ITEM("config-file", misc, "Current location of the \"torrc\" file."), - ITEM("config-defaults-file", misc, "Current location of the defaults file."), - ITEM("config-text", misc, - "Return the string that would be written by a saveconf command."), - ITEM("config-can-saveconf", misc, - "Is it possible to save the configuration to the \"torrc\" file?"), - ITEM("accounting/bytes", accounting, - "Number of bytes read/written so far in the accounting interval."), - ITEM("accounting/bytes-left", accounting, - "Number of bytes left to write/read so far in the accounting interval."), - ITEM("accounting/enabled", accounting, "Is accounting currently enabled?"), - ITEM("accounting/hibernating", accounting, "Are we hibernating or awake?"), - ITEM("accounting/interval-start", accounting, - "Time when the accounting period starts."), - ITEM("accounting/interval-end", accounting, - "Time when the accounting period ends."), - ITEM("accounting/interval-wake", accounting, - "Time to wake up in this accounting period."), - ITEM("helper-nodes", entry_guards, NULL), /* deprecated */ - ITEM("entry-guards", entry_guards, - "Which nodes are we using as entry guards?"), - ITEM("fingerprint", misc, NULL), - PREFIX("config/", config, "Current configuration values."), - DOC("config/names", - "List of configuration options, types, and documentation."), - DOC("config/defaults", - "List of default values for configuration options. " - "See also config/names"), - PREFIX("current-time/", current_time, "Current time."), - DOC("current-time/local", "Current time on the local system."), - DOC("current-time/utc", "Current UTC time."), - PREFIX("downloads/networkstatus/", downloads, - "Download statuses for networkstatus objects"), - DOC("downloads/networkstatus/ns", - "Download status for current-mode networkstatus download"), - DOC("downloads/networkstatus/ns/bootstrap", - "Download status for bootstrap-time networkstatus download"), - DOC("downloads/networkstatus/ns/running", - "Download status for run-time networkstatus download"), - DOC("downloads/networkstatus/microdesc", - "Download status for current-mode microdesc download"), - DOC("downloads/networkstatus/microdesc/bootstrap", - "Download status for bootstrap-time microdesc download"), - DOC("downloads/networkstatus/microdesc/running", - "Download status for run-time microdesc download"), - PREFIX("downloads/cert/", downloads, - "Download statuses for certificates, by id fingerprint and " - "signing key"), - DOC("downloads/cert/fps", - "List of authority fingerprints for which any download statuses " - "exist"), - DOC("downloads/cert/fp/", - "Download status for with the default signing key; corresponds " - "to /fp/ URLs on directory server."), - DOC("downloads/cert/fp//sks", - "List of signing keys for which specific download statuses are " - "available for this id fingerprint"), - DOC("downloads/cert/fp//", - "Download status for with signing key ; corresponds " - "to /fp-sk/ URLs on directory server."), - PREFIX("downloads/desc/", downloads, - "Download statuses for router descriptors, by descriptor digest"), - DOC("downloads/desc/descs", - "Return a list of known router descriptor digests"), - DOC("downloads/desc/", - "Return a download status for a given descriptor digest"), - PREFIX("downloads/bridge/", downloads, - "Download statuses for bridge descriptors, by bridge identity " - "digest"), - DOC("downloads/bridge/bridges", - "Return a list of configured bridge identity digests with download " - "statuses"), - DOC("downloads/bridge/", - "Return a download status for a given bridge identity digest"), - ITEM("info/names", misc, - "List of GETINFO options, types, and documentation."), - ITEM("events/names", misc, - "Events that the controller can ask for with SETEVENTS."), - ITEM("signal/names", misc, "Signal names recognized by the SIGNAL command"), - ITEM("features/names", misc, "What arguments can USEFEATURE take?"), - PREFIX("desc/id/", dir, "Router descriptors by ID."), - PREFIX("desc/name/", dir, "Router descriptors by nickname."), - ITEM("desc/all-recent", dir, - "All non-expired, non-superseded router descriptors."), - ITEM("desc/download-enabled", dir, - "Do we try to download router descriptors?"), - ITEM("desc/all-recent-extrainfo-hack", dir, NULL), /* Hack. */ - ITEM("md/all", dir, "All known microdescriptors."), - PREFIX("md/id/", dir, "Microdescriptors by ID"), - PREFIX("md/name/", dir, "Microdescriptors by name"), - ITEM("md/download-enabled", dir, - "Do we try to download microdescriptors?"), - PREFIX("extra-info/digest/", dir, "Extra-info documents by digest."), - PREFIX("hs/client/desc/id", dir, - "Hidden Service descriptor in client's cache by onion."), - PREFIX("hs/service/desc/id/", dir, - "Hidden Service descriptor in services's cache by onion."), - PREFIX("net/listeners/", listeners, "Bound addresses by type"), - ITEM("ns/all", networkstatus, - "Brief summary of router status (v2 directory format)"), - PREFIX("ns/id/", networkstatus, - "Brief summary of router status by ID (v2 directory format)."), - PREFIX("ns/name/", networkstatus, - "Brief summary of router status by nickname (v2 directory format)."), - PREFIX("ns/purpose/", networkstatus, - "Brief summary of router status by purpose (v2 directory format)."), - PREFIX("consensus/", networkstatus, - "Information about and from the ns consensus."), - ITEM("network-status", dir, - "Brief summary of router status (v1 directory format)"), - ITEM("network-liveness", liveness, - "Current opinion on whether the network is live"), - ITEM("circuit-status", events, "List of current circuits originating here."), - ITEM("stream-status", events,"List of current streams."), - ITEM("orconn-status", events, "A list of current OR connections."), - ITEM("dormant", misc, - "Is Tor dormant (not building circuits because it's idle)?"), - PREFIX("address-mappings/", events, NULL), - DOC("address-mappings/all", "Current address mappings."), - DOC("address-mappings/cache", "Current cached DNS replies."), - DOC("address-mappings/config", - "Current address mappings from configuration."), - DOC("address-mappings/control", "Current address mappings from controller."), - PREFIX("status/", events, NULL), - DOC("status/circuit-established", - "Whether we think client functionality is working."), - DOC("status/enough-dir-info", - "Whether we have enough up-to-date directory information to build " - "circuits."), - DOC("status/bootstrap-phase", - "The last bootstrap phase status event that Tor sent."), - DOC("status/clients-seen", - "Breakdown of client countries seen by a bridge."), - DOC("status/fresh-relay-descs", - "A fresh relay/ei descriptor pair for Tor's current state. Not stored."), - DOC("status/version/recommended", "List of currently recommended versions."), - DOC("status/version/current", "Status of the current version."), - ITEM("address", misc, "IP address of this Tor host, if we can guess it."), - ITEM("traffic/read", misc,"Bytes read since the process was started."), - ITEM("traffic/written", misc, - "Bytes written since the process was started."), - ITEM("uptime", misc, "Uptime of the Tor daemon in seconds."), - ITEM("process/pid", misc, "Process id belonging to the main tor process."), - ITEM("process/uid", misc, "User id running the tor process."), - ITEM("process/user", misc, - "Username under which the tor process is running."), - ITEM("process/descriptor-limit", misc, "File descriptor limit."), - ITEM("limits/max-mem-in-queues", misc, "Actual limit on memory in queues"), - PREFIX("desc-annotations/id/", dir, "Router annotations by hexdigest."), - PREFIX("dir/server/", dir,"Router descriptors as retrieved from a DirPort."), - PREFIX("dir/status/", dir, - "v2 networkstatus docs as retrieved from a DirPort."), - ITEM("dir/status-vote/current/consensus", dir, - "v3 Networkstatus consensus as retrieved from a DirPort."), - ITEM("exit-policy/default", policies, - "The default value appended to the configured exit policy."), - ITEM("exit-policy/reject-private/default", policies, - "The default rules appended to the configured exit policy by" - " ExitPolicyRejectPrivate."), - ITEM("exit-policy/reject-private/relay", policies, - "The relay-specific rules appended to the configured exit policy by" - " ExitPolicyRejectPrivate and/or ExitPolicyRejectLocalInterfaces."), - ITEM("exit-policy/full", policies, "The entire exit policy of onion router"), - ITEM("exit-policy/ipv4", policies, "IPv4 parts of exit policy"), - ITEM("exit-policy/ipv6", policies, "IPv6 parts of exit policy"), - PREFIX("ip-to-country/", geoip, "Perform a GEOIP lookup"), - ITEM("onions/current", onions, - "Onion services owned by the current control connection."), - ITEM("onions/detached", onions, - "Onion services detached from the control connection."), - ITEM("sr/current", sr, "Get current shared random value."), - ITEM("sr/previous", sr, "Get previous shared random value."), - { NULL, NULL, NULL, 0 } -}; - -/** Allocate and return a list of recognized GETINFO options. */ -static char * -list_getinfo_options(void) -{ - int i; - smartlist_t *lines = smartlist_new(); - char *ans; - for (i = 0; getinfo_items[i].varname; ++i) { - if (!getinfo_items[i].desc) - continue; - - smartlist_add_asprintf(lines, "%s%s -- %s\n", - getinfo_items[i].varname, - getinfo_items[i].is_prefix ? "*" : "", - getinfo_items[i].desc); - } - smartlist_sort_strings(lines); - - ans = smartlist_join_strings(lines, "", 0, NULL); - SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); - smartlist_free(lines); - - return ans; -} - -/** Lookup the 'getinfo' entry question, and return - * the answer in *answer (or NULL if key not recognized). - * Return 0 if success or unrecognized, or -1 if recognized but - * internal error. */ -static int -handle_getinfo_helper(control_connection_t *control_conn, - const char *question, char **answer, - const char **err_out) -{ - int i; - *answer = NULL; /* unrecognized key by default */ - - for (i = 0; getinfo_items[i].varname; ++i) { - int match; - if (getinfo_items[i].is_prefix) - match = !strcmpstart(question, getinfo_items[i].varname); - else - match = !strcmp(question, getinfo_items[i].varname); - if (match) { - tor_assert(getinfo_items[i].fn); - return getinfo_items[i].fn(control_conn, question, answer, err_out); - } - } - - return 0; /* unrecognized */ -} - -/** Called when we receive a GETINFO command. Try to fetch all requested - * information, and reply with information or error message. */ -static int -handle_control_getinfo(control_connection_t *conn, uint32_t len, - const char *body) -{ - smartlist_t *questions = smartlist_new(); - smartlist_t *answers = smartlist_new(); - smartlist_t *unrecognized = smartlist_new(); - char *ans = NULL; - int i; - (void) len; /* body is NUL-terminated, so it's safe to ignore the length. */ - - smartlist_split_string(questions, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - SMARTLIST_FOREACH_BEGIN(questions, const char *, q) { - const char *errmsg = NULL; - - if (handle_getinfo_helper(conn, q, &ans, &errmsg) < 0) { - if (!errmsg) - errmsg = "Internal error"; - connection_printf_to_buf(conn, "551 %s\r\n", errmsg); - 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); - } else { - smartlist_add_strdup(answers, q); - smartlist_add(answers, 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) - connection_printf_to_buf(conn, - "552-%s\r\n", - (char *)smartlist_get(unrecognized, i)); - - connection_printf_to_buf(conn, - "552 %s\r\n", - (char *)smartlist_get(unrecognized, i)); - 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')) { - connection_printf_to_buf(conn, "250-%s=", k); - connection_write_str_to_buf(v, conn); - connection_write_str_to_buf("\r\n", conn); - } else { - char *esc = NULL; - size_t esc_len; - esc_len = write_escaped_data(v, strlen(v), &esc); - connection_printf_to_buf(conn, "250+%s=\r\n", k); - connection_buf_add(esc, esc_len, TO_CONN(conn)); - tor_free(esc); - } - } - connection_write_str_to_buf("250 OK\r\n", conn); - - done: - SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp)); - smartlist_free(answers); - SMARTLIST_FOREACH(questions, char *, cp, tor_free(cp)); - smartlist_free(questions); - SMARTLIST_FOREACH(unrecognized, char *, cp, tor_free(cp)); - smartlist_free(unrecognized); - - return 0; -} - -/** Given a string, convert it to a circuit purpose. */ -static uint8_t -circuit_purpose_from_string(const char *string) -{ - if (!strcasecmpstart(string, "purpose=")) - string += strlen("purpose="); - - if (!strcasecmp(string, "general")) - return CIRCUIT_PURPOSE_C_GENERAL; - else if (!strcasecmp(string, "controller")) - return CIRCUIT_PURPOSE_CONTROLLER; - else - return CIRCUIT_PURPOSE_UNKNOWN; -} - -/** Return a newly allocated smartlist containing the arguments to the command - * waiting in body. If there are fewer than min_args arguments, - * or if max_args is nonnegative and there are more than - * max_args arguments, send a 512 error to the controller, using - * command as the command name in the error message. */ -static smartlist_t * -getargs_helper(const char *command, control_connection_t *conn, - const char *body, int min_args, int max_args) -{ - smartlist_t *args = smartlist_new(); - smartlist_split_string(args, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - if (smartlist_len(args) < min_args) { - connection_printf_to_buf(conn, "512 Missing argument to %s\r\n",command); - goto err; - } else if (max_args >= 0 && smartlist_len(args) > max_args) { - connection_printf_to_buf(conn, "512 Too many arguments to %s\r\n",command); - goto err; - } - return args; - err: - SMARTLIST_FOREACH(args, char *, s, tor_free(s)); - smartlist_free(args); - return NULL; -} - -/** Helper. Return the first element of sl at index start_at or - * higher that starts with prefix, case-insensitive. Return NULL if no - * such element exists. */ -static const char * -find_element_starting_with(smartlist_t *sl, int start_at, const char *prefix) -{ - int i; - for (i = start_at; i < smartlist_len(sl); ++i) { - const char *elt = smartlist_get(sl, i); - if (!strcasecmpstart(elt, prefix)) - return elt; - } - return NULL; -} - -/** Helper. Return true iff s is an argument that we should treat as a - * key-value pair. */ -static int -is_keyval_pair(const char *s) -{ - /* An argument is a key-value pair if it has an =, and it isn't of the form - * $fingeprint=name */ - return strchr(s, '=') && s[0] != '$'; -} - -/** Called when we get an EXTENDCIRCUIT message. Try to extend the listed - * circuit, and report success or failure. */ -static int -handle_control_extendcircuit(control_connection_t *conn, uint32_t len, - const char *body) -{ - smartlist_t *router_nicknames=NULL, *nodes=NULL; - origin_circuit_t *circ = NULL; - int zero_circ; - uint8_t intended_purpose = CIRCUIT_PURPOSE_C_GENERAL; - smartlist_t *args; - (void) len; - - router_nicknames = smartlist_new(); - - args = getargs_helper("EXTENDCIRCUIT", conn, body, 1, -1); - if (!args) - goto done; - - zero_circ = !strcmp("0", (char*)smartlist_get(args,0)); - - if (zero_circ) { - const char *purp = find_element_starting_with(args, 1, "PURPOSE="); - - if (purp) { - intended_purpose = circuit_purpose_from_string(purp); - if (intended_purpose == CIRCUIT_PURPOSE_UNKNOWN) { - connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", purp); - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - goto done; - } - } - - if ((smartlist_len(args) == 1) || - (smartlist_len(args) >= 2 && is_keyval_pair(smartlist_get(args, 1)))) { - // "EXTENDCIRCUIT 0" || EXTENDCIRCUIT 0 foo=bar" - circ = circuit_launch(intended_purpose, CIRCLAUNCH_NEED_CAPACITY); - if (!circ) { - connection_write_str_to_buf("551 Couldn't start circuit\r\n", conn); - } else { - connection_printf_to_buf(conn, "250 EXTENDED %lu\r\n", - (unsigned long)circ->global_identifier); - } - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - goto done; - } - // "EXTENDCIRCUIT 0 router1,router2" || - // "EXTENDCIRCUIT 0 router1,router2 PURPOSE=foo" - } - - if (!zero_circ && !(circ = get_circ(smartlist_get(args,0)))) { - connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n", - (char*)smartlist_get(args, 0)); - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - goto done; - } - - if (smartlist_len(args) < 2) { - connection_printf_to_buf(conn, - "512 syntax error: not enough arguments.\r\n"); - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - goto done; - } - - smartlist_split_string(router_nicknames, smartlist_get(args,1), ",", 0, 0); - - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - - nodes = smartlist_new(); - int first_node = zero_circ; - SMARTLIST_FOREACH_BEGIN(router_nicknames, const char *, n) { - const node_t *node = node_get_by_nickname(n, 0); - if (!node) { - connection_printf_to_buf(conn, "552 No such router \"%s\"\r\n", n); - goto done; - } - if (!node_has_preferred_descriptor(node, first_node)) { - connection_printf_to_buf(conn, "552 No descriptor for \"%s\"\r\n", n); - goto done; - } - smartlist_add(nodes, (void*)node); - first_node = 0; - } SMARTLIST_FOREACH_END(n); - if (!smartlist_len(nodes)) { - connection_write_str_to_buf("512 No router names provided\r\n", conn); - goto done; - } - - if (zero_circ) { - /* start a new circuit */ - circ = origin_circuit_init(intended_purpose, 0); - } - - /* now circ refers to something that is ready to be extended */ - first_node = zero_circ; - SMARTLIST_FOREACH(nodes, const node_t *, node, - { - extend_info_t *info = extend_info_from_node(node, first_node); - if (!info) { - tor_assert_nonfatal(first_node); - log_warn(LD_CONTROL, - "controller tried to connect to a node that lacks a suitable " - "descriptor, or which doesn't have any " - "addresses that are allowed by the firewall configuration; " - "circuit marked for closing."); - circuit_mark_for_close(TO_CIRCUIT(circ), -END_CIRC_REASON_CONNECTFAILED); - connection_write_str_to_buf("551 Couldn't start circuit\r\n", conn); - goto done; - } - circuit_append_new_exit(circ, info); - if (circ->build_state->desired_path_len > 1) { - circ->build_state->onehop_tunnel = 0; - } - extend_info_free(info); - first_node = 0; - }); - - /* now that we've populated the cpath, start extending */ - if (zero_circ) { - int err_reason = 0; - if ((err_reason = circuit_handle_first_hop(circ)) < 0) { - circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason); - connection_write_str_to_buf("551 Couldn't start circuit\r\n", conn); - goto done; - } - } else { - if (circ->base_.state == CIRCUIT_STATE_OPEN || - circ->base_.state == CIRCUIT_STATE_GUARD_WAIT) { - int err_reason = 0; - circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING); - if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) { - log_info(LD_CONTROL, - "send_next_onion_skin failed; circuit marked for closing."); - circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason); - connection_write_str_to_buf("551 Couldn't send onion skin\r\n", conn); - goto done; - } - } - } - - connection_printf_to_buf(conn, "250 EXTENDED %lu\r\n", - (unsigned long)circ->global_identifier); - if (zero_circ) /* send a 'launched' event, for completeness */ - circuit_event_status(circ, CIRC_EVENT_LAUNCHED, 0); - done: - SMARTLIST_FOREACH(router_nicknames, char *, n, tor_free(n)); - smartlist_free(router_nicknames); - smartlist_free(nodes); - return 0; -} - -/** Called when we get a SETCIRCUITPURPOSE message. If we can find the - * circuit and it's a valid purpose, change it. */ -static int -handle_control_setcircuitpurpose(control_connection_t *conn, - uint32_t len, const char *body) -{ - origin_circuit_t *circ = NULL; - uint8_t new_purpose; - smartlist_t *args; - (void) len; /* body is NUL-terminated, so it's safe to ignore the length. */ - - args = getargs_helper("SETCIRCUITPURPOSE", conn, body, 2, -1); - if (!args) - goto done; - - if (!(circ = get_circ(smartlist_get(args,0)))) { - connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n", - (char*)smartlist_get(args, 0)); - goto done; - } - - { - const char *purp = find_element_starting_with(args,1,"PURPOSE="); - if (!purp) { - connection_write_str_to_buf("552 No purpose given\r\n", conn); - goto done; - } - new_purpose = circuit_purpose_from_string(purp); - if (new_purpose == CIRCUIT_PURPOSE_UNKNOWN) { - connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", purp); - goto done; - } - } - - circuit_change_purpose(TO_CIRCUIT(circ), new_purpose); - connection_write_str_to_buf("250 OK\r\n", conn); - - done: - if (args) { - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - } - return 0; -} - -/** Called when we get an ATTACHSTREAM message. Try to attach the requested - * stream, and report success or failure. */ -static int -handle_control_attachstream(control_connection_t *conn, uint32_t len, - const char *body) -{ - entry_connection_t *ap_conn = NULL; - origin_circuit_t *circ = NULL; - int zero_circ; - smartlist_t *args; - crypt_path_t *cpath=NULL; - int hop=0, hop_line_ok=1; - (void) len; - - args = getargs_helper("ATTACHSTREAM", conn, body, 2, -1); - if (!args) - return 0; - - zero_circ = !strcmp("0", (char*)smartlist_get(args,1)); - - if (!(ap_conn = get_stream(smartlist_get(args, 0)))) { - connection_printf_to_buf(conn, "552 Unknown stream \"%s\"\r\n", - (char*)smartlist_get(args, 0)); - } else if (!zero_circ && !(circ = get_circ(smartlist_get(args, 1)))) { - connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n", - (char*)smartlist_get(args, 1)); - } else if (circ) { - const char *hopstring = find_element_starting_with(args,2,"HOP="); - if (hopstring) { - hopstring += strlen("HOP="); - hop = (int) tor_parse_ulong(hopstring, 10, 0, INT_MAX, - &hop_line_ok, NULL); - if (!hop_line_ok) { /* broken hop line */ - connection_printf_to_buf(conn, "552 Bad value hop=%s\r\n", hopstring); - } - } - } - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - if (!ap_conn || (!zero_circ && !circ) || !hop_line_ok) - return 0; - - if (ENTRY_TO_CONN(ap_conn)->state != AP_CONN_STATE_CONTROLLER_WAIT && - ENTRY_TO_CONN(ap_conn)->state != AP_CONN_STATE_CONNECT_WAIT && - ENTRY_TO_CONN(ap_conn)->state != AP_CONN_STATE_RESOLVE_WAIT) { - connection_write_str_to_buf( - "555 Connection is not managed by controller.\r\n", - conn); - return 0; - } - - /* Do we need to detach it first? */ - if (ENTRY_TO_CONN(ap_conn)->state != AP_CONN_STATE_CONTROLLER_WAIT) { - edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn); - circuit_t *tmpcirc = circuit_get_by_edge_conn(edge_conn); - connection_edge_end(edge_conn, END_STREAM_REASON_TIMEOUT); - /* Un-mark it as ending, since we're going to reuse it. */ - edge_conn->edge_has_sent_end = 0; - edge_conn->end_reason = 0; - if (tmpcirc) - circuit_detach_stream(tmpcirc, edge_conn); - CONNECTION_AP_EXPECT_NONPENDING(ap_conn); - TO_CONN(edge_conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; - } - - if (circ && (circ->base_.state != CIRCUIT_STATE_OPEN)) { - connection_write_str_to_buf( - "551 Can't attach stream to non-open origin circuit\r\n", - conn); - return 0; - } - /* Is this a single hop circuit? */ - if (circ && (circuit_get_cpath_len(circ)<2 || hop==1)) { - connection_write_str_to_buf( - "551 Can't attach stream to this one-hop circuit.\r\n", conn); - return 0; - } - - if (circ && hop>0) { - /* find this hop in the circuit, and set cpath */ - cpath = circuit_get_cpath_hop(circ, hop); - if (!cpath) { - connection_printf_to_buf(conn, - "551 Circuit doesn't have %d hops.\r\n", hop); - return 0; - } - } - if (connection_ap_handshake_rewrite_and_attach(ap_conn, circ, cpath) < 0) { - connection_write_str_to_buf("551 Unable to attach stream\r\n", conn); - return 0; - } - send_control_done(conn); - return 0; -} - -/** Called when we get a POSTDESCRIPTOR message. Try to learn the provided - * descriptor, and report success or failure. */ -static int -handle_control_postdescriptor(control_connection_t *conn, uint32_t len, - const char *body) -{ - char *desc; - const char *msg=NULL; - uint8_t purpose = ROUTER_PURPOSE_GENERAL; - int cache = 0; /* eventually, we may switch this to 1 */ - - const char *cp = memchr(body, '\n', len); - - if (cp == NULL) { - connection_printf_to_buf(conn, "251 Empty body\r\n"); - return 0; - } - ++cp; - - char *cmdline = tor_memdup_nulterm(body, cp-body); - smartlist_t *args = smartlist_new(); - smartlist_split_string(args, cmdline, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - SMARTLIST_FOREACH_BEGIN(args, char *, option) { - if (!strcasecmpstart(option, "purpose=")) { - option += strlen("purpose="); - purpose = router_purpose_from_string(option); - if (purpose == ROUTER_PURPOSE_UNKNOWN) { - connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", - option); - goto done; - } - } else if (!strcasecmpstart(option, "cache=")) { - option += strlen("cache="); - if (!strcasecmp(option, "no")) - cache = 0; - else if (!strcasecmp(option, "yes")) - cache = 1; - else { - connection_printf_to_buf(conn, "552 Unknown cache request \"%s\"\r\n", - option); - goto done; - } - } else { /* unrecognized argument? */ - connection_printf_to_buf(conn, - "512 Unexpected argument \"%s\" to postdescriptor\r\n", option); - goto done; - } - } SMARTLIST_FOREACH_END(option); - - read_escaped_data(cp, len-(cp-body), &desc); - - switch (router_load_single_router(desc, purpose, cache, &msg)) { - case -1: - if (!msg) msg = "Could not parse descriptor"; - connection_printf_to_buf(conn, "554 %s\r\n", msg); - break; - case 0: - if (!msg) msg = "Descriptor not added"; - connection_printf_to_buf(conn, "251 %s\r\n",msg); - break; - case 1: - send_control_done(conn); - break; - } - - tor_free(desc); - done: - SMARTLIST_FOREACH(args, char *, arg, tor_free(arg)); - smartlist_free(args); - tor_free(cmdline); - return 0; -} - -/** Called when we receive a REDIRECTSTERAM command. Try to change the target - * address of the named AP stream, and report success or failure. */ -static int -handle_control_redirectstream(control_connection_t *conn, uint32_t len, - const char *body) -{ - entry_connection_t *ap_conn = NULL; - char *new_addr = NULL; - uint16_t new_port = 0; - smartlist_t *args; - (void) len; - - args = getargs_helper("REDIRECTSTREAM", conn, body, 2, -1); - if (!args) - return 0; - - if (!(ap_conn = get_stream(smartlist_get(args, 0))) - || !ap_conn->socks_request) { - connection_printf_to_buf(conn, "552 Unknown stream \"%s\"\r\n", - (char*)smartlist_get(args, 0)); - } else { - int ok = 1; - if (smartlist_len(args) > 2) { /* they included a port too */ - new_port = (uint16_t) tor_parse_ulong(smartlist_get(args, 2), - 10, 1, 65535, &ok, NULL); - } - if (!ok) { - connection_printf_to_buf(conn, "512 Cannot parse port \"%s\"\r\n", - (char*)smartlist_get(args, 2)); - } else { - new_addr = tor_strdup(smartlist_get(args, 1)); - } - } - - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - if (!new_addr) - return 0; - - strlcpy(ap_conn->socks_request->address, new_addr, - sizeof(ap_conn->socks_request->address)); - if (new_port) - ap_conn->socks_request->port = new_port; - tor_free(new_addr); - send_control_done(conn); - return 0; -} - -/** Called when we get a CLOSESTREAM command; try to close the named stream - * and report success or failure. */ -static int -handle_control_closestream(control_connection_t *conn, uint32_t len, - const char *body) -{ - entry_connection_t *ap_conn=NULL; - uint8_t reason=0; - smartlist_t *args; - int ok; - (void) len; - - args = getargs_helper("CLOSESTREAM", conn, body, 2, -1); - if (!args) - return 0; - - else if (!(ap_conn = get_stream(smartlist_get(args, 0)))) - connection_printf_to_buf(conn, "552 Unknown stream \"%s\"\r\n", - (char*)smartlist_get(args, 0)); - else { - reason = (uint8_t) tor_parse_ulong(smartlist_get(args,1), 10, 0, 255, - &ok, NULL); - if (!ok) { - connection_printf_to_buf(conn, "552 Unrecognized reason \"%s\"\r\n", - (char*)smartlist_get(args, 1)); - ap_conn = NULL; - } - } - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - if (!ap_conn) - return 0; - - connection_mark_unattached_ap(ap_conn, reason); - send_control_done(conn); - return 0; -} - -/** Called when we get a CLOSECIRCUIT command; try to close the named circuit - * and report success or failure. */ -static int -handle_control_closecircuit(control_connection_t *conn, uint32_t len, - const char *body) -{ - origin_circuit_t *circ = NULL; - int safe = 0; - smartlist_t *args; - (void) len; - - args = getargs_helper("CLOSECIRCUIT", conn, body, 1, -1); - if (!args) - return 0; - - if (!(circ=get_circ(smartlist_get(args, 0)))) - connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n", - (char*)smartlist_get(args, 0)); - else { - int i; - for (i=1; i < smartlist_len(args); ++i) { - if (!strcasecmp(smartlist_get(args, i), "IfUnused")) - safe = 1; - else - log_info(LD_CONTROL, "Skipping unknown option %s", - (char*)smartlist_get(args,i)); - } - } - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - if (!circ) - return 0; - - if (!safe || !circ->p_streams) { - circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_REQUESTED); - } - - send_control_done(conn); - return 0; -} - -/** Called when we get a RESOLVE command: start trying to resolve - * the listed addresses. */ -static int -handle_control_resolve(control_connection_t *conn, uint32_t len, - const char *body) -{ - smartlist_t *args, *failed; - int is_reverse = 0; - (void) len; /* body is nul-terminated; it's safe to ignore the length */ - - if (!(conn->event_mask & (((event_mask_t)1)<have_sent_protocolinfo = 1; - args = smartlist_new(); - smartlist_split_string(args, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - SMARTLIST_FOREACH(args, const char *, arg, { - int ok; - tor_parse_long(arg, 10, 0, LONG_MAX, &ok, NULL); - if (!ok) { - bad_arg = arg; - break; - } - }); - if (bad_arg) { - connection_printf_to_buf(conn, "513 No such version %s\r\n", - escaped(bad_arg)); - /* 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); - } - - connection_printf_to_buf(conn, - "250-PROTOCOLINFO 1\r\n" - "250-AUTH METHODS=%s%s%s\r\n" - "250-VERSION Tor=%s\r\n" - "250 OK\r\n", - methods, - cookies?" COOKIEFILE=":"", - cookies?esc_cfile:"", - escaped(VERSION)); - tor_free(methods); - tor_free(cfile); - tor_free(abs_cfile); - tor_free(esc_cfile); - } - done: - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - return 0; -} - -/** Called when we get an AUTHCHALLENGE command. */ -static int -handle_control_authchallenge(control_connection_t *conn, uint32_t len, - const char *body) -{ - const char *cp = body; - char *client_nonce; - size_t client_nonce_len; - char server_hash[DIGEST256_LEN]; - char server_hash_encoded[HEX_DIGEST256_LEN+1]; - char server_nonce[SAFECOOKIE_SERVER_NONCE_LEN]; - char server_nonce_encoded[(2*SAFECOOKIE_SERVER_NONCE_LEN) + 1]; - - cp += strspn(cp, " \t\n\r"); - if (!strcasecmpstart(cp, "SAFECOOKIE")) { - cp += strlen("SAFECOOKIE"); - } else { - connection_write_str_to_buf("513 AUTHCHALLENGE only supports SAFECOOKIE " - "authentication\r\n", conn); - connection_mark_for_close(TO_CONN(conn)); - return -1; - } - - if (!authentication_cookie_is_set) { - connection_write_str_to_buf("515 Cookie authentication is disabled\r\n", - conn); - connection_mark_for_close(TO_CONN(conn)); - return -1; - } - - cp += strspn(cp, " \t\n\r"); - if (*cp == '"') { - const char *newcp = - decode_escaped_string(cp, len - (cp - body), - &client_nonce, &client_nonce_len); - if (newcp == NULL) { - connection_write_str_to_buf("513 Invalid quoted client nonce\r\n", - conn); - connection_mark_for_close(TO_CONN(conn)); - return -1; - } - cp = newcp; - } else { - size_t client_nonce_encoded_len = strspn(cp, "0123456789ABCDEFabcdef"); - - client_nonce_len = client_nonce_encoded_len / 2; - client_nonce = tor_malloc_zero(client_nonce_len); - - if (base16_decode(client_nonce, client_nonce_len, - cp, client_nonce_encoded_len) - != (int) client_nonce_len) { - connection_write_str_to_buf("513 Invalid base16 client nonce\r\n", - conn); - connection_mark_for_close(TO_CONN(conn)); - tor_free(client_nonce); - return -1; - } - - cp += client_nonce_encoded_len; - } - - cp += strspn(cp, " \t\n\r"); - if (*cp != '\0' || - cp != body + len) { - connection_write_str_to_buf("513 Junk at end of AUTHCHALLENGE command\r\n", - conn); - connection_mark_for_close(TO_CONN(conn)); - tor_free(client_nonce); - return -1; - } - crypto_rand(server_nonce, SAFECOOKIE_SERVER_NONCE_LEN); - - /* Now compute and send the server-to-controller response, and the - * server's nonce. */ - tor_assert(authentication_cookie != NULL); - - { - size_t tmp_len = (AUTHENTICATION_COOKIE_LEN + - client_nonce_len + - SAFECOOKIE_SERVER_NONCE_LEN); - char *tmp = tor_malloc_zero(tmp_len); - char *client_hash = tor_malloc_zero(DIGEST256_LEN); - memcpy(tmp, authentication_cookie, AUTHENTICATION_COOKIE_LEN); - memcpy(tmp + AUTHENTICATION_COOKIE_LEN, client_nonce, client_nonce_len); - memcpy(tmp + AUTHENTICATION_COOKIE_LEN + client_nonce_len, - server_nonce, SAFECOOKIE_SERVER_NONCE_LEN); - - crypto_hmac_sha256(server_hash, - SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT, - strlen(SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT), - tmp, - tmp_len); - - crypto_hmac_sha256(client_hash, - SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT, - strlen(SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT), - tmp, - tmp_len); - - conn->safecookie_client_hash = client_hash; - - tor_free(tmp); - } - - base16_encode(server_hash_encoded, sizeof(server_hash_encoded), - server_hash, sizeof(server_hash)); - base16_encode(server_nonce_encoded, sizeof(server_nonce_encoded), - server_nonce, sizeof(server_nonce)); - - connection_printf_to_buf(conn, - "250 AUTHCHALLENGE SERVERHASH=%s " - "SERVERNONCE=%s\r\n", - server_hash_encoded, - server_nonce_encoded); - - tor_free(client_nonce); - return 0; -} - -/** Called when we get a USEFEATURE command: parse the feature list, and - * set up the control_connection's options properly. */ -static int -handle_control_usefeature(control_connection_t *conn, - uint32_t len, - const char *body) -{ - smartlist_t *args; - int bad = 0; - (void) len; /* body is nul-terminated; it's safe to ignore the length */ - args = smartlist_new(); - smartlist_split_string(args, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - SMARTLIST_FOREACH_BEGIN(args, const char *, arg) { - if (!strcasecmp(arg, "VERBOSE_NAMES")) - ; - else if (!strcasecmp(arg, "EXTENDED_EVENTS")) - ; - else { - connection_printf_to_buf(conn, "552 Unrecognized feature \"%s\"\r\n", - arg); - bad = 1; - break; - } - } SMARTLIST_FOREACH_END(arg); - - if (!bad) { - send_control_done(conn); - } - - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - return 0; -} - -/** Implementation for the DROPGUARDS command. */ -static int -handle_control_dropguards(control_connection_t *conn, - uint32_t len, - const char *body) -{ - smartlist_t *args; - (void) len; /* body is nul-terminated; it's safe to ignore the length */ - args = smartlist_new(); - smartlist_split_string(args, body, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - - static int have_warned = 0; - if (! have_warned) { - log_warn(LD_CONTROL, "DROPGUARDS is dangerous; make sure you understand " - "the risks before using it. It may be removed in a future " - "version of Tor."); - have_warned = 1; - } - - if (smartlist_len(args)) { - connection_printf_to_buf(conn, "512 Too many arguments to DROPGUARDS\r\n"); - } else { - remove_all_entry_guards(); - send_control_done(conn); - } - - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - return 0; -} - -/** Implementation for the HSFETCH command. */ -static int -handle_control_hsfetch(control_connection_t *conn, uint32_t len, - const char *body) -{ - int i; - char digest[DIGEST_LEN], *hsaddress = NULL, *arg1 = NULL, *desc_id = NULL; - smartlist_t *args = NULL, *hsdirs = NULL; - (void) len; /* body is nul-terminated; it's safe to ignore the length */ - static const char *hsfetch_command = "HSFETCH"; - static const char *v2_str = "v2-"; - const size_t v2_str_len = strlen(v2_str); - rend_data_t *rend_query = NULL; - - /* Make sure we have at least one argument, the HSAddress. */ - args = getargs_helper(hsfetch_command, conn, body, 1, -1); - if (!args) { - goto exit; - } - - /* Extract the first argument (either HSAddress or DescID). */ - arg1 = smartlist_get(args, 0); - /* Test if it's an HS address without the .onion part. */ - if (rend_valid_v2_service_id(arg1)) { - hsaddress = arg1; - } else if (strcmpstart(arg1, v2_str) == 0 && - rend_valid_descriptor_id(arg1 + v2_str_len) && - base32_decode(digest, sizeof(digest), arg1 + v2_str_len, - REND_DESC_ID_V2_LEN_BASE32) == 0) { - /* We have a well formed version 2 descriptor ID. Keep the decoded value - * of the id. */ - desc_id = digest; - } else { - connection_printf_to_buf(conn, "513 Invalid argument \"%s\"\r\n", - arg1); - goto done; - } - - static const char *opt_server = "SERVER="; - - /* Skip first argument because it's the HSAddress or DescID. */ - for (i = 1; i < smartlist_len(args); ++i) { - const char *arg = smartlist_get(args, i); - const node_t *node; - - if (!strcasecmpstart(arg, opt_server)) { - const char *server; - - server = arg + strlen(opt_server); - node = node_get_by_hex_id(server, 0); - if (!node) { - connection_printf_to_buf(conn, "552 Server \"%s\" not found\r\n", - server); - goto done; - } - if (!hsdirs) { - /* Stores routerstatus_t object for each specified server. */ - hsdirs = smartlist_new(); - } - /* Valid server, add it to our local list. */ - smartlist_add(hsdirs, node->rs); - } else { - connection_printf_to_buf(conn, "513 Unexpected argument \"%s\"\r\n", - arg); - goto done; - } - } - - rend_query = rend_data_client_create(hsaddress, desc_id, NULL, - REND_NO_AUTH); - if (rend_query == NULL) { - connection_printf_to_buf(conn, "551 Error creating the HS query\r\n"); - goto done; - } - - /* Using a descriptor ID, we force the user to provide at least one - * hsdir server using the SERVER= option. */ - if (desc_id && (!hsdirs || !smartlist_len(hsdirs))) { - connection_printf_to_buf(conn, "512 %s option is required\r\n", - opt_server); - goto done; - } - - /* We are about to trigger HSDir fetch so send the OK now because after - * that 650 event(s) are possible so better to have the 250 OK before them - * to avoid out of order replies. */ - send_control_done(conn); - - /* Trigger the fetch using the built rend query and possibly a list of HS - * directory to use. This function ignores the client cache thus this will - * always send a fetch command. */ - rend_client_fetch_v2_desc(rend_query, hsdirs); - - done: - SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); - smartlist_free(args); - /* Contains data pointer that we don't own thus no cleanup. */ - smartlist_free(hsdirs); - rend_data_free(rend_query); - exit: - return 0; -} - -/** Implementation for the HSPOST command. */ -static int -handle_control_hspost(control_connection_t *conn, - uint32_t len, - const char *body) -{ - static const char *opt_server = "SERVER="; - static const char *opt_hsaddress = "HSADDRESS="; - smartlist_t *hs_dirs = NULL; - const char *encoded_desc = body; - size_t encoded_desc_len = len; - const char *onion_address = NULL; - - char *cp = memchr(body, '\n', len); - if (cp == NULL) { - connection_printf_to_buf(conn, "251 Empty body\r\n"); - return 0; - } - char *argline = tor_strndup(body, cp-body); - - smartlist_t *args = smartlist_new(); - - /* If any SERVER= or HSADDRESS= options were specified, try to parse - * the options line. */ - if (!strcasecmpstart(argline, opt_server) || - !strcasecmpstart(argline, opt_hsaddress)) { - /* encoded_desc begins after a newline character */ - cp = cp + 1; - encoded_desc = cp; - encoded_desc_len = len-(cp-body); - - smartlist_split_string(args, argline, " ", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - SMARTLIST_FOREACH_BEGIN(args, const char *, arg) { - if (!strcasecmpstart(arg, opt_server)) { - const char *server = arg + strlen(opt_server); - const node_t *node = node_get_by_hex_id(server, 0); - - if (!node || !node->rs) { - connection_printf_to_buf(conn, "552 Server \"%s\" not found\r\n", - server); - goto done; - } - /* Valid server, add it to our local list. */ - if (!hs_dirs) - hs_dirs = smartlist_new(); - smartlist_add(hs_dirs, node->rs); - } else if (!strcasecmpstart(arg, opt_hsaddress)) { - const char *address = arg + strlen(opt_hsaddress); - if (!hs_address_is_valid(address)) { - connection_printf_to_buf(conn, "512 Malformed onion address\r\n"); - goto done; - } - onion_address = address; - } else { - connection_printf_to_buf(conn, "512 Unexpected argument \"%s\"\r\n", - arg); - goto done; - } - } SMARTLIST_FOREACH_END(arg); - } - - /* Handle the v3 case. */ - if (onion_address) { - char *desc_str = NULL; - read_escaped_data(encoded_desc, encoded_desc_len, &desc_str); - if (hs_control_hspost_command(desc_str, onion_address, hs_dirs) < 0) { - connection_printf_to_buf(conn, "554 Invalid descriptor\r\n"); - } else { - send_control_done(conn); - } - tor_free(desc_str); - goto done; - } - - /* From this point on, it is only v2. */ - - /* Read the dot encoded descriptor, and parse it. */ - rend_encoded_v2_service_descriptor_t *desc = - tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t)); - read_escaped_data(encoded_desc, encoded_desc_len, &desc->desc_str); - - rend_service_descriptor_t *parsed = NULL; - char *intro_content = NULL; - size_t intro_size; - size_t encoded_size; - const char *next_desc; - if (!rend_parse_v2_service_descriptor(&parsed, desc->desc_id, &intro_content, - &intro_size, &encoded_size, - &next_desc, desc->desc_str, 1)) { - /* Post the descriptor. */ - char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; - if (!rend_get_service_id(parsed->pk, serviceid)) { - smartlist_t *descs = smartlist_new(); - smartlist_add(descs, desc); - - /* We are about to trigger HS descriptor upload so send the OK now - * because after that 650 event(s) are possible so better to have the - * 250 OK before them to avoid out of order replies. */ - send_control_done(conn); - - /* Trigger the descriptor upload */ - directory_post_to_hs_dir(parsed, descs, hs_dirs, serviceid, 0); - smartlist_free(descs); - } - - rend_service_descriptor_free(parsed); - } else { - connection_printf_to_buf(conn, "554 Invalid descriptor\r\n"); - } - - tor_free(intro_content); - rend_encoded_v2_service_descriptor_free(desc); - done: - tor_free(argline); - smartlist_free(hs_dirs); /* Contents belong to the rend service code. */ - SMARTLIST_FOREACH(args, char *, arg, tor_free(arg)); - smartlist_free(args); - return 0; -} - -/* Helper function for ADD_ONION that adds an ephemeral service depending on - * the given hs_version. - * - * The secret key in pk depends on the hs_version. The ownership of the key - * used in pk is given to the HS subsystem so the caller must stop accessing - * it after. - * - * The port_cfgs is a list of service port. Ownership transferred to service. - * The max_streams refers to the MaxStreams= key. - * The max_streams_close_circuit refers to the MaxStreamsCloseCircuit key. - * The auth_type is the authentication type of the clients in auth_clients. - * The ownership of that list is transferred to the service. - * - * On success (RSAE_OKAY), the address_out points to a newly allocated string - * containing the onion address without the .onion part. On error, address_out - * is untouched. */ -static hs_service_add_ephemeral_status_t -add_onion_helper_add_service(int hs_version, - add_onion_secret_key_t *pk, - smartlist_t *port_cfgs, int max_streams, - int max_streams_close_circuit, int auth_type, - smartlist_t *auth_clients, char **address_out) -{ - hs_service_add_ephemeral_status_t ret; - - tor_assert(pk); - tor_assert(port_cfgs); - tor_assert(address_out); - - switch (hs_version) { - case HS_VERSION_TWO: - ret = rend_service_add_ephemeral(pk->v2, port_cfgs, max_streams, - max_streams_close_circuit, auth_type, - auth_clients, address_out); - break; - case HS_VERSION_THREE: - ret = hs_service_add_ephemeral(pk->v3, port_cfgs, max_streams, - max_streams_close_circuit, address_out); - break; - default: - tor_assert_unreached(); - } - - return ret; -} - -/** Called when we get a ADD_ONION command; parse the body, and set up - * the new ephemeral Onion Service. */ -static int -handle_control_add_onion(control_connection_t *conn, - uint32_t len, - const char *body) -{ - smartlist_t *args; - int arg_len; - (void) len; /* body is nul-terminated; it's safe to ignore the length */ - args = getargs_helper("ADD_ONION", conn, body, 2, -1); - if (!args) - return 0; - arg_len = smartlist_len(args); - - /* Parse all of the arguments that do not involve handling cryptographic - * material first, since there's no reason to touch that at all if any of - * the other arguments are malformed. - */ - smartlist_t *port_cfgs = smartlist_new(); - smartlist_t *auth_clients = NULL; - smartlist_t *auth_created_clients = NULL; - int discard_pk = 0; - int detach = 0; - int max_streams = 0; - int max_streams_close_circuit = 0; - rend_auth_type_t auth_type = REND_NO_AUTH; - /* Default to adding an anonymous hidden service if no flag is given */ - int non_anonymous = 0; - for (int i = 1; i < arg_len; i++) { - static const char *port_prefix = "Port="; - static const char *flags_prefix = "Flags="; - static const char *max_s_prefix = "MaxStreams="; - static const char *auth_prefix = "ClientAuth="; - - const char *arg = smartlist_get(args, (int)i); - if (!strcasecmpstart(arg, port_prefix)) { - /* "Port=VIRTPORT[,TARGET]". */ - const char *port_str = arg + strlen(port_prefix); - - rend_service_port_config_t *cfg = - rend_service_parse_port_config(port_str, ",", NULL); - if (!cfg) { - connection_printf_to_buf(conn, "512 Invalid VIRTPORT/TARGET\r\n"); - goto out; - } - smartlist_add(port_cfgs, cfg); - } else if (!strcasecmpstart(arg, max_s_prefix)) { - /* "MaxStreams=[0..65535]". */ - const char *max_s_str = arg + strlen(max_s_prefix); - int ok = 0; - max_streams = (int)tor_parse_long(max_s_str, 10, 0, 65535, &ok, NULL); - if (!ok) { - connection_printf_to_buf(conn, "512 Invalid MaxStreams\r\n"); - goto out; - } - } else if (!strcasecmpstart(arg, flags_prefix)) { - /* "Flags=Flag[,Flag]", where Flag can be: - * * 'DiscardPK' - If tor generates the keypair, do not include it in - * the response. - * * 'Detach' - Do not tie this onion service to any particular control - * connection. - * * 'MaxStreamsCloseCircuit' - Close the circuit if MaxStreams is - * exceeded. - * * 'BasicAuth' - Client authorization using the 'basic' method. - * * 'NonAnonymous' - Add a non-anonymous Single Onion Service. If this - * flag is present, tor must be in non-anonymous - * hidden service mode. If this flag is absent, - * tor must be in anonymous hidden service mode. - */ - static const char *discard_flag = "DiscardPK"; - static const char *detach_flag = "Detach"; - static const char *max_s_close_flag = "MaxStreamsCloseCircuit"; - static const char *basicauth_flag = "BasicAuth"; - static const char *non_anonymous_flag = "NonAnonymous"; - - smartlist_t *flags = smartlist_new(); - int bad = 0; - - smartlist_split_string(flags, arg + strlen(flags_prefix), ",", - SPLIT_IGNORE_BLANK, 0); - if (smartlist_len(flags) < 1) { - connection_printf_to_buf(conn, "512 Invalid 'Flags' argument\r\n"); - bad = 1; - } - SMARTLIST_FOREACH_BEGIN(flags, const char *, flag) - { - if (!strcasecmp(flag, discard_flag)) { - discard_pk = 1; - } else if (!strcasecmp(flag, detach_flag)) { - detach = 1; - } else if (!strcasecmp(flag, max_s_close_flag)) { - max_streams_close_circuit = 1; - } else if (!strcasecmp(flag, basicauth_flag)) { - auth_type = REND_BASIC_AUTH; - } else if (!strcasecmp(flag, non_anonymous_flag)) { - non_anonymous = 1; - } else { - connection_printf_to_buf(conn, - "512 Invalid 'Flags' argument: %s\r\n", - escaped(flag)); - bad = 1; - break; - } - } SMARTLIST_FOREACH_END(flag); - SMARTLIST_FOREACH(flags, char *, cp, tor_free(cp)); - smartlist_free(flags); - if (bad) - goto out; - } else if (!strcasecmpstart(arg, auth_prefix)) { - char *err_msg = NULL; - int created = 0; - rend_authorized_client_t *client = - add_onion_helper_clientauth(arg + strlen(auth_prefix), - &created, &err_msg); - if (!client) { - if (err_msg) { - connection_write_str_to_buf(err_msg, conn); - tor_free(err_msg); - } - goto out; - } - - if (auth_clients != NULL) { - int bad = 0; - SMARTLIST_FOREACH_BEGIN(auth_clients, rend_authorized_client_t *, ac) { - if (strcmp(ac->client_name, client->client_name) == 0) { - bad = 1; - break; - } - } SMARTLIST_FOREACH_END(ac); - if (bad) { - connection_printf_to_buf(conn, - "512 Duplicate name in ClientAuth\r\n"); - rend_authorized_client_free(client); - goto out; - } - } else { - auth_clients = smartlist_new(); - auth_created_clients = smartlist_new(); - } - smartlist_add(auth_clients, client); - if (created) { - smartlist_add(auth_created_clients, client); - } - } else { - connection_printf_to_buf(conn, "513 Invalid argument\r\n"); - goto out; - } - } - if (smartlist_len(port_cfgs) == 0) { - connection_printf_to_buf(conn, "512 Missing 'Port' argument\r\n"); - goto out; - } else if (auth_type == REND_NO_AUTH && auth_clients != NULL) { - connection_printf_to_buf(conn, "512 No auth type specified\r\n"); - goto out; - } else if (auth_type != REND_NO_AUTH && auth_clients == NULL) { - connection_printf_to_buf(conn, "512 No auth clients specified\r\n"); - goto out; - } else if ((auth_type == REND_BASIC_AUTH && - smartlist_len(auth_clients) > 512) || - (auth_type == REND_STEALTH_AUTH && - smartlist_len(auth_clients) > 16)) { - connection_printf_to_buf(conn, "512 Too many auth clients\r\n"); - goto out; - } else if (non_anonymous != rend_service_non_anonymous_mode_enabled( - get_options())) { - /* If we failed, and the non-anonymous flag is set, Tor must be in - * anonymous hidden service mode. - * The error message changes based on the current Tor config: - * 512 Tor is in anonymous hidden service mode - * 512 Tor is in non-anonymous hidden service mode - * (I've deliberately written them out in full here to aid searchability.) - */ - connection_printf_to_buf(conn, "512 Tor is in %sanonymous hidden service " - "mode\r\n", - non_anonymous ? "" : "non-"); - goto out; - } - - /* Parse the "keytype:keyblob" argument. */ - int hs_version = 0; - add_onion_secret_key_t pk = { NULL }; - const char *key_new_alg = NULL; - char *key_new_blob = NULL; - char *err_msg = NULL; - - if (add_onion_helper_keyarg(smartlist_get(args, 0), discard_pk, - &key_new_alg, &key_new_blob, &pk, &hs_version, - &err_msg) < 0) { - if (err_msg) { - connection_write_str_to_buf(err_msg, conn); - tor_free(err_msg); - } - goto out; - } - tor_assert(!err_msg); - - /* Hidden service version 3 don't have client authentication support so if - * ClientAuth was given, send back an error. */ - if (hs_version == HS_VERSION_THREE && auth_clients) { - connection_printf_to_buf(conn, "513 ClientAuth not supported\r\n"); - goto out; - } - - /* Create the HS, using private key pk, client authentication auth_type, - * the list of auth_clients, and port config port_cfg. - * rend_service_add_ephemeral() will take ownership of pk and port_cfg, - * regardless of success/failure. - */ - char *service_id = NULL; - int ret = add_onion_helper_add_service(hs_version, &pk, port_cfgs, - max_streams, - max_streams_close_circuit, auth_type, - auth_clients, &service_id); - port_cfgs = NULL; /* port_cfgs is now owned by the rendservice code. */ - auth_clients = NULL; /* so is auth_clients */ - switch (ret) { - case RSAE_OKAY: - { - if (detach) { - if (!detached_onion_services) - detached_onion_services = smartlist_new(); - smartlist_add(detached_onion_services, service_id); - } else { - if (!conn->ephemeral_onion_services) - conn->ephemeral_onion_services = smartlist_new(); - smartlist_add(conn->ephemeral_onion_services, service_id); - } - - tor_assert(service_id); - connection_printf_to_buf(conn, "250-ServiceID=%s\r\n", service_id); - if (key_new_alg) { - tor_assert(key_new_blob); - connection_printf_to_buf(conn, "250-PrivateKey=%s:%s\r\n", - key_new_alg, key_new_blob); - } - if (auth_created_clients) { - SMARTLIST_FOREACH(auth_created_clients, rend_authorized_client_t *, ac, { - char *encoded = rend_auth_encode_cookie(ac->descriptor_cookie, - auth_type); - tor_assert(encoded); - connection_printf_to_buf(conn, "250-ClientAuth=%s:%s\r\n", - ac->client_name, encoded); - memwipe(encoded, 0, strlen(encoded)); - tor_free(encoded); - }); - } - - connection_printf_to_buf(conn, "250 OK\r\n"); - break; - } - case RSAE_BADPRIVKEY: - connection_printf_to_buf(conn, "551 Failed to generate onion address\r\n"); - break; - case RSAE_ADDREXISTS: - connection_printf_to_buf(conn, "550 Onion address collision\r\n"); - break; - case RSAE_BADVIRTPORT: - connection_printf_to_buf(conn, "512 Invalid VIRTPORT/TARGET\r\n"); - break; - case RSAE_BADAUTH: - connection_printf_to_buf(conn, "512 Invalid client authorization\r\n"); - break; - case RSAE_INTERNAL: /* FALLSTHROUGH */ - default: - connection_printf_to_buf(conn, "551 Failed to add Onion Service\r\n"); - } - if (key_new_blob) { - memwipe(key_new_blob, 0, strlen(key_new_blob)); - tor_free(key_new_blob); - } - - out: - if (port_cfgs) { - SMARTLIST_FOREACH(port_cfgs, rend_service_port_config_t*, p, - rend_service_port_config_free(p)); - smartlist_free(port_cfgs); - } - - if (auth_clients) { - SMARTLIST_FOREACH(auth_clients, rend_authorized_client_t *, ac, - rend_authorized_client_free(ac)); - smartlist_free(auth_clients); - } - if (auth_created_clients) { - // Do not free entries; they are the same as auth_clients - smartlist_free(auth_created_clients); - } - - SMARTLIST_FOREACH(args, char *, cp, { - memwipe(cp, 0, strlen(cp)); - tor_free(cp); - }); - smartlist_free(args); - return 0; -} - -/** Helper function to handle parsing the KeyType:KeyBlob argument to the - * ADD_ONION command. Return a new crypto_pk_t and if a new key was generated - * and the private key not discarded, the algorithm and serialized private key, - * or NULL and an optional control protocol error message on failure. The - * caller is responsible for freeing the returned key_new_blob and err_msg. - * - * Note: The error messages returned are deliberately vague to avoid echoing - * key material. - */ -STATIC int -add_onion_helper_keyarg(const char *arg, int discard_pk, - const char **key_new_alg_out, char **key_new_blob_out, - add_onion_secret_key_t *decoded_key, int *hs_version, - char **err_msg_out) -{ - smartlist_t *key_args = smartlist_new(); - crypto_pk_t *pk = NULL; - const char *key_new_alg = NULL; - char *key_new_blob = NULL; - char *err_msg = NULL; - int ret = -1; - - smartlist_split_string(key_args, arg, ":", SPLIT_IGNORE_BLANK, 0); - if (smartlist_len(key_args) != 2) { - err_msg = tor_strdup("512 Invalid key type/blob\r\n"); - goto err; - } - - /* The format is "KeyType:KeyBlob". */ - static const char *key_type_new = "NEW"; - static const char *key_type_best = "BEST"; - static const char *key_type_rsa1024 = "RSA1024"; - static const char *key_type_ed25519_v3 = "ED25519-V3"; - - const char *key_type = smartlist_get(key_args, 0); - const char *key_blob = smartlist_get(key_args, 1); - - if (!strcasecmp(key_type_rsa1024, key_type)) { - /* "RSA:" - Loading a pre-existing RSA1024 key. */ - pk = crypto_pk_base64_decode_private(key_blob, strlen(key_blob)); - if (!pk) { - err_msg = tor_strdup("512 Failed to decode RSA key\r\n"); - goto err; - } - if (crypto_pk_num_bits(pk) != PK_BYTES*8) { - crypto_pk_free(pk); - err_msg = tor_strdup("512 Invalid RSA key size\r\n"); - goto err; - } - decoded_key->v2 = pk; - *hs_version = HS_VERSION_TWO; - } else if (!strcasecmp(key_type_ed25519_v3, key_type)) { - /* "ED25519-V3:" - Loading a pre-existing ed25519 key. */ - ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk)); - if (base64_decode((char *) sk->seckey, sizeof(sk->seckey), key_blob, - strlen(key_blob)) != sizeof(sk->seckey)) { - tor_free(sk); - err_msg = tor_strdup("512 Failed to decode ED25519-V3 key\r\n"); - goto err; - } - decoded_key->v3 = sk; - *hs_version = HS_VERSION_THREE; - } else if (!strcasecmp(key_type_new, key_type)) { - /* "NEW:" - Generating a new key, blob as algorithm. */ - if (!strcasecmp(key_type_rsa1024, key_blob) || - !strcasecmp(key_type_best, key_blob)) { - /* "RSA1024", RSA 1024 bit, also currently "BEST" by default. */ - pk = crypto_pk_new(); - if (crypto_pk_generate_key(pk)) { - tor_asprintf(&err_msg, "551 Failed to generate %s key\r\n", - key_type_rsa1024); - goto err; - } - if (!discard_pk) { - if (crypto_pk_base64_encode_private(pk, &key_new_blob)) { - crypto_pk_free(pk); - tor_asprintf(&err_msg, "551 Failed to encode %s key\r\n", - key_type_rsa1024); - goto err; - } - key_new_alg = key_type_rsa1024; - } - decoded_key->v2 = pk; - *hs_version = HS_VERSION_TWO; - } else if (!strcasecmp(key_type_ed25519_v3, key_blob)) { - ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk)); - if (ed25519_secret_key_generate(sk, 1) < 0) { - tor_free(sk); - tor_asprintf(&err_msg, "551 Failed to generate %s key\r\n", - key_type_ed25519_v3); - goto err; - } - if (!discard_pk) { - ssize_t len = base64_encode_size(sizeof(sk->seckey), 0) + 1; - key_new_blob = tor_malloc_zero(len); - if (base64_encode(key_new_blob, len, (const char *) sk->seckey, - sizeof(sk->seckey), 0) != (len - 1)) { - tor_free(sk); - tor_free(key_new_blob); - tor_asprintf(&err_msg, "551 Failed to encode %s key\r\n", - key_type_ed25519_v3); - goto err; - } - key_new_alg = key_type_ed25519_v3; - } - decoded_key->v3 = sk; - *hs_version = HS_VERSION_THREE; - } else { - err_msg = tor_strdup("513 Invalid key type\r\n"); - goto err; - } - } else { - err_msg = tor_strdup("513 Invalid key type\r\n"); - goto err; - } - - /* Succeeded in loading or generating a private key. */ - ret = 0; - - err: - SMARTLIST_FOREACH(key_args, char *, cp, { - memwipe(cp, 0, strlen(cp)); - tor_free(cp); - }); - smartlist_free(key_args); - - if (err_msg_out) { - *err_msg_out = err_msg; - } else { - tor_free(err_msg); - } - *key_new_alg_out = key_new_alg; - *key_new_blob_out = key_new_blob; - - return ret; -} - -/** Helper function to handle parsing a ClientAuth argument to the - * ADD_ONION command. Return a new rend_authorized_client_t, or NULL - * and an optional control protocol error message on failure. The - * caller is responsible for freeing the returned auth_client and err_msg. - * - * If 'created' is specified, it will be set to 1 when a new cookie has - * been generated. - */ -STATIC rend_authorized_client_t * -add_onion_helper_clientauth(const char *arg, int *created, char **err_msg) -{ - int ok = 0; - - tor_assert(arg); - tor_assert(created); - tor_assert(err_msg); - *err_msg = NULL; - - smartlist_t *auth_args = smartlist_new(); - rend_authorized_client_t *client = - tor_malloc_zero(sizeof(rend_authorized_client_t)); - smartlist_split_string(auth_args, arg, ":", 0, 0); - if (smartlist_len(auth_args) < 1 || smartlist_len(auth_args) > 2) { - *err_msg = tor_strdup("512 Invalid ClientAuth syntax\r\n"); - goto err; - } - client->client_name = tor_strdup(smartlist_get(auth_args, 0)); - if (smartlist_len(auth_args) == 2) { - char *decode_err_msg = NULL; - if (rend_auth_decode_cookie(smartlist_get(auth_args, 1), - client->descriptor_cookie, - NULL, &decode_err_msg) < 0) { - tor_assert(decode_err_msg); - tor_asprintf(err_msg, "512 %s\r\n", decode_err_msg); - tor_free(decode_err_msg); - goto err; - } - *created = 0; - } else { - crypto_rand((char *) client->descriptor_cookie, REND_DESC_COOKIE_LEN); - *created = 1; - } - - if (!rend_valid_client_name(client->client_name)) { - *err_msg = tor_strdup("512 Invalid name in ClientAuth\r\n"); - goto err; - } - - ok = 1; - err: - SMARTLIST_FOREACH(auth_args, char *, item, tor_free(item)); - smartlist_free(auth_args); - if (!ok) { - rend_authorized_client_free(client); - client = NULL; - } - return client; -} - -/** Called when we get a DEL_ONION command; parse the body, and remove - * the existing ephemeral Onion Service. */ -static int -handle_control_del_onion(control_connection_t *conn, - uint32_t len, - const char *body) -{ - int hs_version = 0; - smartlist_t *args; - (void) len; /* body is nul-terminated; it's safe to ignore the length */ - args = getargs_helper("DEL_ONION", conn, body, 1, 1); - if (!args) - return 0; - - const char *service_id = smartlist_get(args, 0); - if (rend_valid_v2_service_id(service_id)) { - hs_version = HS_VERSION_TWO; - } else if (hs_address_is_valid(service_id)) { - hs_version = HS_VERSION_THREE; - } else { - connection_printf_to_buf(conn, "512 Malformed Onion Service id\r\n"); - goto out; - } - - /* Determine if the onion service belongs to this particular control - * connection, or if it is in the global list of detached services. If it - * is in neither, either the service ID is invalid in some way, or it - * explicitly belongs to a different control connection, and an error - * should be returned. - */ - smartlist_t *services[2] = { - conn->ephemeral_onion_services, - detached_onion_services - }; - smartlist_t *onion_services = NULL; - int idx = -1; - for (size_t i = 0; i < ARRAY_LENGTH(services); i++) { - idx = smartlist_string_pos(services[i], service_id); - if (idx != -1) { - onion_services = services[i]; - break; - } - } - if (onion_services == NULL) { - connection_printf_to_buf(conn, "552 Unknown Onion Service id\r\n"); - } else { - int ret = -1; - switch (hs_version) { - case HS_VERSION_TWO: - ret = rend_service_del_ephemeral(service_id); - break; - case HS_VERSION_THREE: - ret = hs_service_del_ephemeral(service_id); - break; - default: - /* The ret value will be -1 thus hitting the warning below. This should - * never happen because of the check at the start of the function. */ - break; - } - if (ret < 0) { - /* This should *NEVER* fail, since the service is on either the - * per-control connection list, or the global one. - */ - log_warn(LD_BUG, "Failed to remove Onion Service %s.", - escaped(service_id)); - tor_fragile_assert(); - } - - /* Remove/scrub the service_id from the appropriate list. */ - char *cp = smartlist_get(onion_services, idx); - smartlist_del(onion_services, idx); - memwipe(cp, 0, strlen(cp)); - tor_free(cp); - - send_control_done(conn); - } - - out: - SMARTLIST_FOREACH(args, char *, cp, { - memwipe(cp, 0, strlen(cp)); - tor_free(cp); - }); - smartlist_free(args); - return 0; -} - -/** Called when conn has no more bytes left on its outbuf. */ -int -connection_control_finished_flushing(control_connection_t *conn) -{ - tor_assert(conn); - return 0; -} - -/** Called when conn has gotten its socket closed. */ -int -connection_control_reached_eof(control_connection_t *conn) -{ - tor_assert(conn); - - log_info(LD_CONTROL,"Control connection reached EOF. Closing."); - connection_mark_for_close(TO_CONN(conn)); - return 0; -} - -/** Shut down this Tor instance in the same way that SIGINT would, but - * with a log message appropriate for the loss of an owning controller. */ -static void -lost_owning_controller(const char *owner_type, const char *loss_manner) -{ - log_notice(LD_CONTROL, "Owning controller %s has %s -- exiting now.", - owner_type, loss_manner); - - activate_signal(SIGTERM); -} - -/** Called when conn is being freed. */ -void -connection_control_closed(control_connection_t *conn) -{ - tor_assert(conn); - - conn->event_mask = 0; - control_update_global_event_mask(); - - /* Close all ephemeral Onion Services if any. - * The list and it's contents are scrubbed/freed in connection_free_. - */ - if (conn->ephemeral_onion_services) { - SMARTLIST_FOREACH_BEGIN(conn->ephemeral_onion_services, char *, cp) { - if (rend_valid_v2_service_id(cp)) { - rend_service_del_ephemeral(cp); - } else if (hs_address_is_valid(cp)) { - hs_service_del_ephemeral(cp); - } else { - /* An invalid .onion in our list should NEVER happen */ - tor_fragile_assert(); - } - } SMARTLIST_FOREACH_END(cp); - } - - if (conn->is_owning_control_connection) { - lost_owning_controller("connection", "closed"); - } -} - -/** Return true iff cmd is allowable (or at least forgivable) at this - * stage of the protocol. */ -static int -is_valid_initial_command(control_connection_t *conn, const char *cmd) -{ - if (conn->base_.state == CONTROL_CONN_STATE_OPEN) - return 1; - if (!strcasecmp(cmd, "PROTOCOLINFO")) - return (!conn->have_sent_protocolinfo && - conn->safecookie_client_hash == NULL); - if (!strcasecmp(cmd, "AUTHCHALLENGE")) - return (conn->safecookie_client_hash == NULL); - if (!strcasecmp(cmd, "AUTHENTICATE") || - !strcasecmp(cmd, "QUIT")) - return 1; - return 0; -} - -/** Do not accept any control command of more than 1MB in length. Anything - * that needs to be anywhere near this long probably means that one of our - * interfaces is broken. */ -#define MAX_COMMAND_LINE_LENGTH (1024*1024) - -/** Wrapper around peek_buf_has_control0 command: presents the same - * interface as that underlying functions, but takes a connection_t intead of - * a buf_t. - */ -static int -peek_connection_has_control0_command(connection_t *conn) -{ - return peek_buf_has_control0_command(conn->inbuf); -} - -static int -peek_connection_has_http_command(connection_t *conn) -{ - return peek_buf_has_http_command(conn->inbuf); -} - -static const char CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG[] = - "HTTP/1.0 501 Tor ControlPort is not an HTTP proxy" - "\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n" - "\n" - "\n" - "Tor's ControlPort is not an HTTP proxy\n" - "\n" - "\n" - "

Tor's ControlPort is not an HTTP proxy

\n" - "

\n" - "It appears you have configured your web browser to use Tor's control port" - " as an HTTP proxy.\n" - "This is not correct: Tor's default SOCKS proxy port is 9050.\n" - "Please configure your client accordingly.\n" - "

\n" - "

\n" - "See " - "https://www.torproject.org/documentation.html for more " - "information.\n" - "\n" - "

\n" - "\n" - "\n"; - -/** Called when data has arrived on a v1 control connection: Try to fetch - * commands from conn->inbuf, and execute them. - */ -int -connection_control_process_inbuf(control_connection_t *conn) -{ - size_t data_len; - uint32_t cmd_data_len; - int cmd_len; - char *args; - - tor_assert(conn); - tor_assert(conn->base_.state == CONTROL_CONN_STATE_OPEN || - conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH); - - if (!conn->incoming_cmd) { - conn->incoming_cmd = tor_malloc(1024); - conn->incoming_cmd_len = 1024; - conn->incoming_cmd_cur_len = 0; - } - - if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && - peek_connection_has_control0_command(TO_CONN(conn))) { - /* Detect v0 commands and send a "no more v0" message. */ - size_t body_len; - char buf[128]; - set_uint16(buf+2, htons(0x0000)); /* type == error */ - set_uint16(buf+4, htons(0x0001)); /* code == internal error */ - strlcpy(buf+6, "The v0 control protocol is not supported by Tor 0.1.2.17 " - "and later; upgrade your controller.", - sizeof(buf)-6); - body_len = 2+strlen(buf+6)+2; /* code, msg, nul. */ - set_uint16(buf+0, htons(body_len)); - connection_buf_add(buf, 4+body_len, TO_CONN(conn)); - - connection_mark_and_flush(TO_CONN(conn)); - return 0; - } - - /* If the user has the HTTP proxy port and the control port confused. */ - if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && - peek_connection_has_http_command(TO_CONN(conn))) { - connection_write_str_to_buf(CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG, conn); - log_notice(LD_CONTROL, "Received HTTP request on ControlPort"); - connection_mark_and_flush(TO_CONN(conn)); - return 0; - } - - again: - while (1) { - size_t last_idx; - int r; - /* First, fetch a line. */ - do { - data_len = conn->incoming_cmd_len - conn->incoming_cmd_cur_len; - r = connection_buf_get_line(TO_CONN(conn), - conn->incoming_cmd+conn->incoming_cmd_cur_len, - &data_len); - if (r == 0) - /* Line not all here yet. Wait. */ - return 0; - else if (r == -1) { - if (data_len + conn->incoming_cmd_cur_len > MAX_COMMAND_LINE_LENGTH) { - connection_write_str_to_buf("500 Line too long.\r\n", conn); - connection_stop_reading(TO_CONN(conn)); - connection_mark_and_flush(TO_CONN(conn)); - } - while (conn->incoming_cmd_len < data_len+conn->incoming_cmd_cur_len) - conn->incoming_cmd_len *= 2; - conn->incoming_cmd = tor_realloc(conn->incoming_cmd, - conn->incoming_cmd_len); - } - } while (r != 1); - - tor_assert(data_len); - - last_idx = conn->incoming_cmd_cur_len; - conn->incoming_cmd_cur_len += (int)data_len; - - /* We have appended a line to incoming_cmd. Is the command done? */ - if (last_idx == 0 && *conn->incoming_cmd != '+') - /* One line command, didn't start with '+'. */ - break; - /* XXXX this code duplication is kind of dumb. */ - if (last_idx+3 == conn->incoming_cmd_cur_len && - tor_memeq(conn->incoming_cmd + last_idx, ".\r\n", 3)) { - /* Just appended ".\r\n"; we're done. Remove it. */ - conn->incoming_cmd[last_idx] = '\0'; - conn->incoming_cmd_cur_len -= 3; - break; - } else if (last_idx+2 == conn->incoming_cmd_cur_len && - tor_memeq(conn->incoming_cmd + last_idx, ".\n", 2)) { - /* Just appended ".\n"; we're done. Remove it. */ - conn->incoming_cmd[last_idx] = '\0'; - conn->incoming_cmd_cur_len -= 2; - break; - } - /* Otherwise, read another line. */ - } - data_len = conn->incoming_cmd_cur_len; - /* Okay, we now have a command sitting on conn->incoming_cmd. See if we - * recognize it. - */ - cmd_len = 0; - while ((size_t)cmd_len < data_len - && !TOR_ISSPACE(conn->incoming_cmd[cmd_len])) - ++cmd_len; - - conn->incoming_cmd[cmd_len]='\0'; - args = conn->incoming_cmd+cmd_len+1; - tor_assert(data_len>(size_t)cmd_len); - data_len -= (cmd_len+1); /* skip the command and NUL we added after it */ - while (TOR_ISSPACE(*args)) { - ++args; - --data_len; - } - - /* If the connection is already closing, ignore further commands */ - if (TO_CONN(conn)->marked_for_close) { - return 0; - } - - /* Otherwise, Quit is always valid. */ - if (!strcasecmp(conn->incoming_cmd, "QUIT")) { - connection_write_str_to_buf("250 closing connection\r\n", conn); - connection_mark_and_flush(TO_CONN(conn)); - return 0; - } - - if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && - !is_valid_initial_command(conn, conn->incoming_cmd)) { - connection_write_str_to_buf("514 Authentication required.\r\n", conn); - connection_mark_for_close(TO_CONN(conn)); - return 0; - } - - if (data_len >= UINT32_MAX) { - connection_write_str_to_buf("500 A 4GB command? Nice try.\r\n", conn); - connection_mark_for_close(TO_CONN(conn)); - return 0; - } - - /* XXXX Why is this not implemented as a table like the GETINFO - * items are? Even handling the plus signs at the beginnings of - * commands wouldn't be very hard with proper macros. */ - cmd_data_len = (uint32_t)data_len; - if (!strcasecmp(conn->incoming_cmd, "SETCONF")) { - if (handle_control_setconf(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "RESETCONF")) { - if (handle_control_resetconf(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "GETCONF")) { - if (handle_control_getconf(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "+LOADCONF")) { - if (handle_control_loadconf(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "SETEVENTS")) { - if (handle_control_setevents(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "AUTHENTICATE")) { - if (handle_control_authenticate(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "SAVECONF")) { - if (handle_control_saveconf(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "SIGNAL")) { - if (handle_control_signal(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "TAKEOWNERSHIP")) { - if (handle_control_takeownership(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "DROPOWNERSHIP")) { - if (handle_control_dropownership(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "MAPADDRESS")) { - if (handle_control_mapaddress(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "GETINFO")) { - if (handle_control_getinfo(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "EXTENDCIRCUIT")) { - if (handle_control_extendcircuit(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "SETCIRCUITPURPOSE")) { - if (handle_control_setcircuitpurpose(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "SETROUTERPURPOSE")) { - connection_write_str_to_buf("511 SETROUTERPURPOSE is obsolete.\r\n", conn); - } else if (!strcasecmp(conn->incoming_cmd, "ATTACHSTREAM")) { - if (handle_control_attachstream(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "+POSTDESCRIPTOR")) { - if (handle_control_postdescriptor(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "REDIRECTSTREAM")) { - if (handle_control_redirectstream(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "CLOSESTREAM")) { - if (handle_control_closestream(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "CLOSECIRCUIT")) { - if (handle_control_closecircuit(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "USEFEATURE")) { - if (handle_control_usefeature(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "RESOLVE")) { - if (handle_control_resolve(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "PROTOCOLINFO")) { - if (handle_control_protocolinfo(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "AUTHCHALLENGE")) { - if (handle_control_authchallenge(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "DROPGUARDS")) { - if (handle_control_dropguards(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "HSFETCH")) { - if (handle_control_hsfetch(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "+HSPOST")) { - if (handle_control_hspost(conn, cmd_data_len, args)) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "ADD_ONION")) { - int ret = handle_control_add_onion(conn, cmd_data_len, args); - memwipe(args, 0, cmd_data_len); /* Scrub the private key. */ - if (ret) - return -1; - } else if (!strcasecmp(conn->incoming_cmd, "DEL_ONION")) { - int ret = handle_control_del_onion(conn, cmd_data_len, args); - memwipe(args, 0, cmd_data_len); /* Scrub the service id/pk. */ - if (ret) - return -1; - } else { - connection_printf_to_buf(conn, "510 Unrecognized command \"%s\"\r\n", - conn->incoming_cmd); - } - - conn->incoming_cmd_cur_len = 0; - goto again; -} - -/** Something major has happened to circuit circ: tell any - * interested control connections. */ -int -control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp, - int reason_code) -{ - const char *status; - char reasons[64] = ""; - - if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS)) - return 0; - tor_assert(circ); - - switch (tp) - { - case CIRC_EVENT_LAUNCHED: status = "LAUNCHED"; break; - case CIRC_EVENT_BUILT: status = "BUILT"; break; - case CIRC_EVENT_EXTENDED: status = "EXTENDED"; break; - case CIRC_EVENT_FAILED: status = "FAILED"; break; - case CIRC_EVENT_CLOSED: status = "CLOSED"; break; - default: - log_warn(LD_BUG, "Unrecognized status code %d", (int)tp); - tor_fragile_assert(); - return 0; - } - - if (tp == CIRC_EVENT_FAILED || tp == CIRC_EVENT_CLOSED) { - const char *reason_str = circuit_end_reason_to_control_string(reason_code); - char unk_reason_buf[16]; - if (!reason_str) { - tor_snprintf(unk_reason_buf, 16, "UNKNOWN_%d", reason_code); - reason_str = unk_reason_buf; - } - if (reason_code > 0 && reason_code & END_CIRC_REASON_FLAG_REMOTE) { - tor_snprintf(reasons, sizeof(reasons), - " REASON=DESTROYED REMOTE_REASON=%s", reason_str); - } else { - tor_snprintf(reasons, sizeof(reasons), - " REASON=%s", reason_str); - } - } - - { - char *circdesc = circuit_describe_status_for_controller(circ); - const char *sp = strlen(circdesc) ? " " : ""; - send_control_event(EVENT_CIRCUIT_STATUS, - "650 CIRC %lu %s%s%s%s\r\n", - (unsigned long)circ->global_identifier, - status, sp, - circdesc, - reasons); - tor_free(circdesc); - } - - return 0; -} - -/** Something minor has happened to circuit circ: tell any - * interested control connections. */ -static int -control_event_circuit_status_minor(origin_circuit_t *circ, - circuit_status_minor_event_t e, - int purpose, const struct timeval *tv) -{ - const char *event_desc; - char event_tail[160] = ""; - if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS_MINOR)) - return 0; - tor_assert(circ); - - switch (e) - { - case CIRC_MINOR_EVENT_PURPOSE_CHANGED: - event_desc = "PURPOSE_CHANGED"; - - { - /* event_tail can currently be up to 68 chars long */ - const char *hs_state_str = - circuit_purpose_to_controller_hs_state_string(purpose); - tor_snprintf(event_tail, sizeof(event_tail), - " OLD_PURPOSE=%s%s%s", - circuit_purpose_to_controller_string(purpose), - (hs_state_str != NULL) ? " OLD_HS_STATE=" : "", - (hs_state_str != NULL) ? hs_state_str : ""); - } - - break; - case CIRC_MINOR_EVENT_CANNIBALIZED: - event_desc = "CANNIBALIZED"; - - { - /* event_tail can currently be up to 130 chars long */ - const char *hs_state_str = - circuit_purpose_to_controller_hs_state_string(purpose); - const struct timeval *old_timestamp_began = tv; - char tbuf[ISO_TIME_USEC_LEN+1]; - format_iso_time_nospace_usec(tbuf, old_timestamp_began); - - tor_snprintf(event_tail, sizeof(event_tail), - " OLD_PURPOSE=%s%s%s OLD_TIME_CREATED=%s", - circuit_purpose_to_controller_string(purpose), - (hs_state_str != NULL) ? " OLD_HS_STATE=" : "", - (hs_state_str != NULL) ? hs_state_str : "", - tbuf); - } - - break; - default: - log_warn(LD_BUG, "Unrecognized status code %d", (int)e); - tor_fragile_assert(); - return 0; - } - - { - char *circdesc = circuit_describe_status_for_controller(circ); - const char *sp = strlen(circdesc) ? " " : ""; - send_control_event(EVENT_CIRCUIT_STATUS_MINOR, - "650 CIRC_MINOR %lu %s%s%s%s\r\n", - (unsigned long)circ->global_identifier, - event_desc, sp, - circdesc, - event_tail); - tor_free(circdesc); - } - - return 0; -} - -/** - * circ has changed its purpose from old_purpose: tell any - * interested controllers. - */ -int -control_event_circuit_purpose_changed(origin_circuit_t *circ, - int old_purpose) -{ - return control_event_circuit_status_minor(circ, - CIRC_MINOR_EVENT_PURPOSE_CHANGED, - old_purpose, - NULL); -} - -/** - * circ has changed its purpose from old_purpose, and its - * created-time from old_tv_created: tell any interested controllers. - */ -int -control_event_circuit_cannibalized(origin_circuit_t *circ, - int old_purpose, - const struct timeval *old_tv_created) -{ - return control_event_circuit_status_minor(circ, - CIRC_MINOR_EVENT_CANNIBALIZED, - old_purpose, - old_tv_created); -} - -/** Given an AP connection conn and a len-character buffer - * buf, determine the address:port combination requested on - * conn, and write it to buf. Return 0 on success, -1 on - * failure. */ -static int -write_stream_target_to_buf(entry_connection_t *conn, char *buf, size_t len) -{ - char buf2[256]; - if (conn->chosen_exit_name) - if (tor_snprintf(buf2, sizeof(buf2), ".%s.exit", conn->chosen_exit_name)<0) - return -1; - if (!conn->socks_request) - return -1; - if (tor_snprintf(buf, len, "%s%s%s:%d", - conn->socks_request->address, - conn->chosen_exit_name ? buf2 : "", - !conn->chosen_exit_name && connection_edge_is_rendezvous_stream( - ENTRY_TO_EDGE_CONN(conn)) ? ".onion" : "", - conn->socks_request->port)<0) - return -1; - return 0; -} - -/** Something has happened to the stream associated with AP connection - * conn: tell any interested control connections. */ -int -control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp, - int reason_code) -{ - char reason_buf[64]; - char addrport_buf[64]; - const char *status; - circuit_t *circ; - origin_circuit_t *origin_circ = NULL; - char buf[256]; - const char *purpose = ""; - tor_assert(conn->socks_request); - - if (!EVENT_IS_INTERESTING(EVENT_STREAM_STATUS)) - return 0; - - if (tp == STREAM_EVENT_CLOSED && - (reason_code & END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED)) - return 0; - - write_stream_target_to_buf(conn, buf, sizeof(buf)); - - reason_buf[0] = '\0'; - switch (tp) - { - case STREAM_EVENT_SENT_CONNECT: status = "SENTCONNECT"; break; - case STREAM_EVENT_SENT_RESOLVE: status = "SENTRESOLVE"; break; - case STREAM_EVENT_SUCCEEDED: status = "SUCCEEDED"; break; - case STREAM_EVENT_FAILED: status = "FAILED"; break; - case STREAM_EVENT_CLOSED: status = "CLOSED"; break; - case STREAM_EVENT_NEW: status = "NEW"; break; - case STREAM_EVENT_NEW_RESOLVE: status = "NEWRESOLVE"; break; - case STREAM_EVENT_FAILED_RETRIABLE: status = "DETACHED"; break; - case STREAM_EVENT_REMAP: status = "REMAP"; break; - default: - log_warn(LD_BUG, "Unrecognized status code %d", (int)tp); - return 0; - } - if (reason_code && (tp == STREAM_EVENT_FAILED || - tp == STREAM_EVENT_CLOSED || - tp == STREAM_EVENT_FAILED_RETRIABLE)) { - const char *reason_str = stream_end_reason_to_control_string(reason_code); - char *r = NULL; - if (!reason_str) { - tor_asprintf(&r, " UNKNOWN_%d", reason_code); - reason_str = r; - } - if (reason_code & END_STREAM_REASON_FLAG_REMOTE) - tor_snprintf(reason_buf, sizeof(reason_buf), - " REASON=END REMOTE_REASON=%s", reason_str); - else - tor_snprintf(reason_buf, sizeof(reason_buf), - " REASON=%s", reason_str); - tor_free(r); - } else if (reason_code && tp == STREAM_EVENT_REMAP) { - switch (reason_code) { - case REMAP_STREAM_SOURCE_CACHE: - strlcpy(reason_buf, " SOURCE=CACHE", sizeof(reason_buf)); - break; - case REMAP_STREAM_SOURCE_EXIT: - strlcpy(reason_buf, " SOURCE=EXIT", sizeof(reason_buf)); - break; - default: - tor_snprintf(reason_buf, sizeof(reason_buf), " REASON=UNKNOWN_%d", - reason_code); - /* XXX do we want SOURCE=UNKNOWN_%d above instead? -RD */ - break; - } - } - - if (tp == STREAM_EVENT_NEW || tp == STREAM_EVENT_NEW_RESOLVE) { - /* - * When the control conn is an AF_UNIX socket and we have no address, - * it gets set to "(Tor_internal)"; see dnsserv_launch_request() in - * dnsserv.c. - */ - if (strcmp(ENTRY_TO_CONN(conn)->address, "(Tor_internal)") != 0) { - tor_snprintf(addrport_buf,sizeof(addrport_buf), " SOURCE_ADDR=%s:%d", - ENTRY_TO_CONN(conn)->address, ENTRY_TO_CONN(conn)->port); - } else { - /* - * else leave it blank so control on AF_UNIX doesn't need to make - * something up. - */ - addrport_buf[0] = '\0'; - } - } else { - addrport_buf[0] = '\0'; - } - - if (tp == STREAM_EVENT_NEW_RESOLVE) { - purpose = " PURPOSE=DNS_REQUEST"; - } else if (tp == STREAM_EVENT_NEW) { - if (conn->use_begindir) { - connection_t *linked = ENTRY_TO_CONN(conn)->linked_conn; - int linked_dir_purpose = -1; - if (linked && linked->type == CONN_TYPE_DIR) - linked_dir_purpose = linked->purpose; - if (DIR_PURPOSE_IS_UPLOAD(linked_dir_purpose)) - purpose = " PURPOSE=DIR_UPLOAD"; - else - purpose = " PURPOSE=DIR_FETCH"; - } else - purpose = " PURPOSE=USER"; - } - - circ = circuit_get_by_edge_conn(ENTRY_TO_EDGE_CONN(conn)); - if (circ && CIRCUIT_IS_ORIGIN(circ)) - origin_circ = TO_ORIGIN_CIRCUIT(circ); - send_control_event(EVENT_STREAM_STATUS, - "650 STREAM %"PRIu64" %s %lu %s%s%s%s\r\n", - (ENTRY_TO_CONN(conn)->global_identifier), - status, - origin_circ? - (unsigned long)origin_circ->global_identifier : 0ul, - buf, reason_buf, addrport_buf, purpose); - - /* XXX need to specify its intended exit, etc? */ - - return 0; -} - -/** Figure out the best name for the target router of an OR connection - * conn, and write it into the len-character buffer - * name. */ -static void -orconn_target_get_name(char *name, size_t len, or_connection_t *conn) -{ - const node_t *node = node_get_by_id(conn->identity_digest); - if (node) { - tor_assert(len > MAX_VERBOSE_NICKNAME_LEN); - node_get_verbose_nickname(node, name); - } else if (! tor_digest_is_zero(conn->identity_digest)) { - name[0] = '$'; - base16_encode(name+1, len-1, conn->identity_digest, - DIGEST_LEN); - } else { - tor_snprintf(name, len, "%s:%d", - conn->base_.address, conn->base_.port); - } -} - -/** Called when the status of an OR connection conn changes: tell any - * interested control connections. tp is the new status for the - * connection. If conn has just closed or failed, then reason - * may be the reason why. - */ -int -control_event_or_conn_status(or_connection_t *conn, or_conn_status_event_t tp, - int reason) -{ - int ncircs = 0; - const char *status; - char name[128]; - char ncircs_buf[32] = {0}; /* > 8 + log10(2^32)=10 + 2 */ - - if (!EVENT_IS_INTERESTING(EVENT_OR_CONN_STATUS)) - return 0; - - switch (tp) - { - case OR_CONN_EVENT_LAUNCHED: status = "LAUNCHED"; break; - case OR_CONN_EVENT_CONNECTED: status = "CONNECTED"; break; - case OR_CONN_EVENT_FAILED: status = "FAILED"; break; - case OR_CONN_EVENT_CLOSED: status = "CLOSED"; break; - case OR_CONN_EVENT_NEW: status = "NEW"; break; - default: - log_warn(LD_BUG, "Unrecognized status code %d", (int)tp); - return 0; - } - if (conn->chan) { - ncircs = circuit_count_pending_on_channel(TLS_CHAN_TO_BASE(conn->chan)); - } else { - ncircs = 0; - } - ncircs += connection_or_get_num_circuits(conn); - if (ncircs && (tp == OR_CONN_EVENT_FAILED || tp == OR_CONN_EVENT_CLOSED)) { - tor_snprintf(ncircs_buf, sizeof(ncircs_buf), " NCIRCS=%d", ncircs); - } - - orconn_target_get_name(name, sizeof(name), conn); - send_control_event(EVENT_OR_CONN_STATUS, - "650 ORCONN %s %s%s%s%s ID=%"PRIu64"\r\n", - name, status, - reason ? " REASON=" : "", - orconn_end_reason_to_control_string(reason), - ncircs_buf, - (conn->base_.global_identifier)); - - return 0; -} - -/** - * Print out STREAM_BW event for a single conn - */ -int -control_event_stream_bandwidth(edge_connection_t *edge_conn) -{ - struct timeval now; - char tbuf[ISO_TIME_USEC_LEN+1]; - if (EVENT_IS_INTERESTING(EVENT_STREAM_BANDWIDTH_USED)) { - if (!edge_conn->n_read && !edge_conn->n_written) - return 0; - - tor_gettimeofday(&now); - format_iso_time_nospace_usec(tbuf, &now); - send_control_event(EVENT_STREAM_BANDWIDTH_USED, - "650 STREAM_BW %"PRIu64" %lu %lu %s\r\n", - (edge_conn->base_.global_identifier), - (unsigned long)edge_conn->n_read, - (unsigned long)edge_conn->n_written, - tbuf); - - edge_conn->n_written = edge_conn->n_read = 0; - } - - return 0; -} - -/** A second or more has elapsed: tell any interested control - * connections how much bandwidth streams have used. */ -int -control_event_stream_bandwidth_used(void) -{ - if (EVENT_IS_INTERESTING(EVENT_STREAM_BANDWIDTH_USED)) { - smartlist_t *conns = get_connection_array(); - edge_connection_t *edge_conn; - struct timeval now; - char tbuf[ISO_TIME_USEC_LEN+1]; - - SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) - { - if (conn->type != CONN_TYPE_AP) - continue; - edge_conn = TO_EDGE_CONN(conn); - if (!edge_conn->n_read && !edge_conn->n_written) - continue; - - tor_gettimeofday(&now); - format_iso_time_nospace_usec(tbuf, &now); - send_control_event(EVENT_STREAM_BANDWIDTH_USED, - "650 STREAM_BW %"PRIu64" %lu %lu %s\r\n", - (edge_conn->base_.global_identifier), - (unsigned long)edge_conn->n_read, - (unsigned long)edge_conn->n_written, - tbuf); - - edge_conn->n_written = edge_conn->n_read = 0; - } - SMARTLIST_FOREACH_END(conn); - } - - return 0; -} - -/** A second or more has elapsed: tell any interested control connections - * how much bandwidth origin circuits have used. */ -int -control_event_circ_bandwidth_used(void) -{ - if (!EVENT_IS_INTERESTING(EVENT_CIRC_BANDWIDTH_USED)) - return 0; - - SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { - if (!CIRCUIT_IS_ORIGIN(circ)) - continue; - - control_event_circ_bandwidth_used_for_circ(TO_ORIGIN_CIRCUIT(circ)); - } - SMARTLIST_FOREACH_END(circ); - - return 0; -} - -/** - * Emit a CIRC_BW event line for a specific circuit. - * - * This function sets the values it emits to 0, and does not emit - * an event if there is no new data to report since the last call. - * - * Therefore, it may be called at any frequency. - */ -int -control_event_circ_bandwidth_used_for_circ(origin_circuit_t *ocirc) -{ - struct timeval now; - char tbuf[ISO_TIME_USEC_LEN+1]; - - tor_assert(ocirc); - - if (!EVENT_IS_INTERESTING(EVENT_CIRC_BANDWIDTH_USED)) - return 0; - - /* n_read_circ_bw and n_written_circ_bw are always updated - * when there is any new cell on a circuit, and set to 0 after - * the event, below. - * - * Therefore, checking them is sufficient to determine if there - * is new data to report. */ - if (!ocirc->n_read_circ_bw && !ocirc->n_written_circ_bw) - return 0; - - tor_gettimeofday(&now); - format_iso_time_nospace_usec(tbuf, &now); - send_control_event(EVENT_CIRC_BANDWIDTH_USED, - "650 CIRC_BW ID=%d READ=%lu WRITTEN=%lu TIME=%s " - "DELIVERED_READ=%lu OVERHEAD_READ=%lu " - "DELIVERED_WRITTEN=%lu OVERHEAD_WRITTEN=%lu\r\n", - ocirc->global_identifier, - (unsigned long)ocirc->n_read_circ_bw, - (unsigned long)ocirc->n_written_circ_bw, - tbuf, - (unsigned long)ocirc->n_delivered_read_circ_bw, - (unsigned long)ocirc->n_overhead_read_circ_bw, - (unsigned long)ocirc->n_delivered_written_circ_bw, - (unsigned long)ocirc->n_overhead_written_circ_bw); - ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0; - ocirc->n_overhead_written_circ_bw = ocirc->n_overhead_read_circ_bw = 0; - ocirc->n_delivered_written_circ_bw = ocirc->n_delivered_read_circ_bw = 0; - - return 0; -} - -/** Print out CONN_BW event for a single OR/DIR/EXIT conn and reset - * bandwidth counters. */ -int -control_event_conn_bandwidth(connection_t *conn) -{ - const char *conn_type_str; - if (!get_options()->TestingEnableConnBwEvent || - !EVENT_IS_INTERESTING(EVENT_CONN_BW)) - return 0; - if (!conn->n_read_conn_bw && !conn->n_written_conn_bw) - return 0; - switch (conn->type) { - case CONN_TYPE_OR: - conn_type_str = "OR"; - break; - case CONN_TYPE_DIR: - conn_type_str = "DIR"; - break; - case CONN_TYPE_EXIT: - conn_type_str = "EXIT"; - break; - default: - return 0; - } - send_control_event(EVENT_CONN_BW, - "650 CONN_BW ID=%"PRIu64" TYPE=%s " - "READ=%lu WRITTEN=%lu\r\n", - (conn->global_identifier), - conn_type_str, - (unsigned long)conn->n_read_conn_bw, - (unsigned long)conn->n_written_conn_bw); - conn->n_written_conn_bw = conn->n_read_conn_bw = 0; - return 0; -} - -/** A second or more has elapsed: tell any interested control - * connections how much bandwidth connections have used. */ -int -control_event_conn_bandwidth_used(void) -{ - if (get_options()->TestingEnableConnBwEvent && - EVENT_IS_INTERESTING(EVENT_CONN_BW)) { - SMARTLIST_FOREACH(get_connection_array(), connection_t *, conn, - control_event_conn_bandwidth(conn)); - } - return 0; -} - -/** Helper: iterate over cell statistics of circ and sum up added - * cells, removed cells, and waiting times by cell command and direction. - * Store results in cell_stats. Free cell statistics of the - * circuit afterwards. */ -void -sum_up_cell_stats_by_command(circuit_t *circ, cell_stats_t *cell_stats) -{ - memset(cell_stats, 0, sizeof(cell_stats_t)); - SMARTLIST_FOREACH_BEGIN(circ->testing_cell_stats, - const testing_cell_stats_entry_t *, ent) { - tor_assert(ent->command <= CELL_COMMAND_MAX_); - if (!ent->removed && !ent->exitward) { - cell_stats->added_cells_appward[ent->command] += 1; - } else if (!ent->removed && ent->exitward) { - cell_stats->added_cells_exitward[ent->command] += 1; - } else if (!ent->exitward) { - cell_stats->removed_cells_appward[ent->command] += 1; - cell_stats->total_time_appward[ent->command] += ent->waiting_time * 10; - } else { - cell_stats->removed_cells_exitward[ent->command] += 1; - cell_stats->total_time_exitward[ent->command] += ent->waiting_time * 10; - } - } SMARTLIST_FOREACH_END(ent); - circuit_clear_testing_cell_stats(circ); -} - -/** Helper: append a cell statistics string to event_parts, - * prefixed with key=. Statistics consist of comma-separated - * key:value pairs with lower-case command strings as keys and cell - * numbers or total waiting times as values. A key:value pair is included - * if the entry in include_if_non_zero is not zero, but with - * the (possibly zero) entry from number_to_include. Both - * arrays are expected to have a length of CELL_COMMAND_MAX_ + 1. If no - * entry in include_if_non_zero is positive, no string will - * be added to event_parts. */ -void -append_cell_stats_by_command(smartlist_t *event_parts, const char *key, - const uint64_t *include_if_non_zero, - const uint64_t *number_to_include) -{ - smartlist_t *key_value_strings = smartlist_new(); - int i; - for (i = 0; i <= CELL_COMMAND_MAX_; i++) { - if (include_if_non_zero[i] > 0) { - smartlist_add_asprintf(key_value_strings, "%s:%"PRIu64, - cell_command_to_string(i), - (number_to_include[i])); - } - } - if (smartlist_len(key_value_strings) > 0) { - char *joined = smartlist_join_strings(key_value_strings, ",", 0, NULL); - smartlist_add_asprintf(event_parts, "%s=%s", key, joined); - SMARTLIST_FOREACH(key_value_strings, char *, cp, tor_free(cp)); - tor_free(joined); - } - smartlist_free(key_value_strings); -} - -/** Helper: format cell_stats for circ for inclusion in a - * CELL_STATS event and write result string to event_string. */ -void -format_cell_stats(char **event_string, circuit_t *circ, - cell_stats_t *cell_stats) -{ - smartlist_t *event_parts = smartlist_new(); - if (CIRCUIT_IS_ORIGIN(circ)) { - origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); - smartlist_add_asprintf(event_parts, "ID=%lu", - (unsigned long)ocirc->global_identifier); - } else if (TO_OR_CIRCUIT(circ)->p_chan) { - or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); - smartlist_add_asprintf(event_parts, "InboundQueue=%lu", - (unsigned long)or_circ->p_circ_id); - smartlist_add_asprintf(event_parts, "InboundConn=%"PRIu64, - (or_circ->p_chan->global_identifier)); - append_cell_stats_by_command(event_parts, "InboundAdded", - cell_stats->added_cells_appward, - cell_stats->added_cells_appward); - append_cell_stats_by_command(event_parts, "InboundRemoved", - cell_stats->removed_cells_appward, - cell_stats->removed_cells_appward); - append_cell_stats_by_command(event_parts, "InboundTime", - cell_stats->removed_cells_appward, - cell_stats->total_time_appward); - } - if (circ->n_chan) { - smartlist_add_asprintf(event_parts, "OutboundQueue=%lu", - (unsigned long)circ->n_circ_id); - smartlist_add_asprintf(event_parts, "OutboundConn=%"PRIu64, - (circ->n_chan->global_identifier)); - append_cell_stats_by_command(event_parts, "OutboundAdded", - cell_stats->added_cells_exitward, - cell_stats->added_cells_exitward); - append_cell_stats_by_command(event_parts, "OutboundRemoved", - cell_stats->removed_cells_exitward, - cell_stats->removed_cells_exitward); - append_cell_stats_by_command(event_parts, "OutboundTime", - cell_stats->removed_cells_exitward, - cell_stats->total_time_exitward); - } - *event_string = smartlist_join_strings(event_parts, " ", 0, NULL); - SMARTLIST_FOREACH(event_parts, char *, cp, tor_free(cp)); - smartlist_free(event_parts); -} - -/** A second or more has elapsed: tell any interested control connection - * how many cells have been processed for a given circuit. */ -int -control_event_circuit_cell_stats(void) -{ - cell_stats_t *cell_stats; - char *event_string; - if (!get_options()->TestingEnableCellStatsEvent || - !EVENT_IS_INTERESTING(EVENT_CELL_STATS)) - return 0; - cell_stats = tor_malloc(sizeof(cell_stats_t)); - SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { - if (!circ->testing_cell_stats) - continue; - sum_up_cell_stats_by_command(circ, cell_stats); - format_cell_stats(&event_string, circ, cell_stats); - send_control_event(EVENT_CELL_STATS, - "650 CELL_STATS %s\r\n", event_string); - tor_free(event_string); - } - SMARTLIST_FOREACH_END(circ); - tor_free(cell_stats); - return 0; -} - -/* about 5 minutes worth. */ -#define N_BW_EVENTS_TO_CACHE 300 -/* Index into cached_bw_events to next write. */ -static int next_measurement_idx = 0; -/* number of entries set in n_measurements */ -static int n_measurements = 0; -static struct cached_bw_event_s { - uint32_t n_read; - uint32_t n_written; -} cached_bw_events[N_BW_EVENTS_TO_CACHE]; - -/** A second or more has elapsed: tell any interested control - * connections how much bandwidth we used. */ -int -control_event_bandwidth_used(uint32_t n_read, uint32_t n_written) -{ - cached_bw_events[next_measurement_idx].n_read = n_read; - cached_bw_events[next_measurement_idx].n_written = n_written; - if (++next_measurement_idx == N_BW_EVENTS_TO_CACHE) - next_measurement_idx = 0; - if (n_measurements < N_BW_EVENTS_TO_CACHE) - ++n_measurements; - - if (EVENT_IS_INTERESTING(EVENT_BANDWIDTH_USED)) { - send_control_event(EVENT_BANDWIDTH_USED, - "650 BW %lu %lu\r\n", - (unsigned long)n_read, - (unsigned long)n_written); - } - - return 0; -} - -STATIC char * -get_bw_samples(void) -{ - int i; - int idx = (next_measurement_idx + N_BW_EVENTS_TO_CACHE - n_measurements) - % N_BW_EVENTS_TO_CACHE; - tor_assert(0 <= idx && idx < N_BW_EVENTS_TO_CACHE); - - smartlist_t *elements = smartlist_new(); - - for (i = 0; i < n_measurements; ++i) { - tor_assert(0 <= idx && idx < N_BW_EVENTS_TO_CACHE); - const struct cached_bw_event_s *bwe = &cached_bw_events[idx]; - - smartlist_add_asprintf(elements, "%u,%u", - (unsigned)bwe->n_read, - (unsigned)bwe->n_written); - - idx = (idx + 1) % N_BW_EVENTS_TO_CACHE; - } - - char *result = smartlist_join_strings(elements, " ", 0, NULL); - - SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp)); - smartlist_free(elements); - - return result; -} - -/** Called when we are sending a log message to the controllers: suspend - * sending further log messages to the controllers until we're done. Used by - * CONN_LOG_PROTECT. */ -void -disable_control_logging(void) -{ - ++disable_log_messages; -} - -/** We're done sending a log message to the controllers: re-enable controller - * logging. Used by CONN_LOG_PROTECT. */ -void -enable_control_logging(void) -{ - if (--disable_log_messages < 0) - tor_assert(0); -} - -/** We got a log message: tell any interested control connections. */ -void -control_event_logmsg(int severity, uint32_t domain, const char *msg) -{ - int event; - - /* Don't even think of trying to add stuff to a buffer from a cpuworker - * thread. (See #25987 for plan to fix.) */ - if (! in_main_thread()) - return; - - if (disable_log_messages) - return; - - if (domain == LD_BUG && EVENT_IS_INTERESTING(EVENT_STATUS_GENERAL) && - severity <= LOG_NOTICE) { - char *esc = esc_for_log(msg); - ++disable_log_messages; - control_event_general_status(severity, "BUG REASON=%s", esc); - --disable_log_messages; - tor_free(esc); - } - - event = log_severity_to_event(severity); - if (event >= 0 && EVENT_IS_INTERESTING(event)) { - char *b = NULL; - const char *s; - if (strchr(msg, '\n')) { - char *cp; - b = tor_strdup(msg); - for (cp = b; *cp; ++cp) - if (*cp == '\r' || *cp == '\n') - *cp = ' '; - } - switch (severity) { - case LOG_DEBUG: s = "DEBUG"; break; - case LOG_INFO: s = "INFO"; break; - case LOG_NOTICE: s = "NOTICE"; break; - case LOG_WARN: s = "WARN"; break; - case LOG_ERR: s = "ERR"; break; - default: s = "UnknownLogSeverity"; break; - } - ++disable_log_messages; - send_control_event(event, "650 %s %s\r\n", s, b?b:msg); - if (severity == LOG_ERR) { - /* Force a flush, since we may be about to die horribly */ - queued_events_flush_all(1); - } - --disable_log_messages; - tor_free(b); - } -} +static int +peek_connection_has_http_command(connection_t *conn) +{ + return peek_buf_has_http_command(conn->inbuf); +} /** - * Logging callback: called when there is a queued pending log callback. - */ -void -control_event_logmsg_pending(void) -{ - if (! in_main_thread()) { - /* We can't handle this case yet, since we're using a - * mainloop_event_t to invoke queued_events_flush_all. We ought to - * use a different mechanism instead: see #25987. - **/ - return; - } - tor_assert(flush_queued_events_event); - mainloop_event_activate(flush_queued_events_event); -} - -/** Called whenever we receive new router descriptors: tell any - * interested control connections. routers is a list of - * routerinfo_t's. - */ -int -control_event_descriptors_changed(smartlist_t *routers) -{ - char *msg; - - if (!EVENT_IS_INTERESTING(EVENT_NEW_DESC)) - return 0; - - { - smartlist_t *names = smartlist_new(); - char *ids; - SMARTLIST_FOREACH(routers, routerinfo_t *, ri, { - char *b = tor_malloc(MAX_VERBOSE_NICKNAME_LEN+1); - router_get_verbose_nickname(b, ri); - smartlist_add(names, b); - }); - ids = smartlist_join_strings(names, " ", 0, NULL); - tor_asprintf(&msg, "650 NEWDESC %s\r\n", ids); - send_control_event_string(EVENT_NEW_DESC, msg); - tor_free(ids); - tor_free(msg); - SMARTLIST_FOREACH(names, char *, cp, tor_free(cp)); - smartlist_free(names); - } - return 0; -} - -/** Called when an address mapping on from from changes to to. - * expires values less than 3 are special; see connection_edge.c. If - * error is non-NULL, it is an error code describing the failure - * mode of the mapping. - */ -int -control_event_address_mapped(const char *from, const char *to, time_t expires, - const char *error, const int cached) -{ - if (!EVENT_IS_INTERESTING(EVENT_ADDRMAP)) - return 0; - - if (expires < 3 || expires == TIME_MAX) - send_control_event(EVENT_ADDRMAP, - "650 ADDRMAP %s %s NEVER %s%s" - "CACHED=\"%s\"\r\n", - from, to, error?error:"", error?" ":"", - cached?"YES":"NO"); - else { - char buf[ISO_TIME_LEN+1]; - char buf2[ISO_TIME_LEN+1]; - format_local_iso_time(buf,expires); - format_iso_time(buf2,expires); - send_control_event(EVENT_ADDRMAP, - "650 ADDRMAP %s %s \"%s\"" - " %s%sEXPIRES=\"%s\" CACHED=\"%s\"\r\n", - from, to, buf, - error?error:"", error?" ":"", - buf2, cached?"YES":"NO"); - } - - return 0; -} - -/** Cached liveness for network liveness events and GETINFO - */ - -static int network_is_live = 0; - -static int -get_cached_network_liveness(void) -{ - return network_is_live; -} - -static void -set_cached_network_liveness(int liveness) -{ - network_is_live = liveness; -} + * Helper: take a nul-terminated command of given length, and find where the + * command starts and the arguments begin. Separate them, allocate a new + * string in current_cmd_out for the command, and return a pointer + * to the arguments. + **/ +STATIC char * +control_split_incoming_command(char *incoming_cmd, + size_t *data_len, + char **current_cmd_out) +{ + const bool is_multiline = *data_len && incoming_cmd[0] == '+'; + size_t cmd_len = 0; + while (cmd_len < *data_len + && !TOR_ISSPACE(incoming_cmd[cmd_len])) + ++cmd_len; -/** The network liveness has changed; this is called from circuitstats.c - * whenever we receive a cell, or when timeout expires and we assume the - * network is down. */ -int -control_event_network_liveness_update(int liveness) -{ - if (liveness > 0) { - if (get_cached_network_liveness() <= 0) { - /* Update cached liveness */ - set_cached_network_liveness(1); - log_debug(LD_CONTROL, "Sending NETWORK_LIVENESS UP"); - send_control_event_string(EVENT_NETWORK_LIVENESS, - "650 NETWORK_LIVENESS UP\r\n"); + *current_cmd_out = tor_memdup_nulterm(incoming_cmd, cmd_len); + char *args = incoming_cmd+cmd_len; + tor_assert(*data_len>=cmd_len); + *data_len -= cmd_len; + if (is_multiline) { + // Only match horizontal space: any line after the first is data, + // not arguments. + while ((*args == '\t' || *args == ' ') && *data_len) { + ++args; + --*data_len; } - /* else was already live, no-op */ } else { - if (get_cached_network_liveness() > 0) { - /* Update cached liveness */ - set_cached_network_liveness(0); - log_debug(LD_CONTROL, "Sending NETWORK_LIVENESS DOWN"); - send_control_event_string(EVENT_NETWORK_LIVENESS, - "650 NETWORK_LIVENESS DOWN\r\n"); + while (TOR_ISSPACE(*args) && *data_len) { + ++args; + --*data_len; } - /* else was already dead, no-op */ } - return 0; -} - -/** Helper function for NS-style events. Constructs and sends an event - * of type event with string event_string out of the set of - * networkstatuses statuses. Currently it is used for NS events - * and NEWCONSENSUS events. */ -static int -control_event_networkstatus_changed_helper(smartlist_t *statuses, - uint16_t event, - const char *event_string) -{ - smartlist_t *strs; - char *s, *esc = NULL; - if (!EVENT_IS_INTERESTING(event) || !smartlist_len(statuses)) - return 0; - - strs = smartlist_new(); - smartlist_add_strdup(strs, "650+"); - smartlist_add_strdup(strs, event_string); - smartlist_add_strdup(strs, "\r\n"); - SMARTLIST_FOREACH(statuses, const routerstatus_t *, rs, - { - s = networkstatus_getinfo_helper_single(rs); - if (!s) continue; - smartlist_add(strs, s); - }); - - s = smartlist_join_strings(strs, "", 0, NULL); - write_escaped_data(s, strlen(s), &esc); - SMARTLIST_FOREACH(strs, char *, cp, tor_free(cp)); - smartlist_free(strs); - tor_free(s); - send_control_event_string(event, esc); - send_control_event_string(event, - "650 OK\r\n"); - - tor_free(esc); - return 0; -} - -/** Called when the routerstatus_ts statuses have changed: sends - * an NS event to any controller that cares. */ -int -control_event_networkstatus_changed(smartlist_t *statuses) -{ - return control_event_networkstatus_changed_helper(statuses, EVENT_NS, "NS"); + return args; } -/** Called when we get a new consensus networkstatus. Sends a NEWCONSENSUS - * event consisting of an NS-style line for each relay in the consensus. */ -int -control_event_newconsensus(const networkstatus_t *consensus) -{ - if (!control_event_is_interesting(EVENT_NEWCONSENSUS)) - return 0; - return control_event_networkstatus_changed_helper( - consensus->routerstatus_list, EVENT_NEWCONSENSUS, "NEWCONSENSUS"); -} +static const char CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG[] = + "HTTP/1.0 501 Tor ControlPort is not an HTTP proxy" + "\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n" + "\n" + "\n" + "Tor's ControlPort is not an HTTP proxy\n" + "\n" + "\n" + "

Tor's ControlPort is not an HTTP proxy

\n" + "

\n" + "It appears you have configured your web browser to use Tor's control port" + " as an HTTP proxy.\n" + "This is not correct: Tor's default SOCKS proxy port is 9050.\n" + "Please configure your client accordingly.\n" + "

\n" + "

\n" + "See " + "https://www.torproject.org/documentation.html for more " + "information.\n" + "\n" + "

\n" + "\n" + "\n"; -/** Called when we compute a new circuitbuildtimeout */ +/** Called when data has arrived on a v1 control connection: Try to fetch + * commands from conn->inbuf, and execute them. + */ int -control_event_buildtimeout_set(buildtimeout_set_event_t type, - const char *args) +connection_control_process_inbuf(control_connection_t *conn) { - const char *type_string = NULL; + size_t data_len; + uint32_t cmd_data_len; + char *args; - if (!control_event_is_interesting(EVENT_BUILDTIMEOUT_SET)) - return 0; + tor_assert(conn); + tor_assert(conn->base_.state == CONTROL_CONN_STATE_OPEN || + conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH); - switch (type) { - case BUILDTIMEOUT_SET_EVENT_COMPUTED: - type_string = "COMPUTED"; - break; - case BUILDTIMEOUT_SET_EVENT_RESET: - type_string = "RESET"; - break; - case BUILDTIMEOUT_SET_EVENT_SUSPENDED: - type_string = "SUSPENDED"; - break; - case BUILDTIMEOUT_SET_EVENT_DISCARD: - type_string = "DISCARD"; - break; - case BUILDTIMEOUT_SET_EVENT_RESUME: - type_string = "RESUME"; - break; - default: - type_string = "UNKNOWN"; - break; + if (!conn->incoming_cmd) { + conn->incoming_cmd = tor_malloc(1024); + conn->incoming_cmd_len = 1024; + conn->incoming_cmd_cur_len = 0; } - send_control_event(EVENT_BUILDTIMEOUT_SET, - "650 BUILDTIMEOUT_SET %s %s\r\n", - type_string, args); - - return 0; -} - -/** Called when a signal has been processed from signal_callback */ -int -control_event_signal(uintptr_t signal_num) -{ - const char *signal_string = NULL; + if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && + peek_connection_has_control0_command(TO_CONN(conn))) { + /* Detect v0 commands and send a "no more v0" message. */ + size_t body_len; + char buf[128]; + set_uint16(buf+2, htons(0x0000)); /* type == error */ + set_uint16(buf+4, htons(0x0001)); /* code == internal error */ + strlcpy(buf+6, "The v0 control protocol is not supported by Tor 0.1.2.17 " + "and later; upgrade your controller.", + sizeof(buf)-6); + body_len = 2+strlen(buf+6)+2; /* code, msg, nul. */ + set_uint16(buf+0, htons(body_len)); + connection_buf_add(buf, 4+body_len, TO_CONN(conn)); - if (!control_event_is_interesting(EVENT_GOT_SIGNAL)) + connection_mark_and_flush(TO_CONN(conn)); return 0; - - switch (signal_num) { - case SIGHUP: - signal_string = "RELOAD"; - break; - case SIGUSR1: - signal_string = "DUMP"; - break; - case SIGUSR2: - signal_string = "DEBUG"; - break; - case SIGNEWNYM: - signal_string = "NEWNYM"; - break; - case SIGCLEARDNSCACHE: - signal_string = "CLEARDNSCACHE"; - break; - case SIGHEARTBEAT: - signal_string = "HEARTBEAT"; - break; - default: - log_warn(LD_BUG, "Unrecognized signal %lu in control_event_signal", - (unsigned long)signal_num); - return -1; } - send_control_event(EVENT_GOT_SIGNAL, "650 SIGNAL %s\r\n", - signal_string); - return 0; -} - -/** Called when a single local_routerstatus_t has changed: Sends an NS event - * to any controller that cares. */ -int -control_event_networkstatus_changed_single(const routerstatus_t *rs) -{ - smartlist_t *statuses; - int r; - - if (!EVENT_IS_INTERESTING(EVENT_NS)) + /* If the user has the HTTP proxy port and the control port confused. */ + if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && + peek_connection_has_http_command(TO_CONN(conn))) { + connection_write_str_to_buf(CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG, conn); + log_notice(LD_CONTROL, "Received HTTP request on ControlPort"); + connection_mark_and_flush(TO_CONN(conn)); return 0; + } - statuses = smartlist_new(); - smartlist_add(statuses, (void*)rs); - r = control_event_networkstatus_changed(statuses); - smartlist_free(statuses); - return r; -} + again: + while (1) { + size_t last_idx; + int r; + /* First, fetch a line. */ + do { + data_len = conn->incoming_cmd_len - conn->incoming_cmd_cur_len; + r = connection_buf_get_line(TO_CONN(conn), + conn->incoming_cmd+conn->incoming_cmd_cur_len, + &data_len); + if (r == 0) + /* Line not all here yet. Wait. */ + return 0; + else if (r == -1) { + if (data_len + conn->incoming_cmd_cur_len > MAX_COMMAND_LINE_LENGTH) { + control_write_endreply(conn, 500, "Line too long."); + connection_stop_reading(TO_CONN(conn)); + connection_mark_and_flush(TO_CONN(conn)); + } + while (conn->incoming_cmd_len < data_len+conn->incoming_cmd_cur_len) + conn->incoming_cmd_len *= 2; + conn->incoming_cmd = tor_realloc(conn->incoming_cmd, + conn->incoming_cmd_len); + } + } while (r != 1); -/** Our own router descriptor has changed; tell any controllers that care. - */ -int -control_event_my_descriptor_changed(void) -{ - send_control_event(EVENT_DESCCHANGED, "650 DESCCHANGED\r\n"); - return 0; -} + tor_assert(data_len); -/** Helper: sends a status event where type is one of - * EVENT_STATUS_{GENERAL,CLIENT,SERVER}, where severity is one of - * LOG_{NOTICE,WARN,ERR}, and where format is a printf-style format - * string corresponding to args. */ -static int -control_event_status(int type, int severity, const char *format, va_list args) -{ - char *user_buf = NULL; - char format_buf[160]; - const char *status, *sev; + last_idx = conn->incoming_cmd_cur_len; + conn->incoming_cmd_cur_len += (int)data_len; - switch (type) { - case EVENT_STATUS_GENERAL: - status = "STATUS_GENERAL"; - break; - case EVENT_STATUS_CLIENT: - status = "STATUS_CLIENT"; - break; - case EVENT_STATUS_SERVER: - status = "STATUS_SERVER"; - break; - default: - log_warn(LD_BUG, "Unrecognized status type %d", type); - return -1; - } - switch (severity) { - case LOG_NOTICE: - sev = "NOTICE"; + /* We have appended a line to incoming_cmd. Is the command done? */ + if (last_idx == 0 && *conn->incoming_cmd != '+') + /* One line command, didn't start with '+'. */ break; - case LOG_WARN: - sev = "WARN"; + /* XXXX this code duplication is kind of dumb. */ + if (last_idx+3 == conn->incoming_cmd_cur_len && + tor_memeq(conn->incoming_cmd + last_idx, ".\r\n", 3)) { + /* Just appended ".\r\n"; we're done. Remove it. */ + conn->incoming_cmd[last_idx] = '\0'; + conn->incoming_cmd_cur_len -= 3; break; - case LOG_ERR: - sev = "ERR"; + } else if (last_idx+2 == conn->incoming_cmd_cur_len && + tor_memeq(conn->incoming_cmd + last_idx, ".\n", 2)) { + /* Just appended ".\n"; we're done. Remove it. */ + conn->incoming_cmd[last_idx] = '\0'; + conn->incoming_cmd_cur_len -= 2; break; - default: - log_warn(LD_BUG, "Unrecognized status severity %d", severity); - return -1; - } - if (tor_snprintf(format_buf, sizeof(format_buf), "650 %s %s", - status, sev)<0) { - log_warn(LD_BUG, "Format string too long."); - return -1; - } - tor_vasprintf(&user_buf, format, args); - - send_control_event(type, "%s %s\r\n", format_buf, user_buf); - tor_free(user_buf); - return 0; -} - -#define CONTROL_EVENT_STATUS_BODY(event, sev) \ - int r; \ - do { \ - va_list ap; \ - if (!EVENT_IS_INTERESTING(event)) \ - return 0; \ - \ - va_start(ap, format); \ - r = control_event_status((event), (sev), format, ap); \ - va_end(ap); \ - } while (0) - -/** Format and send an EVENT_STATUS_GENERAL event whose main text is obtained - * by formatting the arguments using the printf-style format. */ -int -control_event_general_status(int severity, const char *format, ...) -{ - CONTROL_EVENT_STATUS_BODY(EVENT_STATUS_GENERAL, severity); - return r; -} - -/** Format and send an EVENT_STATUS_GENERAL LOG_ERR event, and flush it to the - * controller(s) immediately. */ -int -control_event_general_error(const char *format, ...) -{ - CONTROL_EVENT_STATUS_BODY(EVENT_STATUS_GENERAL, LOG_ERR); - /* Force a flush, since we may be about to die horribly */ - queued_events_flush_all(1); - return r; -} - -/** Format and send an EVENT_STATUS_CLIENT event whose main text is obtained - * by formatting the arguments using the printf-style format. */ -int -control_event_client_status(int severity, const char *format, ...) -{ - CONTROL_EVENT_STATUS_BODY(EVENT_STATUS_CLIENT, severity); - return r; -} - -/** Format and send an EVENT_STATUS_CLIENT LOG_ERR event, and flush it to the - * controller(s) immediately. */ -int -control_event_client_error(const char *format, ...) -{ - CONTROL_EVENT_STATUS_BODY(EVENT_STATUS_CLIENT, LOG_ERR); - /* Force a flush, since we may be about to die horribly */ - queued_events_flush_all(1); - return r; -} - -/** Format and send an EVENT_STATUS_SERVER event whose main text is obtained - * by formatting the arguments using the printf-style format. */ -int -control_event_server_status(int severity, const char *format, ...) -{ - CONTROL_EVENT_STATUS_BODY(EVENT_STATUS_SERVER, severity); - return r; -} + } + /* Otherwise, read another line. */ + } + data_len = conn->incoming_cmd_cur_len; -/** Format and send an EVENT_STATUS_SERVER LOG_ERR event, and flush it to the - * controller(s) immediately. */ -int -control_event_server_error(const char *format, ...) -{ - CONTROL_EVENT_STATUS_BODY(EVENT_STATUS_SERVER, LOG_ERR); - /* Force a flush, since we may be about to die horribly */ - queued_events_flush_all(1); - return r; -} + /* Okay, we now have a command sitting on conn->incoming_cmd. See if we + * recognize it. + */ + tor_free(conn->current_cmd); + args = control_split_incoming_command(conn->incoming_cmd, &data_len, + &conn->current_cmd); + if (BUG(!conn->current_cmd)) + return -1; -/** Called when the status of an entry guard with the given nickname - * and identity digest has changed to status: tells any - * controllers that care. */ -int -control_event_guard(const char *nickname, const char *digest, - const char *status) -{ - char hbuf[HEX_DIGEST_LEN+1]; - base16_encode(hbuf, sizeof(hbuf), digest, DIGEST_LEN); - if (!EVENT_IS_INTERESTING(EVENT_GUARD)) + /* If the connection is already closing, ignore further commands */ + if (TO_CONN(conn)->marked_for_close) { return 0; - - { - char buf[MAX_VERBOSE_NICKNAME_LEN+1]; - const node_t *node = node_get_by_id(digest); - if (node) { - node_get_verbose_nickname(node, buf); - } else { - tor_snprintf(buf, sizeof(buf), "$%s~%s", hbuf, nickname); - } - send_control_event(EVENT_GUARD, - "650 GUARD ENTRY %s %s\r\n", buf, status); } - return 0; -} -/** Called when a configuration option changes. This is generally triggered - * by SETCONF requests and RELOAD/SIGHUP signals. The elements is - * a smartlist_t containing (key, value, ...) pairs in sequence. - * value can be NULL. */ -int -control_event_conf_changed(const smartlist_t *elements) -{ - int i; - char *result; - smartlist_t *lines; - if (!EVENT_IS_INTERESTING(EVENT_CONF_CHANGED) || - smartlist_len(elements) == 0) { + /* Otherwise, Quit is always valid. */ + if (!strcasecmp(conn->current_cmd, "QUIT")) { + control_write_endreply(conn, 250, "closing connection"); + connection_mark_and_flush(TO_CONN(conn)); return 0; } - lines = smartlist_new(); - for (i = 0; i < smartlist_len(elements); i += 2) { - char *k = smartlist_get(elements, i); - char *v = smartlist_get(elements, i+1); - if (v == NULL) { - smartlist_add_asprintf(lines, "650-%s", k); - } else { - smartlist_add_asprintf(lines, "650-%s=%s", k, v); - } + + if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && + !is_valid_initial_command(conn, conn->current_cmd)) { + control_write_endreply(conn, 514, "Authentication required."); + connection_mark_for_close(TO_CONN(conn)); + return 0; } - result = smartlist_join_strings(lines, "\r\n", 0, NULL); - send_control_event(EVENT_CONF_CHANGED, - "650-CONF_CHANGED\r\n%s\r\n650 OK\r\n", result); - tor_free(result); - SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); - smartlist_free(lines); - return 0; -} -/** Helper: Return a newly allocated string containing a path to the - * file where we store our authentication cookie. */ -char * -get_controller_cookie_file_name(void) -{ - const or_options_t *options = get_options(); - if (options->CookieAuthFile && strlen(options->CookieAuthFile)) { - return tor_strdup(options->CookieAuthFile); - } else { - return get_datadir_fname("control_auth_cookie"); + if (data_len >= UINT32_MAX) { + control_write_endreply(conn, 500, "A 4GB command? Nice try."); + connection_mark_for_close(TO_CONN(conn)); + return 0; } + + cmd_data_len = (uint32_t)data_len; + if (handle_control_command(conn, cmd_data_len, args) < 0) + return -1; + + conn->incoming_cmd_cur_len = 0; + goto again; } -/* Initialize the cookie-based authentication system of the - * ControlPort. If enabled is 0, then disable the cookie - * authentication system. */ +/** Cached liveness for network liveness events and GETINFO + */ + +static int network_is_live = 0; + int -init_control_cookie_authentication(int enabled) +get_cached_network_liveness(void) { - char *fname = NULL; - int retval; - - if (!enabled) { - authentication_cookie_is_set = 0; - return 0; - } + return network_is_live; +} - fname = get_controller_cookie_file_name(); - retval = init_cookie_authentication(fname, "", /* no header */ - AUTHENTICATION_COOKIE_LEN, - get_options()->CookieAuthFileGroupReadable, - &authentication_cookie, - &authentication_cookie_is_set); - tor_free(fname); - return retval; +void +set_cached_network_liveness(int liveness) +{ + network_is_live = liveness; } /** A copy of the process specifier of Tor's owning controller, or @@ -7025,553 +566,12 @@ monitor_owning_controller_process(const char *process_spec) } } -/** We just generated a new summary of which countries we've seen clients - * from recently. Send a copy to the controller in case it wants to - * display it for the user. */ -void -control_event_clients_seen(const char *controller_str) -{ - send_control_event(EVENT_CLIENTS_SEEN, - "650 CLIENTS_SEEN %s\r\n", controller_str); -} - -/** A new pluggable transport called transport_name was - * launched on addr:port. mode is either - * "server" or "client" depending on the mode of the pluggable - * transport. - * "650" SP "TRANSPORT_LAUNCHED" SP Mode SP Name SP Address SP Port - */ -void -control_event_transport_launched(const char *mode, const char *transport_name, - tor_addr_t *addr, uint16_t port) -{ - send_control_event(EVENT_TRANSPORT_LAUNCHED, - "650 TRANSPORT_LAUNCHED %s %s %s %u\r\n", - mode, transport_name, fmt_addr(addr), port); -} - -/** A pluggable transport called pt_name has emitted a log message - * found in message at severity log level. */ -void -control_event_pt_log(const char *log) -{ - send_control_event(EVENT_PT_LOG, - "650 PT_LOG %s\r\n", - log); -} - -/** A pluggable transport has emitted a STATUS message found in - * status. */ -void -control_event_pt_status(const char *status) -{ - send_control_event(EVENT_PT_STATUS, - "650 PT_STATUS %s\r\n", - status); -} - -/** Convert rendezvous auth type to string for HS_DESC control events - */ -const char * -rend_auth_type_to_string(rend_auth_type_t auth_type) -{ - const char *str; - - switch (auth_type) { - case REND_NO_AUTH: - str = "NO_AUTH"; - break; - case REND_BASIC_AUTH: - str = "BASIC_AUTH"; - break; - case REND_STEALTH_AUTH: - str = "STEALTH_AUTH"; - break; - default: - str = "UNKNOWN"; - } - - return str; -} - -/** Return a longname the node whose identity is id_digest. If - * node_get_by_id() returns NULL, base 16 encoding of id_digest is - * returned instead. - * - * This function is not thread-safe. Each call to this function invalidates - * previous values returned by this function. - */ -MOCK_IMPL(const char *, -node_describe_longname_by_id,(const char *id_digest)) -{ - static char longname[MAX_VERBOSE_NICKNAME_LEN+1]; - node_get_verbose_nickname_by_id(id_digest, longname); - return longname; -} - -/** Return either the onion address if the given pointer is a non empty - * string else the unknown string. */ -static const char * -rend_hsaddress_str_or_unknown(const char *onion_address) -{ - static const char *str_unknown = "UNKNOWN"; - const char *str_ret = str_unknown; - - /* No valid pointer, unknown it is. */ - if (!onion_address) { - goto end; - } - /* Empty onion address thus we don't know, unknown it is. */ - if (onion_address[0] == '\0') { - goto end; - } - /* All checks are good so return the given onion address. */ - str_ret = onion_address; - - end: - return str_ret; -} - -/** send HS_DESC requested event. - * - * rend_query is used to fetch requested onion address and auth type. - * hs_dir is the description of contacting hs directory. - * desc_id_base32 is the ID of requested hs descriptor. - * hsdir_index is the HSDir fetch index value for v3, an hex string. - */ -void -control_event_hs_descriptor_requested(const char *onion_address, - rend_auth_type_t auth_type, - const char *id_digest, - const char *desc_id, - const char *hsdir_index) -{ - char *hsdir_index_field = NULL; - - if (BUG(!id_digest || !desc_id)) { - return; - } - - if (hsdir_index) { - tor_asprintf(&hsdir_index_field, " HSDIR_INDEX=%s", hsdir_index); - } - - send_control_event(EVENT_HS_DESC, - "650 HS_DESC REQUESTED %s %s %s %s%s\r\n", - rend_hsaddress_str_or_unknown(onion_address), - rend_auth_type_to_string(auth_type), - node_describe_longname_by_id(id_digest), - desc_id, - hsdir_index_field ? hsdir_index_field : ""); - tor_free(hsdir_index_field); -} - -/** For an HS descriptor query rend_data, using the - * onion_address and HSDir fingerprint hsdir_fp, find out - * which descriptor ID in the query is the right one. - * - * Return a pointer of the binary descriptor ID found in the query's object - * or NULL if not found. */ -static const char * -get_desc_id_from_query(const rend_data_t *rend_data, const char *hsdir_fp) -{ - int replica; - const char *desc_id = NULL; - const rend_data_v2_t *rend_data_v2 = TO_REND_DATA_V2(rend_data); - - /* Possible if the fetch was done using a descriptor ID. This means that - * the HSFETCH command was used. */ - if (!tor_digest_is_zero(rend_data_v2->desc_id_fetch)) { - desc_id = rend_data_v2->desc_id_fetch; - goto end; - } - - /* Without a directory fingerprint at this stage, we can't do much. */ - if (hsdir_fp == NULL) { - goto end; - } - - /* OK, we have an onion address so now let's find which descriptor ID - * is the one associated with the HSDir fingerprint. */ - for (replica = 0; replica < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; - replica++) { - const char *digest = rend_data_get_desc_id(rend_data, replica, NULL); - - SMARTLIST_FOREACH_BEGIN(rend_data->hsdirs_fp, char *, fingerprint) { - if (tor_memcmp(fingerprint, hsdir_fp, DIGEST_LEN) == 0) { - /* Found it! This descriptor ID is the right one. */ - desc_id = digest; - goto end; - } - } SMARTLIST_FOREACH_END(fingerprint); - } - - end: - return desc_id; -} - -/** send HS_DESC CREATED event when a local service generates a descriptor. - * - * onion_address is service address. - * desc_id is the descriptor ID. - * replica is the the descriptor replica number. If it is negative, it - * is ignored. - */ -void -control_event_hs_descriptor_created(const char *onion_address, - const char *desc_id, - int replica) -{ - char *replica_field = NULL; - - if (BUG(!onion_address || !desc_id)) { - return; - } - - if (replica >= 0) { - tor_asprintf(&replica_field, " REPLICA=%d", replica); - } - - send_control_event(EVENT_HS_DESC, - "650 HS_DESC CREATED %s UNKNOWN UNKNOWN %s%s\r\n", - onion_address, desc_id, - replica_field ? replica_field : ""); - tor_free(replica_field); -} - -/** send HS_DESC upload event. - * - * onion_address is service address. - * hs_dir is the description of contacting hs directory. - * desc_id is the ID of requested hs descriptor. - */ -void -control_event_hs_descriptor_upload(const char *onion_address, - const char *id_digest, - const char *desc_id, - const char *hsdir_index) -{ - char *hsdir_index_field = NULL; - - if (BUG(!onion_address || !id_digest || !desc_id)) { - return; - } - - if (hsdir_index) { - tor_asprintf(&hsdir_index_field, " HSDIR_INDEX=%s", hsdir_index); - } - - send_control_event(EVENT_HS_DESC, - "650 HS_DESC UPLOAD %s UNKNOWN %s %s%s\r\n", - onion_address, - node_describe_longname_by_id(id_digest), - desc_id, - hsdir_index_field ? hsdir_index_field : ""); - tor_free(hsdir_index_field); -} - -/** send HS_DESC event after got response from hs directory. - * - * NOTE: this is an internal function used by following functions: - * control_event_hsv2_descriptor_received - * control_event_hsv2_descriptor_failed - * control_event_hsv3_descriptor_failed - * - * So do not call this function directly. - */ -static void -event_hs_descriptor_receive_end(const char *action, - const char *onion_address, - const char *desc_id, - rend_auth_type_t auth_type, - const char *hsdir_id_digest, - const char *reason) -{ - char *reason_field = NULL; - - if (BUG(!action || !onion_address)) { - return; - } - - if (reason) { - tor_asprintf(&reason_field, " REASON=%s", reason); - } - - send_control_event(EVENT_HS_DESC, - "650 HS_DESC %s %s %s %s%s%s\r\n", - action, - rend_hsaddress_str_or_unknown(onion_address), - rend_auth_type_to_string(auth_type), - hsdir_id_digest ? - node_describe_longname_by_id(hsdir_id_digest) : - "UNKNOWN", - desc_id ? desc_id : "", - reason_field ? reason_field : ""); - - tor_free(reason_field); -} - -/** send HS_DESC event after got response from hs directory. - * - * NOTE: this is an internal function used by following functions: - * control_event_hs_descriptor_uploaded - * control_event_hs_descriptor_upload_failed - * - * So do not call this function directly. - */ -void -control_event_hs_descriptor_upload_end(const char *action, - const char *onion_address, - const char *id_digest, - const char *reason) -{ - char *reason_field = NULL; - - if (BUG(!action || !id_digest)) { - return; - } - - if (reason) { - tor_asprintf(&reason_field, " REASON=%s", reason); - } - - send_control_event(EVENT_HS_DESC, - "650 HS_DESC %s %s UNKNOWN %s%s\r\n", - action, - rend_hsaddress_str_or_unknown(onion_address), - node_describe_longname_by_id(id_digest), - reason_field ? reason_field : ""); - - tor_free(reason_field); -} - -/** send HS_DESC RECEIVED event - * - * called when we successfully received a hidden service descriptor. - */ -void -control_event_hsv2_descriptor_received(const char *onion_address, - const rend_data_t *rend_data, - const char *hsdir_id_digest) -{ - char *desc_id_field = NULL; - const char *desc_id; - - if (BUG(!rend_data || !hsdir_id_digest || !onion_address)) { - return; - } - - desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest); - if (desc_id != NULL) { - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - /* Set the descriptor ID digest to base32 so we can send it. */ - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id, - DIGEST_LEN); - /* Extra whitespace is needed before the value. */ - tor_asprintf(&desc_id_field, " %s", desc_id_base32); - } - - event_hs_descriptor_receive_end("RECEIVED", onion_address, desc_id_field, - TO_REND_DATA_V2(rend_data)->auth_type, - hsdir_id_digest, NULL); - tor_free(desc_id_field); -} - -/* Send HS_DESC RECEIVED event - * - * Called when we successfully received a hidden service descriptor. */ -void -control_event_hsv3_descriptor_received(const char *onion_address, - const char *desc_id, - const char *hsdir_id_digest) -{ - char *desc_id_field = NULL; - - if (BUG(!onion_address || !desc_id || !hsdir_id_digest)) { - return; - } - - /* Because DescriptorID is an optional positional value, we need to add a - * whitespace before in order to not be next to the HsDir value. */ - tor_asprintf(&desc_id_field, " %s", desc_id); - - event_hs_descriptor_receive_end("RECEIVED", onion_address, desc_id_field, - REND_NO_AUTH, hsdir_id_digest, NULL); - tor_free(desc_id_field); -} - -/** send HS_DESC UPLOADED event - * - * called when we successfully uploaded a hidden service descriptor. - */ -void -control_event_hs_descriptor_uploaded(const char *id_digest, - const char *onion_address) -{ - if (BUG(!id_digest)) { - return; - } - - control_event_hs_descriptor_upload_end("UPLOADED", onion_address, - id_digest, NULL); -} - -/** Send HS_DESC event to inform controller that query rend_data - * failed to retrieve hidden service descriptor from directory identified by - * id_digest. If NULL, "UNKNOWN" is used. If reason is not NULL, - * add it to REASON= field. - */ -void -control_event_hsv2_descriptor_failed(const rend_data_t *rend_data, - const char *hsdir_id_digest, - const char *reason) -{ - char *desc_id_field = NULL; - const char *desc_id; - - if (BUG(!rend_data)) { - return; - } - - desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest); - if (desc_id != NULL) { - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - /* Set the descriptor ID digest to base32 so we can send it. */ - base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id, - DIGEST_LEN); - /* Extra whitespace is needed before the value. */ - tor_asprintf(&desc_id_field, " %s", desc_id_base32); - } - - event_hs_descriptor_receive_end("FAILED", rend_data_get_address(rend_data), - desc_id_field, - TO_REND_DATA_V2(rend_data)->auth_type, - hsdir_id_digest, reason); - tor_free(desc_id_field); -} - -/** Send HS_DESC event to inform controller that the query to - * onion_address failed to retrieve hidden service descriptor - * desc_id from directory identified by hsdir_id_digest. If - * NULL, "UNKNOWN" is used. If reason is not NULL, add it to REASON= - * field. */ -void -control_event_hsv3_descriptor_failed(const char *onion_address, - const char *desc_id, - const char *hsdir_id_digest, - const char *reason) -{ - char *desc_id_field = NULL; - - if (BUG(!onion_address || !desc_id || !reason)) { - return; - } - - /* Because DescriptorID is an optional positional value, we need to add a - * whitespace before in order to not be next to the HsDir value. */ - tor_asprintf(&desc_id_field, " %s", desc_id); - - event_hs_descriptor_receive_end("FAILED", onion_address, desc_id_field, - REND_NO_AUTH, hsdir_id_digest, reason); - tor_free(desc_id_field); -} - -/** Send HS_DESC_CONTENT event after completion of a successful fetch - * from hs directory. If hsdir_id_digest is NULL, it is replaced - * by "UNKNOWN". If content is NULL, it is replaced by an empty - * string. The onion_address or desc_id set to NULL will - * not trigger the control event. */ -void -control_event_hs_descriptor_content(const char *onion_address, - const char *desc_id, - const char *hsdir_id_digest, - const char *content) -{ - static const char *event_name = "HS_DESC_CONTENT"; - char *esc_content = NULL; - - if (!onion_address || !desc_id) { - log_warn(LD_BUG, "Called with onion_address==%p, desc_id==%p, ", - onion_address, desc_id); - return; - } - - if (content == NULL) { - /* Point it to empty content so it can still be escaped. */ - content = ""; - } - write_escaped_data(content, strlen(content), &esc_content); - - send_control_event(EVENT_HS_DESC_CONTENT, - "650+%s %s %s %s\r\n%s650 OK\r\n", - event_name, - rend_hsaddress_str_or_unknown(onion_address), - desc_id, - hsdir_id_digest ? - node_describe_longname_by_id(hsdir_id_digest) : - "UNKNOWN", - esc_content); - tor_free(esc_content); -} - -/** Send HS_DESC event to inform controller upload of hidden service - * descriptor identified by id_digest failed. If reason - * is not NULL, add it to REASON= field. - */ -void -control_event_hs_descriptor_upload_failed(const char *id_digest, - const char *onion_address, - const char *reason) -{ - if (BUG(!id_digest)) { - return; - } - control_event_hs_descriptor_upload_end("FAILED", onion_address, - id_digest, reason); -} - /** Free any leftover allocated memory of the control.c subsystem. */ void control_free_all(void) { - smartlist_t *queued_events = NULL; - - stats_prev_n_read = stats_prev_n_written = 0; - - if (authentication_cookie) /* Free the auth cookie */ - tor_free(authentication_cookie); - if (detached_onion_services) { /* Free the detached onion services */ - SMARTLIST_FOREACH(detached_onion_services, char *, cp, tor_free(cp)); - smartlist_free(detached_onion_services); - } - - if (queued_control_events_lock) { - tor_mutex_acquire(queued_control_events_lock); - flush_queued_event_pending = 0; - queued_events = queued_control_events; - queued_control_events = NULL; - tor_mutex_release(queued_control_events_lock); - } - if (queued_events) { - SMARTLIST_FOREACH(queued_events, queued_event_t *, ev, - queued_event_free(ev)); - smartlist_free(queued_events); - } - if (flush_queued_events_event) { - mainloop_event_free(flush_queued_events_event); - flush_queued_events_event = NULL; - } + control_auth_free_all(); + control_events_free_all(); + control_cmd_free_all(); control_event_bootstrap_reset(); - authentication_cookie_is_set = 0; - global_event_mask = 0; - disable_log_messages = 0; -} - -#ifdef TOR_UNIT_TESTS -/* For testing: change the value of global_event_mask */ -void -control_testing_set_global_event_mask(uint64_t mask) -{ - global_event_mask = mask; } -#endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/feature/control/control.h b/src/feature/control/control.h index b2ab4c1997..8d3595d2ed 100644 --- a/src/feature/control/control.h +++ b/src/feature/control/control.h @@ -12,84 +12,6 @@ #ifndef TOR_CONTROL_H #define TOR_CONTROL_H -#include "core/or/ocirc_event.h" - -/** Used to indicate the type of a CIRC_MINOR event passed to the controller. - * The various types are defined in control-spec.txt . */ -typedef enum circuit_status_minor_event_t { - CIRC_MINOR_EVENT_PURPOSE_CHANGED, - CIRC_MINOR_EVENT_CANNIBALIZED, -} circuit_status_minor_event_t; - -#include "core/or/orconn_event.h" - -/** Used to indicate the type of a stream event passed to the controller. - * The various types are defined in control-spec.txt */ -typedef enum stream_status_event_t { - STREAM_EVENT_SENT_CONNECT = 0, - STREAM_EVENT_SENT_RESOLVE = 1, - STREAM_EVENT_SUCCEEDED = 2, - STREAM_EVENT_FAILED = 3, - STREAM_EVENT_CLOSED = 4, - STREAM_EVENT_NEW = 5, - STREAM_EVENT_NEW_RESOLVE = 6, - STREAM_EVENT_FAILED_RETRIABLE = 7, - STREAM_EVENT_REMAP = 8 -} stream_status_event_t; - -/** Used to indicate the type of a buildtime event */ -typedef enum buildtimeout_set_event_t { - BUILDTIMEOUT_SET_EVENT_COMPUTED = 0, - BUILDTIMEOUT_SET_EVENT_RESET = 1, - BUILDTIMEOUT_SET_EVENT_SUSPENDED = 2, - BUILDTIMEOUT_SET_EVENT_DISCARD = 3, - BUILDTIMEOUT_SET_EVENT_RESUME = 4 -} buildtimeout_set_event_t; - -/** Enum describing various stages of bootstrapping, for use with controller - * bootstrap status events. The values range from 0 to 100. */ -typedef enum { - BOOTSTRAP_STATUS_UNDEF=-1, - BOOTSTRAP_STATUS_STARTING=0, - - /* Initial connection to any relay */ - - BOOTSTRAP_STATUS_CONN_PT=1, - BOOTSTRAP_STATUS_CONN_DONE_PT=2, - BOOTSTRAP_STATUS_CONN_PROXY=3, - BOOTSTRAP_STATUS_CONN_DONE_PROXY=4, - BOOTSTRAP_STATUS_CONN=5, - BOOTSTRAP_STATUS_CONN_DONE=10, - BOOTSTRAP_STATUS_HANDSHAKE=14, - BOOTSTRAP_STATUS_HANDSHAKE_DONE=15, - - /* Loading directory info */ - - BOOTSTRAP_STATUS_ONEHOP_CREATE=20, - BOOTSTRAP_STATUS_REQUESTING_STATUS=25, - BOOTSTRAP_STATUS_LOADING_STATUS=30, - BOOTSTRAP_STATUS_LOADING_KEYS=40, - BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS=45, - BOOTSTRAP_STATUS_LOADING_DESCRIPTORS=50, - BOOTSTRAP_STATUS_ENOUGH_DIRINFO=75, - - /* Connecting to a relay for AP circuits */ - - BOOTSTRAP_STATUS_AP_CONN_PT=76, - BOOTSTRAP_STATUS_AP_CONN_DONE_PT=77, - BOOTSTRAP_STATUS_AP_CONN_PROXY=78, - BOOTSTRAP_STATUS_AP_CONN_DONE_PROXY=79, - BOOTSTRAP_STATUS_AP_CONN=80, - BOOTSTRAP_STATUS_AP_CONN_DONE=85, - BOOTSTRAP_STATUS_AP_HANDSHAKE=89, - BOOTSTRAP_STATUS_AP_HANDSHAKE_DONE=90, - - /* Creating AP circuits */ - - BOOTSTRAP_STATUS_CIRCUIT_CREATE=95, - BOOTSTRAP_STATUS_DONE=100 -} bootstrap_status_t; - control_connection_t *TO_CONTROL_CONN(connection_t *); #define CONTROL_CONN_STATE_MIN_ 1 @@ -100,18 +22,6 @@ control_connection_t *TO_CONTROL_CONN(connection_t *); #define CONTROL_CONN_STATE_NEEDAUTH 2 #define CONTROL_CONN_STATE_MAX_ 2 -/** Reason for remapping an AP connection's address: we have a cached - * answer. */ -#define REMAP_STREAM_SOURCE_CACHE 1 -/** Reason for remapping an AP connection's address: the exit node told us an - * answer. */ -#define REMAP_STREAM_SOURCE_EXIT 2 - -void control_initialize_event_queue(void); - -void control_update_global_event_mask(void); -void control_adjust_event_log_severity(void); - void control_ports_write_to_file(void); /** Log information about the connection conn, protecting it as with @@ -132,300 +42,28 @@ void connection_control_closed(control_connection_t *conn); int connection_control_process_inbuf(control_connection_t *conn); -#define EVENT_NS 0x000F -int control_event_is_interesting(int event); - -void control_per_second_events(void); -int control_any_per_second_event_enabled(void); - -int control_event_circuit_status(origin_circuit_t *circ, - circuit_status_event_t e, int reason); -int control_event_circuit_purpose_changed(origin_circuit_t *circ, - int old_purpose); -int control_event_circuit_cannibalized(origin_circuit_t *circ, - int old_purpose, - const struct timeval *old_tv_created); -int control_event_stream_status(entry_connection_t *conn, - stream_status_event_t e, - int reason); -int control_event_or_conn_status(or_connection_t *conn, - or_conn_status_event_t e, int reason); -int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written); -int control_event_stream_bandwidth(edge_connection_t *edge_conn); -int control_event_stream_bandwidth_used(void); -int control_event_circ_bandwidth_used(void); -int control_event_circ_bandwidth_used_for_circ(origin_circuit_t *ocirc); -int control_event_conn_bandwidth(connection_t *conn); -int control_event_conn_bandwidth_used(void); -int control_event_circuit_cell_stats(void); -void control_event_logmsg(int severity, uint32_t domain, const char *msg); -void control_event_logmsg_pending(void); -int control_event_descriptors_changed(smartlist_t *routers); -int control_event_address_mapped(const char *from, const char *to, - time_t expires, const char *error, - const int cached); -int control_event_my_descriptor_changed(void); -int control_event_network_liveness_update(int liveness); -int control_event_networkstatus_changed(smartlist_t *statuses); - -int control_event_newconsensus(const networkstatus_t *consensus); -int control_event_networkstatus_changed_single(const routerstatus_t *rs); -int control_event_general_status(int severity, const char *format, ...) - CHECK_PRINTF(2,3); -int control_event_client_status(int severity, const char *format, ...) - CHECK_PRINTF(2,3); -int control_event_server_status(int severity, const char *format, ...) - CHECK_PRINTF(2,3); - -int control_event_general_error(const char *format, ...) - CHECK_PRINTF(1,2); -int control_event_client_error(const char *format, ...) - CHECK_PRINTF(1,2); -int control_event_server_error(const char *format, ...) - CHECK_PRINTF(1,2); - -int control_event_guard(const char *nickname, const char *digest, - const char *status); -int control_event_conf_changed(const smartlist_t *elements); -int control_event_buildtimeout_set(buildtimeout_set_event_t type, - const char *args); -int control_event_signal(uintptr_t signal); - -int init_control_cookie_authentication(int enabled); -char *get_controller_cookie_file_name(void); -struct config_line_t; -smartlist_t *decode_hashed_passwords(struct config_line_t *passwords); void disable_control_logging(void); void enable_control_logging(void); void monitor_owning_controller_process(const char *process_spec); -void control_event_bootstrap(bootstrap_status_t status, int progress); -MOCK_DECL(void, control_event_bootstrap_prob_or,(const char *warn, - int reason, - or_connection_t *or_conn)); -void control_event_boot_dir(bootstrap_status_t status, int progress); -void control_event_boot_first_orconn(void); -void control_event_bootstrap_problem(const char *warn, const char *reason, - const connection_t *conn, int dowarn); -char *control_event_boot_last_msg(void); -void control_event_bootstrap_reset(void); - -void control_event_clients_seen(const char *controller_str); -void control_event_transport_launched(const char *mode, - const char *transport_name, - tor_addr_t *addr, uint16_t port); -void control_event_pt_log(const char *log); -void control_event_pt_status(const char *status); const char *rend_auth_type_to_string(rend_auth_type_t auth_type); -MOCK_DECL(const char *, node_describe_longname_by_id,(const char *id_digest)); -void control_event_hs_descriptor_requested(const char *onion_address, - rend_auth_type_t auth_type, - const char *id_digest, - const char *desc_id, - const char *hsdir_index); -void control_event_hs_descriptor_created(const char *onion_address, - const char *desc_id, - int replica); -void control_event_hs_descriptor_upload(const char *onion_address, - const char *desc_id, - const char *hs_dir, - const char *hsdir_index); -void control_event_hs_descriptor_upload_end(const char *action, - const char *onion_address, - const char *hs_dir, - const char *reason); -void control_event_hs_descriptor_uploaded(const char *hs_dir, - const char *onion_address); -/* Hidden service v2 HS_DESC specific. */ -void control_event_hsv2_descriptor_failed(const rend_data_t *rend_data, - const char *id_digest, - const char *reason); -void control_event_hsv2_descriptor_received(const char *onion_address, - const rend_data_t *rend_data, - const char *id_digest); -/* Hidden service v3 HS_DESC specific. */ -void control_event_hsv3_descriptor_failed(const char *onion_address, - const char *desc_id, - const char *hsdir_id_digest, - const char *reason); -void control_event_hsv3_descriptor_received(const char *onion_address, - const char *desc_id, - const char *hsdir_id_digest); -void control_event_hs_descriptor_upload_failed(const char *hs_dir, - const char *onion_address, - const char *reason); -void control_event_hs_descriptor_content(const char *onion_address, - const char *desc_id, - const char *hsdir_fp, - const char *content); void control_free_all(void); -#ifdef CONTROL_PRIVATE -#include "lib/crypt_ops/crypto_ed25519.h" - -/* Recognized asynchronous event types. It's okay to expand this list - * because it is used both as a list of v0 event types, and as indices - * into the bitfield to determine which controllers want which events. - */ -/* This bitfield has no event zero 0x0000 */ -#define EVENT_MIN_ 0x0001 -#define EVENT_CIRCUIT_STATUS 0x0001 -#define EVENT_STREAM_STATUS 0x0002 -#define EVENT_OR_CONN_STATUS 0x0003 -#define EVENT_BANDWIDTH_USED 0x0004 -#define EVENT_CIRCUIT_STATUS_MINOR 0x0005 -#define EVENT_NEW_DESC 0x0006 -#define EVENT_DEBUG_MSG 0x0007 -#define EVENT_INFO_MSG 0x0008 -#define EVENT_NOTICE_MSG 0x0009 -#define EVENT_WARN_MSG 0x000A -#define EVENT_ERR_MSG 0x000B -#define EVENT_ADDRMAP 0x000C -/* There was an AUTHDIR_NEWDESCS event, but it no longer exists. We - can reclaim 0x000D. */ -#define EVENT_DESCCHANGED 0x000E -/* Exposed above */ -// #define EVENT_NS 0x000F -#define EVENT_STATUS_CLIENT 0x0010 -#define EVENT_STATUS_SERVER 0x0011 -#define EVENT_STATUS_GENERAL 0x0012 -#define EVENT_GUARD 0x0013 -#define EVENT_STREAM_BANDWIDTH_USED 0x0014 -#define EVENT_CLIENTS_SEEN 0x0015 -#define EVENT_NEWCONSENSUS 0x0016 -#define EVENT_BUILDTIMEOUT_SET 0x0017 -#define EVENT_GOT_SIGNAL 0x0018 -#define EVENT_CONF_CHANGED 0x0019 -#define EVENT_CONN_BW 0x001A -#define EVENT_CELL_STATS 0x001B -/* UNUSED : 0x001C */ -#define EVENT_CIRC_BANDWIDTH_USED 0x001D -#define EVENT_TRANSPORT_LAUNCHED 0x0020 -#define EVENT_HS_DESC 0x0021 -#define EVENT_HS_DESC_CONTENT 0x0022 -#define EVENT_NETWORK_LIVENESS 0x0023 -#define EVENT_PT_LOG 0x0024 -#define EVENT_PT_STATUS 0x0025 -#define EVENT_MAX_ 0x0025 - -/* sizeof(control_connection_t.event_mask) in bits, currently a uint64_t */ -#define EVENT_CAPACITY_ 0x0040 - -/* If EVENT_MAX_ ever hits 0x0040, we need to make the mask into a - * different structure, as it can only handle a maximum left shift of 1<<63. */ +#ifdef CONTROL_MODULE_PRIVATE +struct signal_name_t { + int sig; + const char *signal_name; +}; +extern const struct signal_name_t signal_table[]; +int get_cached_network_liveness(void); +void set_cached_network_liveness(int liveness); +#endif /* defined(CONTROL_MODULE_PRIVATE) */ -#if EVENT_MAX_ >= EVENT_CAPACITY_ -#error control_connection_t.event_mask has an event greater than its capacity +#ifdef CONTROL_PRIVATE +STATIC char *control_split_incoming_command(char *incoming_cmd, + size_t *data_len, + char **current_cmd_out); #endif -#define EVENT_MASK_(e) (((uint64_t)1)<<(e)) - -#define EVENT_MASK_NONE_ ((uint64_t)0x0) - -#define EVENT_MASK_ABOVE_MIN_ ((~((uint64_t)0x0)) << EVENT_MIN_) -#define EVENT_MASK_BELOW_MAX_ ((~((uint64_t)0x0)) \ - >> (EVENT_CAPACITY_ - EVENT_MAX_ \ - - EVENT_MIN_)) - -#define EVENT_MASK_ALL_ (EVENT_MASK_ABOVE_MIN_ \ - & EVENT_MASK_BELOW_MAX_) - -/* Used only by control.c and test.c */ -STATIC size_t write_escaped_data(const char *data, size_t len, char **out); -STATIC size_t read_escaped_data(const char *data, size_t len, char **out); - -#ifdef TOR_UNIT_TESTS -MOCK_DECL(STATIC void, - send_control_event_string,(uint16_t event, const char *msg)); - -MOCK_DECL(STATIC void, - queue_control_event_string,(uint16_t event, char *msg)); - -void control_testing_set_global_event_mask(uint64_t mask); -#endif /* defined(TOR_UNIT_TESTS) */ - -/** Helper structure: temporarily stores cell statistics for a circuit. */ -typedef struct cell_stats_t { - /** Number of cells added in app-ward direction by command. */ - uint64_t added_cells_appward[CELL_COMMAND_MAX_ + 1]; - /** Number of cells added in exit-ward direction by command. */ - uint64_t added_cells_exitward[CELL_COMMAND_MAX_ + 1]; - /** Number of cells removed in app-ward direction by command. */ - uint64_t removed_cells_appward[CELL_COMMAND_MAX_ + 1]; - /** Number of cells removed in exit-ward direction by command. */ - uint64_t removed_cells_exitward[CELL_COMMAND_MAX_ + 1]; - /** Total waiting time of cells in app-ward direction by command. */ - uint64_t total_time_appward[CELL_COMMAND_MAX_ + 1]; - /** Total waiting time of cells in exit-ward direction by command. */ - uint64_t total_time_exitward[CELL_COMMAND_MAX_ + 1]; -} cell_stats_t; -void sum_up_cell_stats_by_command(circuit_t *circ, - cell_stats_t *cell_stats); -void append_cell_stats_by_command(smartlist_t *event_parts, - const char *key, - const uint64_t *include_if_non_zero, - const uint64_t *number_to_include); -void format_cell_stats(char **event_string, circuit_t *circ, - cell_stats_t *cell_stats); -STATIC char *get_bw_samples(void); - -/* ADD_ONION secret key to create an ephemeral service. The command supports - * multiple versions so this union stores the key and passes it to the HS - * subsystem depending on the requested version. */ -typedef union add_onion_secret_key_t { - /* Hidden service v2 secret key. */ - crypto_pk_t *v2; - /* Hidden service v3 secret key. */ - ed25519_secret_key_t *v3; -} add_onion_secret_key_t; - -STATIC int add_onion_helper_keyarg(const char *arg, int discard_pk, - const char **key_new_alg_out, - char **key_new_blob_out, - add_onion_secret_key_t *decoded_key, - int *hs_version, char **err_msg_out); - -STATIC rend_authorized_client_t * -add_onion_helper_clientauth(const char *arg, int *created, char **err_msg_out); - -STATIC int getinfo_helper_onions( - control_connection_t *control_conn, - const char *question, - char **answer, - const char **errmsg); -STATIC void getinfo_helper_downloads_networkstatus( - const char *flavor, - download_status_t **dl_to_emit, - const char **errmsg); -STATIC void getinfo_helper_downloads_cert( - const char *fp_sk_req, - download_status_t **dl_to_emit, - smartlist_t **digest_list, - const char **errmsg); -STATIC void getinfo_helper_downloads_desc( - const char *desc_req, - download_status_t **dl_to_emit, - smartlist_t **digest_list, - const char **errmsg); -STATIC void getinfo_helper_downloads_bridge( - const char *bridge_req, - download_status_t **dl_to_emit, - smartlist_t **digest_list, - const char **errmsg); -STATIC int getinfo_helper_downloads( - control_connection_t *control_conn, - const char *question, char **answer, - const char **errmsg); -STATIC int getinfo_helper_dir( - control_connection_t *control_conn, - const char *question, char **answer, - const char **errmsg); -STATIC int getinfo_helper_current_time( - control_connection_t *control_conn, - const char *question, char **answer, - const char **errmsg); - -#endif /* defined(CONTROL_PRIVATE) */ - #endif /* !defined(TOR_CONTROL_H) */ diff --git a/src/feature/control/control_auth.c b/src/feature/control/control_auth.c new file mode 100644 index 0000000000..49d4d415c6 --- /dev/null +++ b/src/feature/control/control_auth.c @@ -0,0 +1,445 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_auth.c + * \brief Authentication for Tor's control-socket interface. + **/ + +#include "core/or/or.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "feature/control/control.h" +#include "feature/control/control_cmd.h" +#include "feature/control/control_auth.h" +#include "feature/control/control_cmd_args_st.h" +#include "feature/control/control_connection_st.h" +#include "feature/control/control_proto.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/encoding/confline.h" +#include "lib/encoding/kvline.h" +#include "lib/encoding/qstring.h" + +#include "lib/crypt_ops/crypto_s2k.h" + +/** If we're using cookie-type authentication, how long should our cookies be? + */ +#define AUTHENTICATION_COOKIE_LEN 32 + +/** If true, we've set authentication_cookie to a secret code and + * stored it to disk. */ +static int authentication_cookie_is_set = 0; +/** If authentication_cookie_is_set, a secret cookie that we've stored to disk + * and which we're using to authenticate controllers. (If the controller can + * read it off disk, it has permission to connect.) */ +static uint8_t *authentication_cookie = NULL; + +#define SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT \ + "Tor safe cookie authentication server-to-controller hash" +#define SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT \ + "Tor safe cookie authentication controller-to-server hash" +#define SAFECOOKIE_SERVER_NONCE_LEN DIGEST256_LEN + +/** Helper: Return a newly allocated string containing a path to the + * file where we store our authentication cookie. */ +char * +get_controller_cookie_file_name(void) +{ + const or_options_t *options = get_options(); + if (options->CookieAuthFile && strlen(options->CookieAuthFile)) { + return tor_strdup(options->CookieAuthFile); + } else { + return get_datadir_fname("control_auth_cookie"); + } +} + +/* Initialize the cookie-based authentication system of the + * ControlPort. If enabled is 0, then disable the cookie + * authentication system. */ +int +init_control_cookie_authentication(int enabled) +{ + char *fname = NULL; + int retval; + + if (!enabled) { + authentication_cookie_is_set = 0; + return 0; + } + + fname = get_controller_cookie_file_name(); + retval = init_cookie_authentication(fname, "", /* no header */ + AUTHENTICATION_COOKIE_LEN, + get_options()->CookieAuthFileGroupReadable, + &authentication_cookie, + &authentication_cookie_is_set); + tor_free(fname); + return retval; +} + +/** Decode the hashed, base64'd passwords stored in passwords. + * Return a smartlist of acceptable passwords (unterminated strings of + * length S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) on success, or NULL on + * failure. + */ +smartlist_t * +decode_hashed_passwords(config_line_t *passwords) +{ + char decoded[64]; + config_line_t *cl; + smartlist_t *sl = smartlist_new(); + + tor_assert(passwords); + + for (cl = passwords; cl; cl = cl->next) { + const char *hashed = cl->value; + + if (!strcmpstart(hashed, "16:")) { + if (base16_decode(decoded, sizeof(decoded), hashed+3, strlen(hashed+3)) + != S2K_RFC2440_SPECIFIER_LEN + DIGEST_LEN + || strlen(hashed+3) != (S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN)*2) { + goto err; + } + } else { + if (base64_decode(decoded, sizeof(decoded), hashed, strlen(hashed)) + != S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) { + goto err; + } + } + smartlist_add(sl, + tor_memdup(decoded, S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN)); + } + + return sl; + + err: + SMARTLIST_FOREACH(sl, char*, cp, tor_free(cp)); + smartlist_free(sl); + return NULL; +} + +const control_cmd_syntax_t authchallenge_syntax = { + .min_args = 1, + .max_args = 1, + .accept_keywords=true, + .kvline_flags=KV_OMIT_KEYS|KV_QUOTED_QSTRING, + .store_raw_body=true +}; + +/** Called when we get an AUTHCHALLENGE command. */ +int +handle_control_authchallenge(control_connection_t *conn, + const control_cmd_args_t *args) +{ + char *client_nonce; + size_t client_nonce_len; + char server_hash[DIGEST256_LEN]; + char server_hash_encoded[HEX_DIGEST256_LEN+1]; + char server_nonce[SAFECOOKIE_SERVER_NONCE_LEN]; + char server_nonce_encoded[(2*SAFECOOKIE_SERVER_NONCE_LEN) + 1]; + + if (strcasecmp(smartlist_get(args->args, 0), "SAFECOOKIE")) { + control_write_endreply(conn, 513, + "AUTHCHALLENGE only supports SAFECOOKIE " + "authentication"); + goto fail; + } + if (!authentication_cookie_is_set) { + control_write_endreply(conn, 515, "Cookie authentication is disabled"); + goto fail; + } + if (args->kwargs == NULL || args->kwargs->next != NULL) { + /* connection_write_str_to_buf("512 AUTHCHALLENGE requires exactly " + "2 arguments.\r\n", conn); + */ + control_printf_endreply(conn, 512, + "AUTHCHALLENGE dislikes argument list %s", + escaped(args->raw_body)); + goto fail; + } + if (strcmp(args->kwargs->key, "")) { + control_write_endreply(conn, 512, + "AUTHCHALLENGE does not accept keyword " + "arguments."); + goto fail; + } + + bool contains_quote = strchr(args->raw_body, '\"'); + if (contains_quote) { + /* The nonce was quoted */ + client_nonce = tor_strdup(args->kwargs->value); + client_nonce_len = strlen(client_nonce); + } else { + /* The nonce was should be in hex. */ + const char *hex_nonce = args->kwargs->value; + client_nonce_len = strlen(hex_nonce) / 2; + client_nonce = tor_malloc(client_nonce_len); + if (base16_decode(client_nonce, client_nonce_len, hex_nonce, + strlen(hex_nonce)) != (int)client_nonce_len) { + control_write_endreply(conn, 513, "Invalid base16 client nonce"); + tor_free(client_nonce); + goto fail; + } + } + + crypto_rand(server_nonce, SAFECOOKIE_SERVER_NONCE_LEN); + + /* Now compute and send the server-to-controller response, and the + * server's nonce. */ + tor_assert(authentication_cookie != NULL); + + { + size_t tmp_len = (AUTHENTICATION_COOKIE_LEN + + client_nonce_len + + SAFECOOKIE_SERVER_NONCE_LEN); + char *tmp = tor_malloc_zero(tmp_len); + char *client_hash = tor_malloc_zero(DIGEST256_LEN); + memcpy(tmp, authentication_cookie, AUTHENTICATION_COOKIE_LEN); + memcpy(tmp + AUTHENTICATION_COOKIE_LEN, client_nonce, client_nonce_len); + memcpy(tmp + AUTHENTICATION_COOKIE_LEN + client_nonce_len, + server_nonce, SAFECOOKIE_SERVER_NONCE_LEN); + + crypto_hmac_sha256(server_hash, + SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT, + strlen(SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT), + tmp, + tmp_len); + + crypto_hmac_sha256(client_hash, + SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT, + strlen(SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT), + tmp, + tmp_len); + + conn->safecookie_client_hash = client_hash; + + tor_free(tmp); + } + + base16_encode(server_hash_encoded, sizeof(server_hash_encoded), + server_hash, sizeof(server_hash)); + base16_encode(server_nonce_encoded, sizeof(server_nonce_encoded), + server_nonce, sizeof(server_nonce)); + + control_printf_endreply(conn, 250, + "AUTHCHALLENGE SERVERHASH=%s SERVERNONCE=%s", + server_hash_encoded, + server_nonce_encoded); + + tor_free(client_nonce); + return 0; + fail: + connection_mark_for_close(TO_CONN(conn)); + return -1; +} + +const control_cmd_syntax_t authenticate_syntax = { + .max_args = 0, + .accept_keywords=true, + .kvline_flags=KV_OMIT_KEYS|KV_QUOTED_QSTRING, + .store_raw_body=true +}; + +/** Called when we get an AUTHENTICATE message. Check whether the + * authentication is valid, and if so, update the connection's state to + * OPEN. Reply with DONE or ERROR. + */ +int +handle_control_authenticate(control_connection_t *conn, + const control_cmd_args_t *args) +{ + bool used_quoted_string = false; + const or_options_t *options = get_options(); + const char *errstr = "Unknown error"; + char *password; + size_t password_len; + int bad_cookie=0, bad_password=0; + smartlist_t *sl = NULL; + + if (args->kwargs == NULL) { + password = tor_strdup(""); + password_len = 0; + } else if (args->kwargs->next) { + control_write_endreply(conn, 512, "Too many arguments to AUTHENTICATE."); + connection_mark_for_close(TO_CONN(conn)); + return 0; + } else if (strcmp(args->kwargs->key, "")) { + control_write_endreply(conn, 512, + "AUTHENTICATE does not accept keyword arguments."); + connection_mark_for_close(TO_CONN(conn)); + return 0; + } else if (strchr(args->raw_body, '\"')) { + used_quoted_string = true; + password = tor_strdup(args->kwargs->value); + password_len = strlen(password); + } else { + const char *hex_passwd = args->kwargs->value; + password_len = strlen(hex_passwd) / 2; + password = tor_malloc(password_len+1); + if (base16_decode(password, password_len+1, hex_passwd, strlen(hex_passwd)) + != (int) password_len) { + control_write_endreply(conn, 551, + "Invalid hexadecimal encoding. Maybe you tried a plain text " + "password? If so, the standard requires that you put it in " + "double quotes."); + connection_mark_for_close(TO_CONN(conn)); + tor_free(password); + return 0; + } + } + + if (conn->safecookie_client_hash != NULL) { + /* The controller has chosen safe cookie authentication; the only + * acceptable authentication value is the controller-to-server + * response. */ + + tor_assert(authentication_cookie_is_set); + + if (password_len != DIGEST256_LEN) { + log_warn(LD_CONTROL, + "Got safe cookie authentication response with wrong length " + "(%d)", (int)password_len); + errstr = "Wrong length for safe cookie response."; + goto err; + } + + if (tor_memneq(conn->safecookie_client_hash, password, DIGEST256_LEN)) { + log_warn(LD_CONTROL, + "Got incorrect safe cookie authentication response"); + errstr = "Safe cookie response did not match expected value."; + goto err; + } + + tor_free(conn->safecookie_client_hash); + goto ok; + } + + if (!options->CookieAuthentication && !options->HashedControlPassword && + !options->HashedControlSessionPassword) { + /* if Tor doesn't demand any stronger authentication, then + * the controller can get in with anything. */ + goto ok; + } + + if (options->CookieAuthentication) { + int also_password = options->HashedControlPassword != NULL || + options->HashedControlSessionPassword != NULL; + if (password_len != AUTHENTICATION_COOKIE_LEN) { + if (!also_password) { + log_warn(LD_CONTROL, "Got authentication cookie with wrong length " + "(%d)", (int)password_len); + errstr = "Wrong length on authentication cookie."; + goto err; + } + bad_cookie = 1; + } else if (tor_memneq(authentication_cookie, password, password_len)) { + if (!also_password) { + log_warn(LD_CONTROL, "Got mismatched authentication cookie"); + errstr = "Authentication cookie did not match expected value."; + goto err; + } + bad_cookie = 1; + } else { + goto ok; + } + } + + if (options->HashedControlPassword || + options->HashedControlSessionPassword) { + int bad = 0; + smartlist_t *sl_tmp; + char received[DIGEST_LEN]; + int also_cookie = options->CookieAuthentication; + sl = smartlist_new(); + if (options->HashedControlPassword) { + sl_tmp = decode_hashed_passwords(options->HashedControlPassword); + if (!sl_tmp) + bad = 1; + else { + smartlist_add_all(sl, sl_tmp); + smartlist_free(sl_tmp); + } + } + if (options->HashedControlSessionPassword) { + sl_tmp = decode_hashed_passwords(options->HashedControlSessionPassword); + if (!sl_tmp) + bad = 1; + else { + smartlist_add_all(sl, sl_tmp); + smartlist_free(sl_tmp); + } + } + if (bad) { + if (!also_cookie) { + log_warn(LD_BUG, + "Couldn't decode HashedControlPassword: invalid base16"); + errstr="Couldn't decode HashedControlPassword value in configuration."; + goto err; + } + bad_password = 1; + SMARTLIST_FOREACH(sl, char *, str, tor_free(str)); + smartlist_free(sl); + sl = NULL; + } else { + SMARTLIST_FOREACH(sl, char *, expected, + { + secret_to_key_rfc2440(received,DIGEST_LEN, + password,password_len,expected); + if (tor_memeq(expected + S2K_RFC2440_SPECIFIER_LEN, + received, DIGEST_LEN)) + goto ok; + }); + SMARTLIST_FOREACH(sl, char *, str, tor_free(str)); + smartlist_free(sl); + sl = NULL; + + if (used_quoted_string) + errstr = "Password did not match HashedControlPassword value from " + "configuration"; + else + errstr = "Password did not match HashedControlPassword value from " + "configuration. Maybe you tried a plain text password? " + "If so, the standard requires that you put it in double quotes."; + bad_password = 1; + if (!also_cookie) + goto err; + } + } + + /** We only get here if both kinds of authentication failed. */ + tor_assert(bad_password && bad_cookie); + log_warn(LD_CONTROL, "Bad password or authentication cookie on controller."); + errstr = "Password did not match HashedControlPassword *or* authentication " + "cookie."; + + err: + tor_free(password); + control_printf_endreply(conn, 515, "Authentication failed: %s", errstr); + connection_mark_for_close(TO_CONN(conn)); + if (sl) { /* clean up */ + SMARTLIST_FOREACH(sl, char *, str, tor_free(str)); + smartlist_free(sl); + } + return 0; + ok: + log_info(LD_CONTROL, "Authenticated control connection ("TOR_SOCKET_T_FORMAT + ")", conn->base_.s); + send_control_done(conn); + conn->base_.state = CONTROL_CONN_STATE_OPEN; + tor_free(password); + if (sl) { /* clean up */ + SMARTLIST_FOREACH(sl, char *, str, tor_free(str)); + smartlist_free(sl); + } + return 0; +} + +void +control_auth_free_all(void) +{ + if (authentication_cookie) /* Free the auth cookie */ + tor_free(authentication_cookie); + authentication_cookie_is_set = 0; +} diff --git a/src/feature/control/control_auth.h b/src/feature/control/control_auth.h new file mode 100644 index 0000000000..246e18ccbc --- /dev/null +++ b/src/feature/control/control_auth.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_auth.h + * \brief Header file for control_auth.c. + **/ + +#ifndef TOR_CONTROL_AUTH_H +#define TOR_CONTROL_AUTH_H + +struct control_cmd_args_t; +struct control_cmd_syntax_t; + +int init_control_cookie_authentication(int enabled); +char *get_controller_cookie_file_name(void); +struct config_line_t; +smartlist_t *decode_hashed_passwords(struct config_line_t *passwords); + +int handle_control_authchallenge(control_connection_t *conn, + const struct control_cmd_args_t *args); +int handle_control_authenticate(control_connection_t *conn, + const struct control_cmd_args_t *args); +void control_auth_free_all(void); + +extern const struct control_cmd_syntax_t authchallenge_syntax; +extern const struct control_cmd_syntax_t authenticate_syntax; + +#endif /* !defined(TOR_CONTROL_AUTH_H) */ diff --git a/src/feature/control/control_bootstrap.c b/src/feature/control/control_bootstrap.c index 8153d7595a..098e24682e 100644 --- a/src/feature/control/control_bootstrap.c +++ b/src/feature/control/control_bootstrap.c @@ -14,7 +14,7 @@ #include "core/or/connection_st.h" #include "core/or/or_connection_st.h" #include "core/or/reasons.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/hibernate/hibernate.h" #include "lib/malloc/malloc.h" diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c new file mode 100644 index 0000000000..abb579bd43 --- /dev/null +++ b/src/feature/control/control_cmd.c @@ -0,0 +1,2408 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_cmd.c + * \brief Implement various commands for Tor's control-socket interface. + **/ + +#define CONTROL_MODULE_PRIVATE +#define CONTROL_CMD_PRIVATE +#define CONTROL_EVENTS_PRIVATE + +#include "core/or/or.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "app/main/main.h" +#include "core/mainloop/connection.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "core/or/connection_edge.h" +#include "feature/client/addressmap.h" +#include "feature/client/dnsserv.h" +#include "feature/client/entrynodes.h" +#include "feature/control/control.h" +#include "feature/control/control_auth.h" +#include "feature/control/control_cmd.h" +#include "feature/control/control_events.h" +#include "feature/control/control_getinfo.h" +#include "feature/control/control_proto.h" +#include "feature/hs/hs_control.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/routerinfo.h" +#include "feature/nodelist/routerlist.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendcommon.h" +#include "feature/rend/rendparse.h" +#include "feature/rend/rendservice.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/encoding/confline.h" +#include "lib/encoding/kvline.h" + +#include "core/or/cpath_build_state_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/socks_request_st.h" +#include "feature/control/control_cmd_args_st.h" +#include "feature/control/control_connection_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/rend/rend_authorized_client_st.h" +#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" +#include "feature/rend/rend_service_descriptor_st.h" + +static int control_setconf_helper(control_connection_t *conn, + const control_cmd_args_t *args, + int use_defaults); + +/** Yield true iff s is the state of a control_connection_t that has + * finished authentication and is accepting commands. */ +#define STATE_IS_OPEN(s) ((s) == CONTROL_CONN_STATE_OPEN) + +/** + * Release all storage held in args + **/ +void +control_cmd_args_free_(control_cmd_args_t *args) +{ + if (! args) + return; + + if (args->args) { + SMARTLIST_FOREACH(args->args, char *, c, tor_free(c)); + smartlist_free(args->args); + } + config_free_lines(args->kwargs); + tor_free(args->cmddata); + + tor_free(args); +} + +/** Erase all memory held in args. */ +void +control_cmd_args_wipe(control_cmd_args_t *args) +{ + if (!args) + return; + + if (args->args) { + SMARTLIST_FOREACH(args->args, char *, c, memwipe(c, 0, strlen(c))); + } + for (config_line_t *line = args->kwargs; line; line = line->next) { + memwipe(line->key, 0, strlen(line->key)); + memwipe(line->value, 0, strlen(line->value)); + } + if (args->cmddata) + memwipe(args->cmddata, 0, args->cmddata_len); +} + +/** + * Return true iff any element of the NULL-terminated array matches + * kwd. Case-insensitive. + **/ +static bool +string_array_contains_keyword(const char **array, const char *kwd) +{ + for (unsigned i = 0; array[i]; ++i) { + if (! strcasecmp(array[i], kwd)) + return true; + } + return false; +} + +/** Helper for argument parsing: check whether the keyword arguments just + * parsed in result were well-formed according to syntax. + * + * On success, return 0. On failure, return -1 and set *error_out + * to a newly allocated error string. + **/ +static int +kvline_check_keyword_args(const control_cmd_args_t *result, + const control_cmd_syntax_t *syntax, + char **error_out) +{ + if (result->kwargs == NULL) { + tor_asprintf(error_out, "Cannot parse keyword argument(s)"); + return -1; + } + + if (! syntax->allowed_keywords) { + /* All keywords are permitted. */ + return 0; + } + + /* Check for unpermitted arguments */ + const config_line_t *line; + for (line = result->kwargs; line; line = line->next) { + if (! string_array_contains_keyword(syntax->allowed_keywords, + line->key)) { + tor_asprintf(error_out, "Unrecognized keyword argument %s", + escaped(line->key)); + return -1; + } + } + + return 0; +} + +/** + * Helper: parse the arguments to a command according to syntax. On + * success, set *error_out to NULL and return a newly allocated + * control_cmd_args_t. On failure, set *error_out to newly allocated + * error string, and return NULL. + **/ +STATIC control_cmd_args_t * +control_cmd_parse_args(const char *command, + const control_cmd_syntax_t *syntax, + size_t body_len, + const char *body, + char **error_out) +{ + *error_out = NULL; + control_cmd_args_t *result = tor_malloc_zero(sizeof(control_cmd_args_t)); + const char *cmdline; + char *cmdline_alloc = NULL; + tor_assert(syntax->max_args < INT_MAX || syntax->max_args == UINT_MAX); + + result->command = command; + + if (syntax->store_raw_body) { + tor_assert(body[body_len] == 0); + result->raw_body = body; + } + + const char *eol = memchr(body, '\n', body_len); + if (syntax->want_cmddata) { + if (! eol || (eol+1) == body+body_len) { + *error_out = tor_strdup("Empty body"); + goto err; + } + cmdline_alloc = tor_memdup_nulterm(body, eol-body); + cmdline = cmdline_alloc; + ++eol; + result->cmddata_len = read_escaped_data(eol, (body+body_len)-eol, + &result->cmddata); + } else { + if (eol && (eol+1) != body+body_len) { + *error_out = tor_strdup("Unexpected body"); + goto err; + } + cmdline = body; + } + + result->args = smartlist_new(); + smartlist_split_string(result->args, cmdline, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, + (int)(syntax->max_args+1)); + size_t n_args = smartlist_len(result->args); + if (n_args < syntax->min_args) { + tor_asprintf(error_out, "Need at least %u argument(s)", + syntax->min_args); + goto err; + } else if (n_args > syntax->max_args && ! syntax->accept_keywords) { + tor_asprintf(error_out, "Cannot accept more than %u argument(s)", + syntax->max_args); + goto err; + } + + if (n_args > syntax->max_args) { + /* We have extra arguments after the positional arguments, and we didn't + treat them as an error, so they must count as keyword arguments: Either + K=V pairs, or flags, or both. */ + tor_assert(n_args == syntax->max_args + 1); + tor_assert(syntax->accept_keywords); + char *remainder = smartlist_pop_last(result->args); + result->kwargs = kvline_parse(remainder, syntax->kvline_flags); + tor_free(remainder); + if (kvline_check_keyword_args(result, syntax, error_out) < 0) { + goto err; + } + } + + tor_assert_nonfatal(*error_out == NULL); + goto done; + err: + tor_assert_nonfatal(*error_out != NULL); + control_cmd_args_free(result); + done: + tor_free(cmdline_alloc); + return result; +} + +/** + * Return true iff lines contains flags as a no-value + * (keyword-only) entry. + **/ +static bool +config_lines_contain_flag(const config_line_t *lines, const char *flag) +{ + const config_line_t *line = config_line_find_case(lines, flag); + return line && !strcmp(line->value, ""); +} + +static const control_cmd_syntax_t setconf_syntax = { + .max_args=0, + .accept_keywords=true, + .kvline_flags=KV_OMIT_VALS|KV_QUOTED, +}; + +/** Called when we receive a SETCONF message: parse the body and try + * to update our configuration. Reply with a DONE or ERROR message. + * Modifies the contents of body.*/ +static int +handle_control_setconf(control_connection_t *conn, + const control_cmd_args_t *args) +{ + return control_setconf_helper(conn, args, 0); +} + +static const control_cmd_syntax_t resetconf_syntax = { + .max_args=0, + .accept_keywords=true, + .kvline_flags=KV_OMIT_VALS|KV_QUOTED, +}; + +/** Called when we receive a RESETCONF message: parse the body and try + * to update our configuration. Reply with a DONE or ERROR message. + * Modifies the contents of body. */ +static int +handle_control_resetconf(control_connection_t *conn, + const control_cmd_args_t *args) +{ + return control_setconf_helper(conn, args, 1); +} + +static const control_cmd_syntax_t getconf_syntax = { + .max_args=UINT_MAX +}; + +/** Called when we receive a GETCONF message. Parse the request, and + * reply with a CONFVALUE or an ERROR message */ +static int +handle_control_getconf(control_connection_t *conn, + const control_cmd_args_t *args) +{ + 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); + } 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); + } + + while (answer) { + config_line_t *next; + smartlist_add_asprintf(answers, "250-%s=%s\r\n", + answer->key, answer->value); + + next = answer->next; + tor_free(answer->key); + tor_free(answer->value); + tor_free(answer); + answer = next; + } + } + } 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)); + } else { + send_control_done(conn); + } + + SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp)); + smartlist_free(answers); + smartlist_free(unrecognized); + + tor_free(msg); + + return 0; +} + +static const control_cmd_syntax_t loadconf_syntax = { + .want_cmddata = true +}; + +/** Called when we get a +LOADCONF message. */ +static int +handle_control_loadconf(control_connection_t *conn, + const control_cmd_args_t *args) +{ + setopt_err_t retval; + char *errstring = NULL; + + retval = options_init_from_string(NULL, args->cmddata, + CMD_RUN_TOR, NULL, &errstring); + + if (retval != SETOPT_OK) + log_warn(LD_CONTROL, + "Controller gave us config file that didn't validate: %s", + errstring); + +#define SEND_ERRMSG(code, msg) \ + control_printf_endreply(conn, code, msg "%s%s", \ + errstring ? ": " : "", \ + errstring ? errstring : "") + switch (retval) { + case SETOPT_ERR_PARSE: + SEND_ERRMSG(552, "Invalid config file"); + break; + case SETOPT_ERR_TRANSITION: + SEND_ERRMSG(553, "Transition not allowed"); + break; + case SETOPT_ERR_SETTING: + SEND_ERRMSG(553, "Unable to set option"); + break; + case SETOPT_ERR_MISC: + default: + SEND_ERRMSG(550, "Unable to load config"); + break; + case SETOPT_OK: + send_control_done(conn); + break; + } +#undef SEND_ERRMSG + tor_free(errstring); + return 0; +} + +static const control_cmd_syntax_t setevents_syntax = { + .max_args = UINT_MAX +}; + +/** Called when we get a SETEVENTS message: update conn->event_mask, + * and reply with DONE or ERROR. */ +static int +handle_control_setevents(control_connection_t *conn, + const control_cmd_args_t *args) +{ + int event_code; + event_mask_t event_mask = 0; + const smartlist_t *events = args->args; + + SMARTLIST_FOREACH_BEGIN(events, const char *, ev) + { + if (!strcasecmp(ev, "EXTENDED") || + !strcasecmp(ev, "AUTHDIR_NEWDESCS")) { + log_warn(LD_CONTROL, "The \"%s\" SETEVENTS argument is no longer " + "supported.", ev); + continue; + } else { + int i; + event_code = -1; + + for (i = 0; control_event_table[i].event_name != NULL; ++i) { + if (!strcasecmp(ev, control_event_table[i].event_name)) { + event_code = control_event_table[i].event_code; + break; + } + } + + if (event_code == -1) { + control_printf_endreply(conn, 552, "Unrecognized event \"%s\"", ev); + return 0; + } + } + event_mask |= (((event_mask_t)1) << event_code); + } + SMARTLIST_FOREACH_END(ev); + + conn->event_mask = event_mask; + + control_update_global_event_mask(); + send_control_done(conn); + return 0; +} + +static const control_cmd_syntax_t saveconf_syntax = { + .max_args = 0, + .accept_keywords = true, + .kvline_flags=KV_OMIT_VALS, +}; + +/** Called when we get a SAVECONF command. Try to flush the current options to + * disk, and report success or failure. */ +static int +handle_control_saveconf(control_connection_t *conn, + const control_cmd_args_t *args) +{ + bool force = config_lines_contain_flag(args->kwargs, "FORCE"); + const or_options_t *options = get_options(); + if ((!force && options->IncludeUsed) || options_save_current() < 0) { + control_write_endreply(conn, 551, + "Unable to write configuration to disk."); + } else { + send_control_done(conn); + } + return 0; +} + +static const control_cmd_syntax_t signal_syntax = { + .min_args = 1, + .max_args = 1, +}; + +/** Called when we get a SIGNAL command. React to the provided signal, and + * report success or failure. (If the signal results in a shutdown, success + * may not be reported.) */ +static int +handle_control_signal(control_connection_t *conn, + const control_cmd_args_t *args) +{ + int sig = -1; + int i; + + tor_assert(smartlist_len(args->args) == 1); + const char *s = smartlist_get(args->args, 0); + + for (i = 0; signal_table[i].signal_name != NULL; ++i) { + if (!strcasecmp(s, signal_table[i].signal_name)) { + sig = signal_table[i].sig; + break; + } + } + + if (sig < 0) + control_printf_endreply(conn, 552, "Unrecognized signal code \"%s\"", s); + if (sig < 0) + return 0; + + send_control_done(conn); + /* Flush the "done" first if the signal might make us shut down. */ + if (sig == SIGTERM || sig == SIGINT) + connection_flush(TO_CONN(conn)); + + activate_signal(sig); + + return 0; +} + +static const control_cmd_syntax_t takeownership_syntax = { + .max_args = UINT_MAX, // This should probably become zero. XXXXX +}; + +/** Called when we get a TAKEOWNERSHIP command. Mark this connection + * as an owning connection, so that we will exit if the connection + * closes. */ +static int +handle_control_takeownership(control_connection_t *conn, + const control_cmd_args_t *args) +{ + (void)args; + + conn->is_owning_control_connection = 1; + + log_info(LD_CONTROL, "Control connection %d has taken ownership of this " + "Tor instance.", + (int)(conn->base_.s)); + + send_control_done(conn); + return 0; +} + +static const control_cmd_syntax_t dropownership_syntax = { + .max_args = UINT_MAX, // This should probably become zero. XXXXX +}; + +/** Called when we get a DROPOWNERSHIP command. Mark this connection + * as a non-owning connection, so that we will not exit if the connection + * closes. */ +static int +handle_control_dropownership(control_connection_t *conn, + const control_cmd_args_t *args) +{ + (void)args; + + conn->is_owning_control_connection = 0; + + log_info(LD_CONTROL, "Control connection %d has dropped ownership of this " + "Tor instance.", + (int)(conn->base_.s)); + + send_control_done(conn); + return 0; +} + +/** Given a text circuit id, return the corresponding circuit. */ +static origin_circuit_t * +get_circ(const char *id) +{ + uint32_t n_id; + int ok; + n_id = (uint32_t) tor_parse_ulong(id, 10, 0, UINT32_MAX, &ok, NULL); + if (!ok) + return NULL; + return circuit_get_by_global_id(n_id); +} + +/** Given a text stream id, return the corresponding AP connection. */ +static entry_connection_t * +get_stream(const char *id) +{ + uint64_t n_id; + int ok; + connection_t *conn; + n_id = tor_parse_uint64(id, 10, 0, UINT64_MAX, &ok, NULL); + if (!ok) + return NULL; + conn = connection_get_by_global_id(n_id); + if (!conn || conn->type != CONN_TYPE_AP || conn->marked_for_close) + return NULL; + return TO_ENTRY_CONN(conn); +} + +/** Helper for setconf and resetconf. Acts like setconf, except + * it passes use_defaults on to options_trial_assign(). Modifies the + * contents of body. + */ +static int +control_setconf_helper(control_connection_t *conn, + const control_cmd_args_t *args, + int use_defaults) +{ + setopt_err_t opt_err; + char *errstring = NULL; + const unsigned flags = + CAL_CLEAR_FIRST | (use_defaults ? CAL_USE_DEFAULTS : 0); + + // We need a copy here, since confparse.c wants to canonicalize cases. + config_line_t *lines = config_lines_dup(args->kwargs); + + opt_err = options_trial_assign(lines, flags, &errstring); + { +#define SEND_ERRMSG(code, msg) \ + control_printf_endreply(conn, code, msg ": %s", errstring); + + switch (opt_err) { + case SETOPT_ERR_MISC: + SEND_ERRMSG(552, "Unrecognized option"); + break; + case SETOPT_ERR_PARSE: + SEND_ERRMSG(513, "Unacceptable option value"); + break; + case SETOPT_ERR_TRANSITION: + SEND_ERRMSG(553, "Transition not allowed"); + break; + case SETOPT_ERR_SETTING: + default: + SEND_ERRMSG(553, "Unable to set option"); + break; + case SETOPT_OK: + config_free_lines(lines); + send_control_done(conn); + return 0; + } +#undef SEND_ERRMSG + log_warn(LD_CONTROL, + "Controller gave us config lines that didn't validate: %s", + errstring); + config_free_lines(lines); + tor_free(errstring); + return 0; + } +} + +/** Return true iff addr is unusable as a mapaddress target because of + * containing funny characters. */ +static int +address_is_invalid_mapaddress_target(const char *addr) +{ + if (!strcmpstart(addr, "*.")) + return address_is_invalid_destination(addr+2, 1); + else + return address_is_invalid_destination(addr, 1); +} + +static const control_cmd_syntax_t mapaddress_syntax = { + .max_args=1, + .accept_keywords=true, +}; + +/** Called when we get a MAPADDRESS command; try to bind all listed addresses, + * and report success or failure. */ +static int +handle_control_mapaddress(control_connection_t *conn, + const control_cmd_args_t *args) +{ + smartlist_t *reply; + char *r; + size_t sz; + + reply = smartlist_new(); + const config_line_t *line; + for (line = args->kwargs; line; line = line->next) { + const char *from = line->key; + const char *to = line->value; + { + if (address_is_invalid_mapaddress_target(to)) { + smartlist_add_asprintf(reply, + "512-syntax error: invalid address '%s'", to); + log_warn(LD_CONTROL, + "Skipping invalid argument '%s' in MapAddress msg", to); + } else if (!strcmp(from, ".") || !strcmp(from, "0.0.0.0") || + !strcmp(from, "::")) { + const char type = + !strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME : + (!strcmp(from, "0.0.0.0") ? RESOLVED_TYPE_IPV4 : RESOLVED_TYPE_IPV6); + const char *address = addressmap_register_virtual_address( + type, tor_strdup(to)); + if (!address) { + smartlist_add_asprintf(reply, + "451-resource exhausted: skipping '%s=%s'", from,to); + log_warn(LD_CONTROL, + "Unable to allocate address for '%s' in MapAddress msg", + safe_str_client(to)); + } else { + smartlist_add_asprintf(reply, "250-%s=%s", address, to); + } + } else { + const char *msg; + if (addressmap_register_auto(from, to, 1, + ADDRMAPSRC_CONTROLLER, &msg) < 0) { + smartlist_add_asprintf(reply, + "512-syntax error: invalid address mapping " + " '%s=%s': %s", from, to, msg); + log_warn(LD_CONTROL, + "Skipping invalid argument '%s=%s' in MapAddress msg: %s", + from, to, msg); + } else { + smartlist_add_asprintf(reply, "250-%s=%s", from, to); + } + } + } + } + + if (smartlist_len(reply)) { + ((char*)smartlist_get(reply,smartlist_len(reply)-1))[3] = ' '; + r = smartlist_join_strings(reply, "\r\n", 1, &sz); + connection_buf_add(r, sz, TO_CONN(conn)); + tor_free(r); + } else { + const char *response = + "512 syntax error: not enough arguments to mapaddress.\r\n"; + connection_buf_add(response, strlen(response), TO_CONN(conn)); + } + + SMARTLIST_FOREACH(reply, char *, cp, tor_free(cp)); + smartlist_free(reply); + return 0; +} + +/** Given a string, convert it to a circuit purpose. */ +static uint8_t +circuit_purpose_from_string(const char *string) +{ + if (!strcasecmpstart(string, "purpose=")) + string += strlen("purpose="); + + if (!strcasecmp(string, "general")) + return CIRCUIT_PURPOSE_C_GENERAL; + else if (!strcasecmp(string, "controller")) + return CIRCUIT_PURPOSE_CONTROLLER; + else + return CIRCUIT_PURPOSE_UNKNOWN; +} + +static const control_cmd_syntax_t extendcircuit_syntax = { + .min_args=1, + .max_args=1, // see note in function + .accept_keywords=true, + .kvline_flags=KV_OMIT_VALS +}; + +/** Called when we get an EXTENDCIRCUIT message. Try to extend the listed + * circuit, and report success or failure. */ +static int +handle_control_extendcircuit(control_connection_t *conn, + const control_cmd_args_t *args) +{ + smartlist_t *router_nicknames=smartlist_new(), *nodes=NULL; + origin_circuit_t *circ = NULL; + uint8_t intended_purpose = CIRCUIT_PURPOSE_C_GENERAL; + const config_line_t *kwargs = args->kwargs; + const char *circ_id = smartlist_get(args->args, 0); + const char *path_str = NULL; + char *path_str_alloc = NULL; + + /* The syntax for this command is unfortunate. The second argument is + optional, and is a comma-separated list long-format fingerprints, which + can (historically!) contain an equals sign. + + Here we check the second argument to see if it's a path, and if so we + remove it from the kwargs list and put it in path_str. + */ + if (kwargs) { + const config_line_t *arg1 = kwargs; + if (!strcmp(arg1->value, "")) { + path_str = arg1->key; + kwargs = kwargs->next; + } else if (arg1->key[0] == '$') { + tor_asprintf(&path_str_alloc, "%s=%s", arg1->key, arg1->value); + path_str = path_str_alloc; + kwargs = kwargs->next; + } + } + + const config_line_t *purpose_line = config_line_find_case(kwargs, "PURPOSE"); + bool zero_circ = !strcmp("0", circ_id); + + if (purpose_line) { + intended_purpose = circuit_purpose_from_string(purpose_line->value); + if (intended_purpose == CIRCUIT_PURPOSE_UNKNOWN) { + control_printf_endreply(conn, 552, "Unknown purpose \"%s\"", + purpose_line->value); + goto done; + } + } + + if (zero_circ) { + if (!path_str) { + // "EXTENDCIRCUIT 0" with no path. + circ = circuit_launch(intended_purpose, CIRCLAUNCH_NEED_CAPACITY); + if (!circ) { + control_write_endreply(conn, 551, "Couldn't start circuit"); + } else { + control_printf_endreply(conn, 250, "EXTENDED %lu", + (unsigned long)circ->global_identifier); + } + goto done; + } + } + + if (!zero_circ && !(circ = get_circ(circ_id))) { + control_printf_endreply(conn, 552, "Unknown circuit \"%s\"", circ_id); + goto done; + } + + if (!path_str) { + control_write_endreply(conn, 512, "syntax error: path required."); + goto done; + } + + smartlist_split_string(router_nicknames, path_str, ",", 0, 0); + + nodes = smartlist_new(); + bool first_node = zero_circ; + SMARTLIST_FOREACH_BEGIN(router_nicknames, const char *, n) { + const node_t *node = node_get_by_nickname(n, 0); + if (!node) { + control_printf_endreply(conn, 552, "No such router \"%s\"", n); + goto done; + } + if (!node_has_preferred_descriptor(node, first_node)) { + control_printf_endreply(conn, 552, "No descriptor for \"%s\"", n); + goto done; + } + smartlist_add(nodes, (void*)node); + first_node = false; + } SMARTLIST_FOREACH_END(n); + + if (!smartlist_len(nodes)) { + control_write_endreply(conn, 512, "No router names provided"); + goto done; + } + + if (zero_circ) { + /* start a new circuit */ + circ = origin_circuit_init(intended_purpose, 0); + } + + /* now circ refers to something that is ready to be extended */ + first_node = zero_circ; + SMARTLIST_FOREACH(nodes, const node_t *, node, + { + extend_info_t *info = extend_info_from_node(node, first_node); + if (!info) { + tor_assert_nonfatal(first_node); + log_warn(LD_CONTROL, + "controller tried to connect to a node that lacks a suitable " + "descriptor, or which doesn't have any " + "addresses that are allowed by the firewall configuration; " + "circuit marked for closing."); + circuit_mark_for_close(TO_CIRCUIT(circ), -END_CIRC_REASON_CONNECTFAILED); + connection_write_str_to_buf("551 Couldn't start circuit\r\n", conn); + goto done; + } + circuit_append_new_exit(circ, info); + if (circ->build_state->desired_path_len > 1) { + circ->build_state->onehop_tunnel = 0; + } + extend_info_free(info); + first_node = 0; + }); + + /* now that we've populated the cpath, start extending */ + if (zero_circ) { + int err_reason = 0; + if ((err_reason = circuit_handle_first_hop(circ)) < 0) { + circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason); + control_write_endreply(conn, 551, "Couldn't start circuit"); + goto done; + } + } else { + if (circ->base_.state == CIRCUIT_STATE_OPEN || + circ->base_.state == CIRCUIT_STATE_GUARD_WAIT) { + int err_reason = 0; + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING); + if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) { + log_info(LD_CONTROL, + "send_next_onion_skin failed; circuit marked for closing."); + circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason); + control_write_endreply(conn, 551, "Couldn't send onion skin"); + goto done; + } + } + } + + control_printf_endreply(conn, 250, "EXTENDED %lu", + (unsigned long)circ->global_identifier); + if (zero_circ) /* send a 'launched' event, for completeness */ + circuit_event_status(circ, CIRC_EVENT_LAUNCHED, 0); + done: + SMARTLIST_FOREACH(router_nicknames, char *, n, tor_free(n)); + smartlist_free(router_nicknames); + smartlist_free(nodes); + tor_free(path_str_alloc); + return 0; +} + +static const control_cmd_syntax_t setcircuitpurpose_syntax = { + .max_args=1, + .accept_keywords=true, +}; + +/** Called when we get a SETCIRCUITPURPOSE message. If we can find the + * circuit and it's a valid purpose, change it. */ +static int +handle_control_setcircuitpurpose(control_connection_t *conn, + const control_cmd_args_t *args) +{ + origin_circuit_t *circ = NULL; + uint8_t new_purpose; + const char *circ_id = smartlist_get(args->args,0); + + if (!(circ = get_circ(circ_id))) { + control_printf_endreply(conn, 552, "Unknown circuit \"%s\"", circ_id); + goto done; + } + + { + const config_line_t *purp = config_line_find_case(args->kwargs, "PURPOSE"); + if (!purp) { + control_write_endreply(conn, 552, "No purpose given"); + goto done; + } + new_purpose = circuit_purpose_from_string(purp->value); + if (new_purpose == CIRCUIT_PURPOSE_UNKNOWN) { + control_printf_endreply(conn, 552, "Unknown purpose \"%s\"", + purp->value); + goto done; + } + } + + circuit_change_purpose(TO_CIRCUIT(circ), new_purpose); + send_control_done(conn); + + done: + return 0; +} + +static const char *attachstream_keywords[] = { + "HOP", NULL +}; +static const control_cmd_syntax_t attachstream_syntax = { + .min_args=2, .max_args=2, + .accept_keywords=true, + .allowed_keywords=attachstream_keywords +}; + +/** Called when we get an ATTACHSTREAM message. Try to attach the requested + * stream, and report success or failure. */ +static int +handle_control_attachstream(control_connection_t *conn, + const control_cmd_args_t *args) +{ + entry_connection_t *ap_conn = NULL; + origin_circuit_t *circ = NULL; + crypt_path_t *cpath=NULL; + int hop=0, hop_line_ok=1; + const char *stream_id = smartlist_get(args->args, 0); + const char *circ_id = smartlist_get(args->args, 1); + int zero_circ = !strcmp(circ_id, "0"); + const config_line_t *hoparg = config_line_find_case(args->kwargs, "HOP"); + + if (!(ap_conn = get_stream(stream_id))) { + control_printf_endreply(conn, 552, "Unknown stream \"%s\"", stream_id); + return 0; + } else if (!zero_circ && !(circ = get_circ(circ_id))) { + control_printf_endreply(conn, 552, "Unknown circuit \"%s\"", circ_id); + return 0; + } else if (circ) { + if (hoparg) { + hop = (int) tor_parse_ulong(hoparg->value, 10, 0, INT_MAX, + &hop_line_ok, NULL); + if (!hop_line_ok) { /* broken hop line */ + control_printf_endreply(conn, 552, "Bad value hop=%s", + hoparg->value); + return 0; + } + } + } + + if (ENTRY_TO_CONN(ap_conn)->state != AP_CONN_STATE_CONTROLLER_WAIT && + ENTRY_TO_CONN(ap_conn)->state != AP_CONN_STATE_CONNECT_WAIT && + ENTRY_TO_CONN(ap_conn)->state != AP_CONN_STATE_RESOLVE_WAIT) { + control_write_endreply(conn, 555, + "Connection is not managed by controller."); + return 0; + } + + /* Do we need to detach it first? */ + if (ENTRY_TO_CONN(ap_conn)->state != AP_CONN_STATE_CONTROLLER_WAIT) { + edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn); + circuit_t *tmpcirc = circuit_get_by_edge_conn(edge_conn); + connection_edge_end(edge_conn, END_STREAM_REASON_TIMEOUT); + /* Un-mark it as ending, since we're going to reuse it. */ + edge_conn->edge_has_sent_end = 0; + edge_conn->end_reason = 0; + if (tmpcirc) + circuit_detach_stream(tmpcirc, edge_conn); + CONNECTION_AP_EXPECT_NONPENDING(ap_conn); + TO_CONN(edge_conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; + } + + if (circ && (circ->base_.state != CIRCUIT_STATE_OPEN)) { + control_write_endreply(conn, 551, + "Can't attach stream to non-open origin circuit"); + return 0; + } + /* Is this a single hop circuit? */ + if (circ && (circuit_get_cpath_len(circ)<2 || hop==1)) { + control_write_endreply(conn, 551, + "Can't attach stream to this one-hop circuit."); + return 0; + } + + if (circ && hop>0) { + /* find this hop in the circuit, and set cpath */ + cpath = circuit_get_cpath_hop(circ, hop); + if (!cpath) { + control_printf_endreply(conn, 551, "Circuit doesn't have %d hops.", hop); + return 0; + } + } + if (connection_ap_handshake_rewrite_and_attach(ap_conn, circ, cpath) < 0) { + control_write_endreply(conn, 551, "Unable to attach stream"); + return 0; + } + send_control_done(conn); + return 0; +} + +static const char *postdescriptor_keywords[] = { + "cache", "purpose", NULL, +}; + +static const control_cmd_syntax_t postdescriptor_syntax = { + .max_args = 0, + .accept_keywords = true, + .allowed_keywords = postdescriptor_keywords, + .want_cmddata = true, +}; + +/** Called when we get a POSTDESCRIPTOR message. Try to learn the provided + * descriptor, and report success or failure. */ +static int +handle_control_postdescriptor(control_connection_t *conn, + const control_cmd_args_t *args) +{ + const char *msg=NULL; + uint8_t purpose = ROUTER_PURPOSE_GENERAL; + int cache = 0; /* eventually, we may switch this to 1 */ + const config_line_t *line; + + line = config_line_find_case(args->kwargs, "purpose"); + if (line) { + purpose = router_purpose_from_string(line->value); + if (purpose == ROUTER_PURPOSE_UNKNOWN) { + control_printf_endreply(conn, 552, "Unknown purpose \"%s\"", + line->value); + goto done; + } + } + line = config_line_find_case(args->kwargs, "cache"); + if (line) { + if (!strcasecmp(line->value, "no")) + cache = 0; + else if (!strcasecmp(line->value, "yes")) + cache = 1; + else { + control_printf_endreply(conn, 552, "Unknown cache request \"%s\"", + line->value); + goto done; + } + } + + switch (router_load_single_router(args->cmddata, purpose, cache, &msg)) { + case -1: + if (!msg) msg = "Could not parse descriptor"; + control_write_endreply(conn, 554, msg); + break; + case 0: + if (!msg) msg = "Descriptor not added"; + control_write_endreply(conn, 251, msg); + break; + case 1: + send_control_done(conn); + break; + } + + done: + return 0; +} + +static const control_cmd_syntax_t redirectstream_syntax = { + .min_args = 2, + .max_args = UINT_MAX, // XXX should be 3. +}; + +/** Called when we receive a REDIRECTSTERAM command. Try to change the target + * address of the named AP stream, and report success or failure. */ +static int +handle_control_redirectstream(control_connection_t *conn, + const control_cmd_args_t *cmd_args) +{ + entry_connection_t *ap_conn = NULL; + char *new_addr = NULL; + uint16_t new_port = 0; + const smartlist_t *args = cmd_args->args; + + if (!(ap_conn = get_stream(smartlist_get(args, 0))) + || !ap_conn->socks_request) { + control_printf_endreply(conn, 552, "Unknown stream \"%s\"", + (char*)smartlist_get(args, 0)); + } else { + int ok = 1; + if (smartlist_len(args) > 2) { /* they included a port too */ + new_port = (uint16_t) tor_parse_ulong(smartlist_get(args, 2), + 10, 1, 65535, &ok, NULL); + } + if (!ok) { + control_printf_endreply(conn, 512, "Cannot parse port \"%s\"", + (char*)smartlist_get(args, 2)); + } else { + new_addr = tor_strdup(smartlist_get(args, 1)); + } + } + + if (!new_addr) + return 0; + + strlcpy(ap_conn->socks_request->address, new_addr, + sizeof(ap_conn->socks_request->address)); + if (new_port) + ap_conn->socks_request->port = new_port; + tor_free(new_addr); + send_control_done(conn); + return 0; +} + +static const control_cmd_syntax_t closestream_syntax = { + .min_args = 2, + .max_args = UINT_MAX, /* XXXX This is the original behavior, but + * maybe we should change the spec. */ +}; + +/** Called when we get a CLOSESTREAM command; try to close the named stream + * and report success or failure. */ +static int +handle_control_closestream(control_connection_t *conn, + const control_cmd_args_t *cmd_args) +{ + entry_connection_t *ap_conn=NULL; + uint8_t reason=0; + int ok; + const smartlist_t *args = cmd_args->args; + + tor_assert(smartlist_len(args) >= 2); + + if (!(ap_conn = get_stream(smartlist_get(args, 0)))) + control_printf_endreply(conn, 552, "Unknown stream \"%s\"", + (char*)smartlist_get(args, 0)); + else { + reason = (uint8_t) tor_parse_ulong(smartlist_get(args,1), 10, 0, 255, + &ok, NULL); + if (!ok) { + control_printf_endreply(conn, 552, "Unrecognized reason \"%s\"", + (char*)smartlist_get(args, 1)); + ap_conn = NULL; + } + } + if (!ap_conn) + return 0; + + connection_mark_unattached_ap(ap_conn, reason); + send_control_done(conn); + return 0; +} + +static const control_cmd_syntax_t closecircuit_syntax = { + .min_args=1, .max_args=1, + .accept_keywords=true, + .kvline_flags=KV_OMIT_VALS, + // XXXX we might want to exclude unrecognized flags, but for now we + // XXXX just ignore them for backward compatibility. +}; + +/** Called when we get a CLOSECIRCUIT command; try to close the named circuit + * and report success or failure. */ +static int +handle_control_closecircuit(control_connection_t *conn, + const control_cmd_args_t *args) +{ + const char *circ_id = smartlist_get(args->args, 0); + origin_circuit_t *circ = NULL; + + if (!(circ=get_circ(circ_id))) { + control_printf_endreply(conn, 552, "Unknown circuit \"%s\"", circ_id); + return 0; + } + + bool safe = config_lines_contain_flag(args->kwargs, "IfUnused"); + + if (!safe || !circ->p_streams) { + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_REQUESTED); + } + + send_control_done(conn); + return 0; +} + +static const control_cmd_syntax_t resolve_syntax = { + .max_args=0, + .accept_keywords=true, + .kvline_flags=KV_OMIT_VALS, +}; + +/** Called when we get a RESOLVE command: start trying to resolve + * the listed addresses. */ +static int +handle_control_resolve(control_connection_t *conn, + const control_cmd_args_t *args) +{ + smartlist_t *failed; + int is_reverse = 0; + + if (!(conn->event_mask & (((event_mask_t)1)<kwargs, "mode"); + if (modearg && !strcasecmp(modearg->value, "reverse")) + is_reverse = 1; + } + failed = smartlist_new(); + for (const config_line_t *line = args->kwargs; line; line = line->next) { + if (!strlen(line->value)) { + const char *addr = line->key; + if (dnsserv_launch_request(addr, is_reverse, conn)<0) + smartlist_add(failed, (char*)addr); + } else { + // XXXX arguably we should reject unrecognized keyword arguments, + // XXXX but the old implementation didn't do that. + } + } + + send_control_done(conn); + SMARTLIST_FOREACH(failed, const char *, arg, { + control_event_address_mapped(arg, arg, time(NULL), + "internal", 0); + }); + + smartlist_free(failed); + return 0; +} + +static const control_cmd_syntax_t protocolinfo_syntax = { + .max_args = UINT_MAX +}; + +/** Called when we get a PROTOCOLINFO command: send back a reply. */ +static int +handle_control_protocolinfo(control_connection_t *conn, + const control_cmd_args_t *cmd_args) +{ + const char *bad_arg = NULL; + const smartlist_t *args = cmd_args->args; + + conn->have_sent_protocolinfo = 1; + + SMARTLIST_FOREACH(args, const char *, arg, { + int ok; + tor_parse_long(arg, 10, 0, LONG_MAX, &ok, NULL); + if (!ok) { + bad_arg = arg; + break; + } + }); + if (bad_arg) { + control_printf_endreply(conn, 513, "No such version %s", + escaped(bad_arg)); + /* 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); + } + done: + return 0; +} + +static const control_cmd_syntax_t usefeature_syntax = { + .max_args = UINT_MAX +}; + +/** Called when we get a USEFEATURE command: parse the feature list, and + * set up the control_connection's options properly. */ +static int +handle_control_usefeature(control_connection_t *conn, + const control_cmd_args_t *cmd_args) +{ + const smartlist_t *args = cmd_args->args; + int bad = 0; + SMARTLIST_FOREACH_BEGIN(args, const char *, arg) { + if (!strcasecmp(arg, "VERBOSE_NAMES")) + ; + else if (!strcasecmp(arg, "EXTENDED_EVENTS")) + ; + else { + control_printf_endreply(conn, 552, "Unrecognized feature \"%s\"", + arg); + bad = 1; + break; + } + } SMARTLIST_FOREACH_END(arg); + + if (!bad) { + send_control_done(conn); + } + + return 0; +} + +static const control_cmd_syntax_t dropguards_syntax = { + .max_args = 0, +}; + +/** Implementation for the DROPGUARDS command. */ +static int +handle_control_dropguards(control_connection_t *conn, + const control_cmd_args_t *args) +{ + (void) args; /* We don't take arguments. */ + + static int have_warned = 0; + if (! have_warned) { + log_warn(LD_CONTROL, "DROPGUARDS is dangerous; make sure you understand " + "the risks before using it. It may be removed in a future " + "version of Tor."); + have_warned = 1; + } + + remove_all_entry_guards(); + send_control_done(conn); + + return 0; +} + +static const char *hsfetch_keywords[] = { + "SERVER", NULL, +}; +static const control_cmd_syntax_t hsfetch_syntax = { + .min_args = 1, .max_args = 1, + .accept_keywords = true, + .allowed_keywords = hsfetch_keywords, +}; + +/** Implementation for the HSFETCH command. */ +static int +handle_control_hsfetch(control_connection_t *conn, + const control_cmd_args_t *args) + +{ + char digest[DIGEST_LEN], *desc_id = NULL; + smartlist_t *hsdirs = NULL; + static const char *v2_str = "v2-"; + const size_t v2_str_len = strlen(v2_str); + rend_data_t *rend_query = NULL; + ed25519_public_key_t v3_pk; + uint32_t version; + const char *hsaddress = NULL; + + /* Extract the first argument (either HSAddress or DescID). */ + const char *arg1 = smartlist_get(args->args, 0); + /* Test if it's an HS address without the .onion part. */ + if (rend_valid_v2_service_id(arg1)) { + hsaddress = arg1; + version = HS_VERSION_TWO; + } else if (strcmpstart(arg1, v2_str) == 0 && + rend_valid_descriptor_id(arg1 + v2_str_len) && + base32_decode(digest, sizeof(digest), arg1 + v2_str_len, + REND_DESC_ID_V2_LEN_BASE32) == + REND_DESC_ID_V2_LEN_BASE32) { + /* We have a well formed version 2 descriptor ID. Keep the decoded value + * of the id. */ + desc_id = digest; + version = HS_VERSION_TWO; + } else if (hs_address_is_valid(arg1)) { + hsaddress = arg1; + version = HS_VERSION_THREE; + hs_parse_address(hsaddress, &v3_pk, NULL, NULL); + } else { + control_printf_endreply(conn, 513, "Invalid argument \"%s\"", arg1); + goto done; + } + + for (const config_line_t *line = args->kwargs; line; line = line->next) { + if (!strcasecmp(line->key, "SERVER")) { + const char *server = line->value; + + const node_t *node = node_get_by_hex_id(server, 0); + if (!node) { + control_printf_endreply(conn, 552, "Server \"%s\" not found", server); + goto done; + } + if (!hsdirs) { + /* Stores routerstatus_t cmddata for each specified server. */ + hsdirs = smartlist_new(); + } + /* Valid server, add it to our local list. */ + smartlist_add(hsdirs, node->rs); + } else { + tor_assert_nonfatal_unreached(); + } + } + + if (version == HS_VERSION_TWO) { + rend_query = rend_data_client_create(hsaddress, desc_id, NULL, + REND_NO_AUTH); + if (rend_query == NULL) { + control_write_endreply(conn, 551, "Error creating the HS query"); + goto done; + } + } + + /* Using a descriptor ID, we force the user to provide at least one + * hsdir server using the SERVER= option. */ + if (desc_id && (!hsdirs || !smartlist_len(hsdirs))) { + control_write_endreply(conn, 512, "SERVER option is required"); + goto done; + } + + /* We are about to trigger HSDir fetch so send the OK now because after + * that 650 event(s) are possible so better to have the 250 OK before them + * to avoid out of order replies. */ + send_control_done(conn); + + /* Trigger the fetch using the built rend query and possibly a list of HS + * directory to use. This function ignores the client cache thus this will + * always send a fetch command. */ + if (version == HS_VERSION_TWO) { + rend_client_fetch_v2_desc(rend_query, hsdirs); + } else if (version == HS_VERSION_THREE) { + hs_control_hsfetch_command(&v3_pk, hsdirs); + } + + done: + /* Contains data pointer that we don't own thus no cleanup. */ + smartlist_free(hsdirs); + rend_data_free(rend_query); + return 0; +} + +static const char *hspost_keywords[] = { + "SERVER", "HSADDRESS", NULL +}; +static const control_cmd_syntax_t hspost_syntax = { + .min_args = 0, .max_args = 0, + .accept_keywords = true, + .want_cmddata = true, + .allowed_keywords = hspost_keywords +}; + +/** Implementation for the HSPOST command. */ +static int +handle_control_hspost(control_connection_t *conn, + const control_cmd_args_t *args) +{ + smartlist_t *hs_dirs = NULL; + const char *encoded_desc = args->cmddata; + size_t encoded_desc_len = args->cmddata_len; + const char *onion_address = NULL; + const config_line_t *line; + + for (line = args->kwargs; line; line = line->next) { + if (!strcasecmpstart(line->key, "SERVER")) { + const char *server = line->value; + const node_t *node = node_get_by_hex_id(server, 0); + + if (!node || !node->rs) { + control_printf_endreply(conn, 552, "Server \"%s\" not found", + server); + goto done; + } + /* Valid server, add it to our local list. */ + if (!hs_dirs) + hs_dirs = smartlist_new(); + smartlist_add(hs_dirs, node->rs); + } else if (!strcasecmpstart(line->key, "HSADDRESS")) { + const char *address = line->value; + if (!hs_address_is_valid(address)) { + control_write_endreply(conn, 512, "Malformed onion address"); + goto done; + } + onion_address = address; + } else { + tor_assert_nonfatal_unreached(); + } + } + + /* Handle the v3 case. */ + if (onion_address) { + if (hs_control_hspost_command(encoded_desc, onion_address, hs_dirs) < 0) { + control_write_endreply(conn, 554, "Invalid descriptor"); + } else { + send_control_done(conn); + } + goto done; + } + + /* From this point on, it is only v2. */ + + /* parse it. */ + rend_encoded_v2_service_descriptor_t *desc = + tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t)); + desc->desc_str = tor_memdup_nulterm(encoded_desc, encoded_desc_len); + + rend_service_descriptor_t *parsed = NULL; + char *intro_content = NULL; + size_t intro_size; + size_t encoded_size; + const char *next_desc; + if (!rend_parse_v2_service_descriptor(&parsed, desc->desc_id, &intro_content, + &intro_size, &encoded_size, + &next_desc, desc->desc_str, 1)) { + /* Post the descriptor. */ + char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; + if (!rend_get_service_id(parsed->pk, serviceid)) { + smartlist_t *descs = smartlist_new(); + smartlist_add(descs, desc); + + /* We are about to trigger HS descriptor upload so send the OK now + * because after that 650 event(s) are possible so better to have the + * 250 OK before them to avoid out of order replies. */ + send_control_done(conn); + + /* Trigger the descriptor upload */ + directory_post_to_hs_dir(parsed, descs, hs_dirs, serviceid, 0); + smartlist_free(descs); + } + + rend_service_descriptor_free(parsed); + } else { + control_write_endreply(conn, 554, "Invalid descriptor"); + } + + tor_free(intro_content); + rend_encoded_v2_service_descriptor_free(desc); + done: + smartlist_free(hs_dirs); /* Contents belong to the rend service code. */ + return 0; +} + +/* Helper function for ADD_ONION that adds an ephemeral service depending on + * the given hs_version. + * + * The secret key in pk depends on the hs_version. The ownership of the key + * used in pk is given to the HS subsystem so the caller must stop accessing + * it after. + * + * The port_cfgs is a list of service port. Ownership transferred to service. + * The max_streams refers to the MaxStreams= key. + * The max_streams_close_circuit refers to the MaxStreamsCloseCircuit key. + * The auth_type is the authentication type of the clients in auth_clients. + * The ownership of that list is transferred to the service. + * + * On success (RSAE_OKAY), the address_out points to a newly allocated string + * containing the onion address without the .onion part. On error, address_out + * is untouched. */ +static hs_service_add_ephemeral_status_t +add_onion_helper_add_service(int hs_version, + add_onion_secret_key_t *pk, + smartlist_t *port_cfgs, int max_streams, + int max_streams_close_circuit, int auth_type, + smartlist_t *auth_clients, char **address_out) +{ + hs_service_add_ephemeral_status_t ret; + + tor_assert(pk); + tor_assert(port_cfgs); + tor_assert(address_out); + + switch (hs_version) { + case HS_VERSION_TWO: + ret = rend_service_add_ephemeral(pk->v2, port_cfgs, max_streams, + max_streams_close_circuit, auth_type, + auth_clients, address_out); + break; + case HS_VERSION_THREE: + ret = hs_service_add_ephemeral(pk->v3, port_cfgs, max_streams, + max_streams_close_circuit, address_out); + break; + default: + tor_assert_unreached(); + } + + return ret; +} + +/** The list of onion services that have been added via ADD_ONION that do not + * belong to any particular control connection. + */ +static smartlist_t *detached_onion_services = NULL; + +/** + * Return a list of detached onion services, or NULL if none exist. + **/ +smartlist_t * +get_detached_onion_services(void) +{ + return detached_onion_services; +} + +static const char *add_onion_keywords[] = { + "Port", "Flags", "MaxStreams", "ClientAuth", NULL +}; +static const control_cmd_syntax_t add_onion_syntax = { + .min_args = 1, .max_args = 1, + .accept_keywords = true, + .allowed_keywords = add_onion_keywords +}; + +/** Called when we get a ADD_ONION command; parse the body, and set up + * the new ephemeral Onion Service. */ +static int +handle_control_add_onion(control_connection_t *conn, + const control_cmd_args_t *args) +{ + /* Parse all of the arguments that do not involve handling cryptographic + * material first, since there's no reason to touch that at all if any of + * the other arguments are malformed. + */ + smartlist_t *port_cfgs = smartlist_new(); + smartlist_t *auth_clients = NULL; + smartlist_t *auth_created_clients = NULL; + int discard_pk = 0; + int detach = 0; + int max_streams = 0; + int max_streams_close_circuit = 0; + rend_auth_type_t auth_type = REND_NO_AUTH; + int non_anonymous = 0; + const config_line_t *arg; + + for (arg = args->kwargs; arg; arg = arg->next) { + if (!strcasecmp(arg->key, "Port")) { + /* "Port=VIRTPORT[,TARGET]". */ + rend_service_port_config_t *cfg = + rend_service_parse_port_config(arg->value, ",", NULL); + if (!cfg) { + control_write_endreply(conn, 512, "Invalid VIRTPORT/TARGET"); + goto out; + } + smartlist_add(port_cfgs, cfg); + } else if (!strcasecmp(arg->key, "MaxStreams")) { + /* "MaxStreams=[0..65535]". */ + int ok = 0; + max_streams = (int)tor_parse_long(arg->value, 10, 0, 65535, &ok, NULL); + if (!ok) { + control_write_endreply(conn, 512, "Invalid MaxStreams"); + goto out; + } + } else if (!strcasecmp(arg->key, "Flags")) { + /* "Flags=Flag[,Flag]", where Flag can be: + * * 'DiscardPK' - If tor generates the keypair, do not include it in + * the response. + * * 'Detach' - Do not tie this onion service to any particular control + * connection. + * * 'MaxStreamsCloseCircuit' - Close the circuit if MaxStreams is + * exceeded. + * * 'BasicAuth' - Client authorization using the 'basic' method. + * * 'NonAnonymous' - Add a non-anonymous Single Onion Service. If this + * flag is present, tor must be in non-anonymous + * hidden service mode. If this flag is absent, + * tor must be in anonymous hidden service mode. + */ + static const char *discard_flag = "DiscardPK"; + static const char *detach_flag = "Detach"; + static const char *max_s_close_flag = "MaxStreamsCloseCircuit"; + static const char *basicauth_flag = "BasicAuth"; + static const char *non_anonymous_flag = "NonAnonymous"; + + smartlist_t *flags = smartlist_new(); + int bad = 0; + + smartlist_split_string(flags, arg->value, ",", SPLIT_IGNORE_BLANK, 0); + if (smartlist_len(flags) < 1) { + control_write_endreply(conn, 512, "Invalid 'Flags' argument"); + bad = 1; + } + SMARTLIST_FOREACH_BEGIN(flags, const char *, flag) + { + if (!strcasecmp(flag, discard_flag)) { + discard_pk = 1; + } else if (!strcasecmp(flag, detach_flag)) { + detach = 1; + } else if (!strcasecmp(flag, max_s_close_flag)) { + max_streams_close_circuit = 1; + } else if (!strcasecmp(flag, basicauth_flag)) { + auth_type = REND_BASIC_AUTH; + } else if (!strcasecmp(flag, non_anonymous_flag)) { + non_anonymous = 1; + } else { + control_printf_endreply(conn, 512, "Invalid 'Flags' argument: %s", + escaped(flag)); + bad = 1; + break; + } + } SMARTLIST_FOREACH_END(flag); + SMARTLIST_FOREACH(flags, char *, cp, tor_free(cp)); + smartlist_free(flags); + if (bad) + goto out; + + } else if (!strcasecmp(arg->key, "ClientAuth")) { + char *err_msg = NULL; + int created = 0; + rend_authorized_client_t *client = + add_onion_helper_clientauth(arg->value, + &created, &err_msg); + if (!client) { + if (err_msg) { + connection_write_str_to_buf(err_msg, conn); + tor_free(err_msg); + } + goto out; + } + + if (auth_clients != NULL) { + int bad = 0; + SMARTLIST_FOREACH_BEGIN(auth_clients, rend_authorized_client_t *, ac) { + if (strcmp(ac->client_name, client->client_name) == 0) { + bad = 1; + break; + } + } SMARTLIST_FOREACH_END(ac); + if (bad) { + control_write_endreply(conn, 512, "Duplicate name in ClientAuth"); + rend_authorized_client_free(client); + goto out; + } + } else { + auth_clients = smartlist_new(); + auth_created_clients = smartlist_new(); + } + smartlist_add(auth_clients, client); + if (created) { + smartlist_add(auth_created_clients, client); + } + } else { + tor_assert_nonfatal_unreached(); + goto out; + } + } + if (smartlist_len(port_cfgs) == 0) { + control_write_endreply(conn, 512, "Missing 'Port' argument"); + goto out; + } else if (auth_type == REND_NO_AUTH && auth_clients != NULL) { + control_write_endreply(conn, 512, "No auth type specified"); + goto out; + } else if (auth_type != REND_NO_AUTH && auth_clients == NULL) { + control_write_endreply(conn, 512, "No auth clients specified"); + goto out; + } else if ((auth_type == REND_BASIC_AUTH && + smartlist_len(auth_clients) > 512) || + (auth_type == REND_STEALTH_AUTH && + smartlist_len(auth_clients) > 16)) { + control_write_endreply(conn, 512, "Too many auth clients"); + goto out; + } else if (non_anonymous != rend_service_non_anonymous_mode_enabled( + get_options())) { + /* If we failed, and the non-anonymous flag is set, Tor must be in + * anonymous hidden service mode. + * The error message changes based on the current Tor config: + * 512 Tor is in anonymous hidden service mode + * 512 Tor is in non-anonymous hidden service mode + * (I've deliberately written them out in full here to aid searchability.) + */ + control_printf_endreply(conn, 512, + "Tor is in %sanonymous hidden service " "mode", + non_anonymous ? "" : "non-"); + goto out; + } + + /* Parse the "keytype:keyblob" argument. */ + int hs_version = 0; + add_onion_secret_key_t pk = { NULL }; + const char *key_new_alg = NULL; + char *key_new_blob = NULL; + char *err_msg = NULL; + + const char *onionkey = smartlist_get(args->args, 0); + if (add_onion_helper_keyarg(onionkey, discard_pk, + &key_new_alg, &key_new_blob, &pk, &hs_version, + &err_msg) < 0) { + if (err_msg) { + connection_write_str_to_buf(err_msg, conn); + tor_free(err_msg); + } + goto out; + } + tor_assert(!err_msg); + + /* Hidden service version 3 don't have client authentication support so if + * ClientAuth was given, send back an error. */ + if (hs_version == HS_VERSION_THREE && auth_clients) { + control_write_endreply(conn, 513, "ClientAuth not supported"); + goto out; + } + + /* Create the HS, using private key pk, client authentication auth_type, + * the list of auth_clients, and port config port_cfg. + * rend_service_add_ephemeral() will take ownership of pk and port_cfg, + * regardless of success/failure. + */ + char *service_id = NULL; + int ret = add_onion_helper_add_service(hs_version, &pk, port_cfgs, + max_streams, + max_streams_close_circuit, auth_type, + auth_clients, &service_id); + port_cfgs = NULL; /* port_cfgs is now owned by the rendservice code. */ + auth_clients = NULL; /* so is auth_clients */ + switch (ret) { + case RSAE_OKAY: + { + if (detach) { + if (!detached_onion_services) + detached_onion_services = smartlist_new(); + smartlist_add(detached_onion_services, service_id); + } else { + if (!conn->ephemeral_onion_services) + conn->ephemeral_onion_services = smartlist_new(); + smartlist_add(conn->ephemeral_onion_services, service_id); + } + + tor_assert(service_id); + control_printf_midreply(conn, 250, "ServiceID=%s", service_id); + if (key_new_alg) { + tor_assert(key_new_blob); + control_printf_midreply(conn, 250, "PrivateKey=%s:%s", + key_new_alg, key_new_blob); + } + if (auth_created_clients) { + SMARTLIST_FOREACH(auth_created_clients, rend_authorized_client_t *, ac, { + char *encoded = rend_auth_encode_cookie(ac->descriptor_cookie, + auth_type); + tor_assert(encoded); + connection_printf_to_buf(conn, "250-ClientAuth=%s:%s\r\n", + ac->client_name, encoded); + memwipe(encoded, 0, strlen(encoded)); + tor_free(encoded); + }); + } + + send_control_done(conn); + break; + } + case RSAE_BADPRIVKEY: + control_write_endreply(conn, 551, "Failed to generate onion address"); + break; + case RSAE_ADDREXISTS: + control_write_endreply(conn, 550, "Onion address collision"); + break; + case RSAE_BADVIRTPORT: + control_write_endreply(conn, 512, "Invalid VIRTPORT/TARGET"); + break; + case RSAE_BADAUTH: + control_write_endreply(conn, 512, "Invalid client authorization"); + break; + case RSAE_INTERNAL: /* FALLSTHROUGH */ + default: + control_write_endreply(conn, 551, "Failed to add Onion Service"); + } + if (key_new_blob) { + memwipe(key_new_blob, 0, strlen(key_new_blob)); + tor_free(key_new_blob); + } + + out: + if (port_cfgs) { + SMARTLIST_FOREACH(port_cfgs, rend_service_port_config_t*, p, + rend_service_port_config_free(p)); + smartlist_free(port_cfgs); + } + + if (auth_clients) { + SMARTLIST_FOREACH(auth_clients, rend_authorized_client_t *, ac, + rend_authorized_client_free(ac)); + smartlist_free(auth_clients); + } + if (auth_created_clients) { + // Do not free entries; they are the same as auth_clients + smartlist_free(auth_created_clients); + } + return 0; +} + +/** Helper function to handle parsing the KeyType:KeyBlob argument to the + * ADD_ONION command. Return a new crypto_pk_t and if a new key was generated + * and the private key not discarded, the algorithm and serialized private key, + * or NULL and an optional control protocol error message on failure. The + * caller is responsible for freeing the returned key_new_blob and err_msg. + * + * Note: The error messages returned are deliberately vague to avoid echoing + * key material. + */ +STATIC int +add_onion_helper_keyarg(const char *arg, int discard_pk, + const char **key_new_alg_out, char **key_new_blob_out, + add_onion_secret_key_t *decoded_key, int *hs_version, + char **err_msg_out) +{ + smartlist_t *key_args = smartlist_new(); + crypto_pk_t *pk = NULL; + const char *key_new_alg = NULL; + char *key_new_blob = NULL; + char *err_msg = NULL; + int ret = -1; + + smartlist_split_string(key_args, arg, ":", SPLIT_IGNORE_BLANK, 0); + if (smartlist_len(key_args) != 2) { + err_msg = tor_strdup("512 Invalid key type/blob\r\n"); + goto err; + } + + /* The format is "KeyType:KeyBlob". */ + static const char *key_type_new = "NEW"; + static const char *key_type_best = "BEST"; + static const char *key_type_rsa1024 = "RSA1024"; + static const char *key_type_ed25519_v3 = "ED25519-V3"; + + const char *key_type = smartlist_get(key_args, 0); + const char *key_blob = smartlist_get(key_args, 1); + + if (!strcasecmp(key_type_rsa1024, key_type)) { + /* "RSA:" - Loading a pre-existing RSA1024 key. */ + pk = crypto_pk_base64_decode_private(key_blob, strlen(key_blob)); + if (!pk) { + err_msg = tor_strdup("512 Failed to decode RSA key\r\n"); + goto err; + } + if (crypto_pk_num_bits(pk) != PK_BYTES*8) { + crypto_pk_free(pk); + err_msg = tor_strdup("512 Invalid RSA key size\r\n"); + goto err; + } + decoded_key->v2 = pk; + *hs_version = HS_VERSION_TWO; + } else if (!strcasecmp(key_type_ed25519_v3, key_type)) { + /* "ED25519-V3:" - Loading a pre-existing ed25519 key. */ + ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk)); + if (base64_decode((char *) sk->seckey, sizeof(sk->seckey), key_blob, + strlen(key_blob)) != sizeof(sk->seckey)) { + tor_free(sk); + err_msg = tor_strdup("512 Failed to decode ED25519-V3 key\r\n"); + goto err; + } + decoded_key->v3 = sk; + *hs_version = HS_VERSION_THREE; + } else if (!strcasecmp(key_type_new, key_type)) { + /* "NEW:" - Generating a new key, blob as algorithm. */ + if (!strcasecmp(key_type_rsa1024, key_blob) || + !strcasecmp(key_type_best, key_blob)) { + /* "RSA1024", RSA 1024 bit, also currently "BEST" by default. */ + pk = crypto_pk_new(); + if (crypto_pk_generate_key(pk)) { + tor_asprintf(&err_msg, "551 Failed to generate %s key\r\n", + key_type_rsa1024); + goto err; + } + if (!discard_pk) { + if (crypto_pk_base64_encode_private(pk, &key_new_blob)) { + crypto_pk_free(pk); + tor_asprintf(&err_msg, "551 Failed to encode %s key\r\n", + key_type_rsa1024); + goto err; + } + key_new_alg = key_type_rsa1024; + } + decoded_key->v2 = pk; + *hs_version = HS_VERSION_TWO; + } else if (!strcasecmp(key_type_ed25519_v3, key_blob)) { + ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk)); + if (ed25519_secret_key_generate(sk, 1) < 0) { + tor_free(sk); + tor_asprintf(&err_msg, "551 Failed to generate %s key\r\n", + key_type_ed25519_v3); + goto err; + } + if (!discard_pk) { + ssize_t len = base64_encode_size(sizeof(sk->seckey), 0) + 1; + key_new_blob = tor_malloc_zero(len); + if (base64_encode(key_new_blob, len, (const char *) sk->seckey, + sizeof(sk->seckey), 0) != (len - 1)) { + tor_free(sk); + tor_free(key_new_blob); + tor_asprintf(&err_msg, "551 Failed to encode %s key\r\n", + key_type_ed25519_v3); + goto err; + } + key_new_alg = key_type_ed25519_v3; + } + decoded_key->v3 = sk; + *hs_version = HS_VERSION_THREE; + } else { + err_msg = tor_strdup("513 Invalid key type\r\n"); + goto err; + } + } else { + err_msg = tor_strdup("513 Invalid key type\r\n"); + goto err; + } + + /* Succeeded in loading or generating a private key. */ + ret = 0; + + err: + SMARTLIST_FOREACH(key_args, char *, cp, { + memwipe(cp, 0, strlen(cp)); + tor_free(cp); + }); + smartlist_free(key_args); + + if (err_msg_out) { + *err_msg_out = err_msg; + } else { + tor_free(err_msg); + } + *key_new_alg_out = key_new_alg; + *key_new_blob_out = key_new_blob; + + return ret; +} + +/** Helper function to handle parsing a ClientAuth argument to the + * ADD_ONION command. Return a new rend_authorized_client_t, or NULL + * and an optional control protocol error message on failure. The + * caller is responsible for freeing the returned auth_client and err_msg. + * + * If 'created' is specified, it will be set to 1 when a new cookie has + * been generated. + */ +STATIC rend_authorized_client_t * +add_onion_helper_clientauth(const char *arg, int *created, char **err_msg) +{ + int ok = 0; + + tor_assert(arg); + tor_assert(created); + tor_assert(err_msg); + *err_msg = NULL; + + smartlist_t *auth_args = smartlist_new(); + rend_authorized_client_t *client = + tor_malloc_zero(sizeof(rend_authorized_client_t)); + smartlist_split_string(auth_args, arg, ":", 0, 0); + if (smartlist_len(auth_args) < 1 || smartlist_len(auth_args) > 2) { + *err_msg = tor_strdup("512 Invalid ClientAuth syntax\r\n"); + goto err; + } + client->client_name = tor_strdup(smartlist_get(auth_args, 0)); + if (smartlist_len(auth_args) == 2) { + char *decode_err_msg = NULL; + if (rend_auth_decode_cookie(smartlist_get(auth_args, 1), + client->descriptor_cookie, + NULL, &decode_err_msg) < 0) { + tor_assert(decode_err_msg); + tor_asprintf(err_msg, "512 %s\r\n", decode_err_msg); + tor_free(decode_err_msg); + goto err; + } + *created = 0; + } else { + crypto_rand((char *) client->descriptor_cookie, REND_DESC_COOKIE_LEN); + *created = 1; + } + + if (!rend_valid_client_name(client->client_name)) { + *err_msg = tor_strdup("512 Invalid name in ClientAuth\r\n"); + goto err; + } + + ok = 1; + err: + SMARTLIST_FOREACH(auth_args, char *, item, tor_free(item)); + smartlist_free(auth_args); + if (!ok) { + rend_authorized_client_free(client); + client = NULL; + } + return client; +} + +static const control_cmd_syntax_t del_onion_syntax = { + .min_args = 1, .max_args = 1, +}; + +/** Called when we get a DEL_ONION command; parse the body, and remove + * the existing ephemeral Onion Service. */ +static int +handle_control_del_onion(control_connection_t *conn, + const control_cmd_args_t *cmd_args) +{ + int hs_version = 0; + smartlist_t *args = cmd_args->args; + tor_assert(smartlist_len(args) == 1); + + const char *service_id = smartlist_get(args, 0); + if (rend_valid_v2_service_id(service_id)) { + hs_version = HS_VERSION_TWO; + } else if (hs_address_is_valid(service_id)) { + hs_version = HS_VERSION_THREE; + } else { + control_write_endreply(conn, 512, "Malformed Onion Service id"); + goto out; + } + + /* Determine if the onion service belongs to this particular control + * connection, or if it is in the global list of detached services. If it + * is in neither, either the service ID is invalid in some way, or it + * explicitly belongs to a different control connection, and an error + * should be returned. + */ + smartlist_t *services[2] = { + conn->ephemeral_onion_services, + detached_onion_services + }; + smartlist_t *onion_services = NULL; + int idx = -1; + for (size_t i = 0; i < ARRAY_LENGTH(services); i++) { + idx = smartlist_string_pos(services[i], service_id); + if (idx != -1) { + onion_services = services[i]; + break; + } + } + if (onion_services == NULL) { + control_write_endreply(conn, 552, "Unknown Onion Service id"); + } else { + int ret = -1; + switch (hs_version) { + case HS_VERSION_TWO: + ret = rend_service_del_ephemeral(service_id); + break; + case HS_VERSION_THREE: + ret = hs_service_del_ephemeral(service_id); + break; + default: + /* The ret value will be -1 thus hitting the warning below. This should + * never happen because of the check at the start of the function. */ + break; + } + if (ret < 0) { + /* This should *NEVER* fail, since the service is on either the + * per-control connection list, or the global one. + */ + log_warn(LD_BUG, "Failed to remove Onion Service %s.", + escaped(service_id)); + tor_fragile_assert(); + } + + /* Remove/scrub the service_id from the appropriate list. */ + char *cp = smartlist_get(onion_services, idx); + smartlist_del(onion_services, idx); + memwipe(cp, 0, strlen(cp)); + tor_free(cp); + + send_control_done(conn); + } + + out: + return 0; +} + +static const control_cmd_syntax_t obsolete_syntax = { + .max_args = UINT_MAX +}; + +/** + * Called when we get an obsolete command: tell the controller that it is + * obsolete. + */ +static int +handle_control_obsolete(control_connection_t *conn, + const control_cmd_args_t *args) +{ + (void)args; + char *command = tor_strdup(conn->current_cmd); + tor_strupper(command); + control_printf_endreply(conn, 511, "%s is obsolete.", command); + tor_free(command); + return 0; +} + +/** + * Function pointer to a handler function for a controller command. + **/ +typedef int (*handler_fn_t) (control_connection_t *conn, + const control_cmd_args_t *args); + +/** + * Definition for a controller command. + */ +typedef struct control_cmd_def_t { + /** + * The name of the command. If the command is multiline, the name must + * begin with "+". This is not case-sensitive. */ + const char *name; + /** + * A function to execute the command. + */ + handler_fn_t handler; + /** + * Zero or more CMD_FL_* flags, or'd together. + */ + unsigned flags; + /** + * For parsed command: a syntax description. + */ + const control_cmd_syntax_t *syntax; +} control_cmd_def_t; + +/** + * Indicates that the command's arguments are sensitive, and should be + * memwiped after use. + */ +#define CMD_FL_WIPE (1u<<0) + +/** Macro: declare a command with a one-line argument, a given set of flags, + * and a syntax definition. + **/ +#define ONE_LINE(name, flags) \ + { \ + #name, \ + handle_control_ ##name, \ + flags, \ + &name##_syntax, \ + } + +/** + * Macro: declare a command with a multi-line argument and a given set of + * flags. + **/ +#define MULTLINE(name, flags) \ + { "+"#name, \ + handle_control_ ##name, \ + flags, \ + &name##_syntax \ + } + +/** + * Macro: declare an obsolete command. (Obsolete commands give a different + * error than non-existent ones.) + **/ +#define OBSOLETE(name) \ + { #name, \ + handle_control_obsolete, \ + 0, \ + &obsolete_syntax, \ + } + +/** + * An array defining all the recognized controller commands. + **/ +static const control_cmd_def_t CONTROL_COMMANDS[] = +{ + ONE_LINE(setconf, 0), + ONE_LINE(resetconf, 0), + ONE_LINE(getconf, 0), + MULTLINE(loadconf, 0), + ONE_LINE(setevents, 0), + ONE_LINE(authenticate, CMD_FL_WIPE), + ONE_LINE(saveconf, 0), + ONE_LINE(signal, 0), + ONE_LINE(takeownership, 0), + ONE_LINE(dropownership, 0), + ONE_LINE(mapaddress, 0), + ONE_LINE(getinfo, 0), + ONE_LINE(extendcircuit, 0), + ONE_LINE(setcircuitpurpose, 0), + OBSOLETE(setrouterpurpose), + ONE_LINE(attachstream, 0), + MULTLINE(postdescriptor, 0), + ONE_LINE(redirectstream, 0), + ONE_LINE(closestream, 0), + ONE_LINE(closecircuit, 0), + ONE_LINE(usefeature, 0), + ONE_LINE(resolve, 0), + ONE_LINE(protocolinfo, 0), + ONE_LINE(authchallenge, CMD_FL_WIPE), + ONE_LINE(dropguards, 0), + ONE_LINE(hsfetch, 0), + MULTLINE(hspost, 0), + ONE_LINE(add_onion, CMD_FL_WIPE), + ONE_LINE(del_onion, CMD_FL_WIPE), +}; + +/** + * The number of entries in CONTROL_COMMANDS. + **/ +static const size_t N_CONTROL_COMMANDS = ARRAY_LENGTH(CONTROL_COMMANDS); + +/** + * Run a single control command, as defined by a control_cmd_def_t, + * with a given set of arguments. + */ +static int +handle_single_control_command(const control_cmd_def_t *def, + control_connection_t *conn, + uint32_t cmd_data_len, + char *args) +{ + int rv = 0; + + control_cmd_args_t *parsed_args; + char *err=NULL; + tor_assert(def->syntax); + parsed_args = control_cmd_parse_args(conn->current_cmd, + def->syntax, + cmd_data_len, args, + &err); + if (!parsed_args) { + control_printf_endreply(conn, 512, "Bad arguments to %s: %s", + conn->current_cmd, err?err:""); + tor_free(err); + } else { + if (BUG(err)) + tor_free(err); + if (def->handler(conn, parsed_args)) + rv = 0; + + if (def->flags & CMD_FL_WIPE) + control_cmd_args_wipe(parsed_args); + + control_cmd_args_free(parsed_args); + } + + if (def->flags & CMD_FL_WIPE) + memwipe(args, 0, cmd_data_len); + + return rv; +} + +/** + * Run a given controller command, as selected by the current_cmd field of + * conn. + */ +int +handle_control_command(control_connection_t *conn, + uint32_t cmd_data_len, + char *args) +{ + tor_assert(conn); + tor_assert(args); + tor_assert(args[cmd_data_len] == '\0'); + + for (unsigned i = 0; i < N_CONTROL_COMMANDS; ++i) { + const control_cmd_def_t *def = &CONTROL_COMMANDS[i]; + if (!strcasecmp(conn->current_cmd, def->name)) { + return handle_single_control_command(def, conn, cmd_data_len, args); + } + } + + control_printf_endreply(conn, 510, "Unrecognized command \"%s\"", + conn->current_cmd); + + return 0; +} + +void +control_cmd_free_all(void) +{ + if (detached_onion_services) { /* Free the detached onion services */ + SMARTLIST_FOREACH(detached_onion_services, char *, cp, tor_free(cp)); + smartlist_free(detached_onion_services); + } +} diff --git a/src/feature/control/control_cmd.h b/src/feature/control/control_cmd.h new file mode 100644 index 0000000000..5c3d1a1cec --- /dev/null +++ b/src/feature/control/control_cmd.h @@ -0,0 +1,112 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_cmd.h + * \brief Header file for control_cmd.c. + **/ + +#ifndef TOR_CONTROL_CMD_H +#define TOR_CONTROL_CMD_H + +#include "lib/malloc/malloc.h" + +int handle_control_command(control_connection_t *conn, + uint32_t cmd_data_len, + char *args); +void control_cmd_free_all(void); + +typedef struct control_cmd_args_t control_cmd_args_t; +void control_cmd_args_free_(control_cmd_args_t *args); +void control_cmd_args_wipe(control_cmd_args_t *args); + +#define control_cmd_args_free(v) \ + FREE_AND_NULL(control_cmd_args_t, control_cmd_args_free_, (v)) + +/** + * Definition for the syntax of a controller command, as parsed by + * control_cmd_parse_args. + * + * WORK IN PROGRESS: This structure is going to get more complex as this + * branch goes on. + **/ +typedef struct control_cmd_syntax_t { + /** + * Lowest number of positional arguments that this command accepts. + * 0 for "it's okay not to have positional arguments." + **/ + unsigned int min_args; + /** + * Highest number of positional arguments that this command accepts. + * UINT_MAX for no limit. + **/ + unsigned int max_args; + /** + * If true, we should parse options after the positional arguments + * as a set of unordered flags and key=value arguments. + * + * Requires that max_args is not UINT_MAX. + **/ + bool accept_keywords; + /** + * If accept_keywords is true, then only the keywords listed in this + * (NULL-terminated) array are valid keywords for this command. + **/ + const char **allowed_keywords; + /** + * If accept_keywords is true, this option is passed to kvline_parse() as + * its flags. + **/ + unsigned kvline_flags; + /** + * True iff this command wants to be followed by a multiline object. + **/ + bool want_cmddata; + /** + * True iff this command needs access to the raw body of the input. + * + * This should not be needed for pure commands; it is purely a legacy + * option. + **/ + bool store_raw_body; +} control_cmd_syntax_t; + +#ifdef CONTROL_CMD_PRIVATE +#include "lib/crypt_ops/crypto_ed25519.h" + +/* ADD_ONION secret key to create an ephemeral service. The command supports + * multiple versions so this union stores the key and passes it to the HS + * subsystem depending on the requested version. */ +typedef union add_onion_secret_key_t { + /* Hidden service v2 secret key. */ + crypto_pk_t *v2; + /* Hidden service v3 secret key. */ + ed25519_secret_key_t *v3; +} add_onion_secret_key_t; + +STATIC int add_onion_helper_keyarg(const char *arg, int discard_pk, + const char **key_new_alg_out, + char **key_new_blob_out, + add_onion_secret_key_t *decoded_key, + int *hs_version, char **err_msg_out); + +STATIC rend_authorized_client_t *add_onion_helper_clientauth(const char *arg, + int *created, char **err_msg_out); + +STATIC control_cmd_args_t *control_cmd_parse_args( + const char *command, + const control_cmd_syntax_t *syntax, + size_t body_len, + const char *body, + char **error_out); + +#endif /* defined(CONTROL_CMD_PRIVATE) */ + +#ifdef CONTROL_MODULE_PRIVATE +smartlist_t * get_detached_onion_services(void); +#endif /* defined(CONTROL_MODULE_PRIVATE) */ + +#endif /* !defined(TOR_CONTROL_CMD_H) */ diff --git a/src/feature/control/control_cmd_args_st.h b/src/feature/control/control_cmd_args_st.h new file mode 100644 index 0000000000..8d7a4f55b3 --- /dev/null +++ b/src/feature/control/control_cmd_args_st.h @@ -0,0 +1,52 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_cmd_args_st.h + * \brief Definition for control_cmd_args_t + **/ + +#ifndef TOR_CONTROL_CMD_ST_H +#define TOR_CONTROL_CMD_ST_H + +struct smartlist_t; +struct config_line_t; + +/** + * Parsed arguments for a control command. + * + * WORK IN PROGRESS: This structure is going to get more complex as this + * branch goes on. + **/ +struct control_cmd_args_t { + /** + * The command itself, as provided by the controller. Not owned by this + * structure. + **/ + const char *command; + /** + * Positional arguments to the command. + **/ + struct smartlist_t *args; + /** + * Keyword arguments to the command. + **/ + struct config_line_t *kwargs; + /** + * Number of bytes in cmddata; 0 if cmddata is not set. + **/ + size_t cmddata_len; + /** + * A multiline object passed with this command. + **/ + char *cmddata; + /** + * If set, a nul-terminated string containing the raw unparsed arguments. + **/ + const char *raw_body; +}; + +#endif /* !defined(TOR_CONTROL_CMD_ST_H) */ diff --git a/src/feature/control/control_connection_st.h b/src/feature/control/control_connection_st.h index 177a916257..c9164f03b3 100644 --- a/src/feature/control/control_connection_st.h +++ b/src/feature/control/control_connection_st.h @@ -40,7 +40,8 @@ struct control_connection_t { /** A control command that we're reading from the inbuf, but which has not * yet arrived completely. */ char *incoming_cmd; + /** The control command that we are currently processing. */ + char *current_cmd; }; -#endif - +#endif /* !defined(CONTROL_CONNECTION_ST_H) */ diff --git a/src/feature/control/control_events.c b/src/feature/control/control_events.c new file mode 100644 index 0000000000..9e0966ca54 --- /dev/null +++ b/src/feature/control/control_events.c @@ -0,0 +1,2318 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_events.c + * \brief Implement the event-reporting part of the controller API. + **/ + +#define CONTROL_MODULE_PRIVATE +#define CONTROL_EVENTS_PRIVATE +#define OCIRC_EVENT_PRIVATE + +#include "core/or/or.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/mainloop/mainloop.h" +#include "core/or/channeltls.h" +#include "core/or/circuitlist.h" +#include "core/or/command.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "core/or/reasons.h" +#include "feature/control/control.h" +#include "feature/control/control_events.h" +#include "feature/control/control_fmt.h" +#include "feature/control/control_proto.h" +#include "feature/dircommon/directory.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/routerinfo.h" + +#include "feature/control/control_connection_st.h" +#include "core/or/entry_connection_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "core/or/or_connection_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" + +#include "lib/evloop/compat_libevent.h" + +static void flush_queued_events_cb(mainloop_event_t *event, void *arg); +static void control_get_bytes_rw_last_sec(uint64_t *r, uint64_t *w); + +/** Yield true iff s is the state of a control_connection_t that has + * finished authentication and is accepting commands. */ +#define STATE_IS_OPEN(s) ((s) == CONTROL_CONN_STATE_OPEN) + +/** An event mask of all the events that any controller is interested in + * receiving. */ +static event_mask_t global_event_mask = 0; + +/** True iff we have disabled log messages from being sent to the controller */ +static int disable_log_messages = 0; + +/** Macro: true if any control connection is interested in events of type + * e. */ +#define EVENT_IS_INTERESTING(e) \ + (!! (global_event_mask & EVENT_MASK_(e))) + +/** Macro: true if any event from the bitfield 'e' is interesting. */ +#define ANY_EVENT_IS_INTERESTING(e) \ + (!! (global_event_mask & (e))) + +static void send_control_event_impl(uint16_t event, + const char *format, va_list ap) + CHECK_PRINTF(2,0); +static int control_event_status(int type, int severity, const char *format, + va_list args) + CHECK_PRINTF(3,0); + +static void send_control_event(uint16_t event, + const char *format, ...) + CHECK_PRINTF(2,3); + +/** Table mapping event values to their names. Used to implement SETEVENTS + * and GETINFO events/names, and to keep they in sync. */ +const struct control_event_t control_event_table[] = { + { EVENT_CIRCUIT_STATUS, "CIRC" }, + { EVENT_CIRCUIT_STATUS_MINOR, "CIRC_MINOR" }, + { EVENT_STREAM_STATUS, "STREAM" }, + { EVENT_OR_CONN_STATUS, "ORCONN" }, + { EVENT_BANDWIDTH_USED, "BW" }, + { EVENT_DEBUG_MSG, "DEBUG" }, + { EVENT_INFO_MSG, "INFO" }, + { EVENT_NOTICE_MSG, "NOTICE" }, + { EVENT_WARN_MSG, "WARN" }, + { EVENT_ERR_MSG, "ERR" }, + { EVENT_NEW_DESC, "NEWDESC" }, + { EVENT_ADDRMAP, "ADDRMAP" }, + { EVENT_DESCCHANGED, "DESCCHANGED" }, + { EVENT_NS, "NS" }, + { EVENT_STATUS_GENERAL, "STATUS_GENERAL" }, + { EVENT_STATUS_CLIENT, "STATUS_CLIENT" }, + { EVENT_STATUS_SERVER, "STATUS_SERVER" }, + { EVENT_GUARD, "GUARD" }, + { EVENT_STREAM_BANDWIDTH_USED, "STREAM_BW" }, + { EVENT_CLIENTS_SEEN, "CLIENTS_SEEN" }, + { EVENT_NEWCONSENSUS, "NEWCONSENSUS" }, + { EVENT_BUILDTIMEOUT_SET, "BUILDTIMEOUT_SET" }, + { EVENT_GOT_SIGNAL, "SIGNAL" }, + { EVENT_CONF_CHANGED, "CONF_CHANGED"}, + { EVENT_CONN_BW, "CONN_BW" }, + { EVENT_CELL_STATS, "CELL_STATS" }, + { EVENT_CIRC_BANDWIDTH_USED, "CIRC_BW" }, + { EVENT_TRANSPORT_LAUNCHED, "TRANSPORT_LAUNCHED" }, + { EVENT_HS_DESC, "HS_DESC" }, + { EVENT_HS_DESC_CONTENT, "HS_DESC_CONTENT" }, + { EVENT_NETWORK_LIVENESS, "NETWORK_LIVENESS" }, + { 0, NULL }, +}; + +/** Given a log severity, return the corresponding control event code. */ +static inline int +log_severity_to_event(int severity) +{ + switch (severity) { + case LOG_DEBUG: return EVENT_DEBUG_MSG; + case LOG_INFO: return EVENT_INFO_MSG; + case LOG_NOTICE: return EVENT_NOTICE_MSG; + case LOG_WARN: return EVENT_WARN_MSG; + case LOG_ERR: return EVENT_ERR_MSG; + default: return -1; + } +} + +/** Helper: clear bandwidth counters of all origin circuits. */ +static void +clear_circ_bw_fields(void) +{ + origin_circuit_t *ocirc; + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { + if (!CIRCUIT_IS_ORIGIN(circ)) + continue; + ocirc = TO_ORIGIN_CIRCUIT(circ); + ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0; + ocirc->n_overhead_written_circ_bw = ocirc->n_overhead_read_circ_bw = 0; + ocirc->n_delivered_written_circ_bw = ocirc->n_delivered_read_circ_bw = 0; + } + SMARTLIST_FOREACH_END(circ); +} + +/** Set global_event_mask* to the bitwise OR of each live control + * connection's event_mask field. */ +void +control_update_global_event_mask(void) +{ + smartlist_t *conns = get_connection_array(); + event_mask_t old_mask, new_mask; + old_mask = global_event_mask; + int any_old_per_sec_events = control_any_per_second_event_enabled(); + + global_event_mask = 0; + SMARTLIST_FOREACH(conns, connection_t *, _conn, + { + if (_conn->type == CONN_TYPE_CONTROL && + STATE_IS_OPEN(_conn->state)) { + control_connection_t *conn = TO_CONTROL_CONN(_conn); + global_event_mask |= conn->event_mask; + } + }); + + new_mask = global_event_mask; + + /* Handle the aftermath. Set up the log callback to tell us only what + * we want to hear...*/ + control_adjust_event_log_severity(); + + /* Macro: true if ev was false before and is true now. */ +#define NEWLY_ENABLED(ev) \ + (! (old_mask & (ev)) && (new_mask & (ev))) + + /* ...then, if we've started logging stream or circ bw, clear the + * appropriate fields. */ + if (NEWLY_ENABLED(EVENT_STREAM_BANDWIDTH_USED)) { + SMARTLIST_FOREACH(conns, connection_t *, conn, + { + if (conn->type == CONN_TYPE_AP) { + edge_connection_t *edge_conn = TO_EDGE_CONN(conn); + edge_conn->n_written = edge_conn->n_read = 0; + } + }); + } + if (NEWLY_ENABLED(EVENT_CIRC_BANDWIDTH_USED)) { + clear_circ_bw_fields(); + } + if (NEWLY_ENABLED(EVENT_BANDWIDTH_USED)) { + uint64_t r, w; + control_get_bytes_rw_last_sec(&r, &w); + } + if (any_old_per_sec_events != control_any_per_second_event_enabled()) { + rescan_periodic_events(get_options()); + } + +#undef NEWLY_ENABLED +} + +/** Given a control event code for a message event, return the corresponding + * log severity. */ +static inline int +event_to_log_severity(int event) +{ + switch (event) { + case EVENT_DEBUG_MSG: return LOG_DEBUG; + case EVENT_INFO_MSG: return LOG_INFO; + case EVENT_NOTICE_MSG: return LOG_NOTICE; + case EVENT_WARN_MSG: return LOG_WARN; + case EVENT_ERR_MSG: return LOG_ERR; + default: return -1; + } +} + +/** Adjust the log severities that result in control_event_logmsg being called + * to match the severity of log messages that any controllers are interested + * in. */ +void +control_adjust_event_log_severity(void) +{ + int i; + int min_log_event=EVENT_ERR_MSG, max_log_event=EVENT_DEBUG_MSG; + + for (i = EVENT_DEBUG_MSG; i <= EVENT_ERR_MSG; ++i) { + if (EVENT_IS_INTERESTING(i)) { + min_log_event = i; + break; + } + } + for (i = EVENT_ERR_MSG; i >= EVENT_DEBUG_MSG; --i) { + if (EVENT_IS_INTERESTING(i)) { + max_log_event = i; + break; + } + } + if (EVENT_IS_INTERESTING(EVENT_STATUS_GENERAL)) { + if (min_log_event > EVENT_NOTICE_MSG) + min_log_event = EVENT_NOTICE_MSG; + if (max_log_event < EVENT_ERR_MSG) + max_log_event = EVENT_ERR_MSG; + } + if (min_log_event <= max_log_event) + change_callback_log_severity(event_to_log_severity(min_log_event), + event_to_log_severity(max_log_event), + control_event_logmsg); + else + change_callback_log_severity(LOG_ERR, LOG_ERR, + control_event_logmsg); +} + +/** Return true iff the event with code c is being sent to any current + * control connection. This is useful if the amount of work needed to prepare + * to call the appropriate control_event_...() function is high. + */ +int +control_event_is_interesting(int event) +{ + return EVENT_IS_INTERESTING(event); +} + +/** Return true if any event that needs to fire once a second is enabled. */ +int +control_any_per_second_event_enabled(void) +{ + return ANY_EVENT_IS_INTERESTING( + EVENT_MASK_(EVENT_BANDWIDTH_USED) | + EVENT_MASK_(EVENT_CELL_STATS) | + EVENT_MASK_(EVENT_CIRC_BANDWIDTH_USED) | + EVENT_MASK_(EVENT_CONN_BW) | + EVENT_MASK_(EVENT_STREAM_BANDWIDTH_USED) + ); +} + +/* The value of 'get_bytes_read()' the previous time that + * control_get_bytes_rw_last_sec() as called. */ +static uint64_t stats_prev_n_read = 0; +/* The value of 'get_bytes_written()' the previous time that + * control_get_bytes_rw_last_sec() as called. */ +static uint64_t stats_prev_n_written = 0; + +/** + * Set n_read and n_written to the total number of bytes read + * and written by Tor since the last call to this function. + * + * Call this only from the main thread. + */ +static void +control_get_bytes_rw_last_sec(uint64_t *n_read, + uint64_t *n_written) +{ + const uint64_t stats_n_bytes_read = get_bytes_read(); + const uint64_t stats_n_bytes_written = get_bytes_written(); + + *n_read = stats_n_bytes_read - stats_prev_n_read; + *n_written = stats_n_bytes_written - stats_prev_n_written; + stats_prev_n_read = stats_n_bytes_read; + stats_prev_n_written = stats_n_bytes_written; +} + +/** + * Run all the controller events (if any) that are scheduled to trigger once + * per second. + */ +void +control_per_second_events(void) +{ + if (!control_any_per_second_event_enabled()) + return; + + uint64_t bytes_read, bytes_written; + control_get_bytes_rw_last_sec(&bytes_read, &bytes_written); + control_event_bandwidth_used((uint32_t)bytes_read,(uint32_t)bytes_written); + + control_event_stream_bandwidth_used(); + control_event_conn_bandwidth_used(); + control_event_circ_bandwidth_used(); + control_event_circuit_cell_stats(); +} + +/** Represents an event that's queued to be sent to one or more + * controllers. */ +typedef struct queued_event_s { + uint16_t event; + char *msg; +} queued_event_t; + +/** Pointer to int. If this is greater than 0, we don't allow new events to be + * queued. */ +static tor_threadlocal_t block_event_queue_flag; + +/** Holds a smartlist of queued_event_t objects that may need to be sent + * to one or more controllers */ +static smartlist_t *queued_control_events = NULL; + +/** True if the flush_queued_events_event is pending. */ +static int flush_queued_event_pending = 0; + +/** Lock to protect the above fields. */ +static tor_mutex_t *queued_control_events_lock = NULL; + +/** An event that should fire in order to flush the contents of + * queued_control_events. */ +static mainloop_event_t *flush_queued_events_event = NULL; + +void +control_initialize_event_queue(void) +{ + if (queued_control_events == NULL) { + queued_control_events = smartlist_new(); + } + + if (flush_queued_events_event == NULL) { + struct event_base *b = tor_libevent_get_base(); + if (b) { + flush_queued_events_event = + mainloop_event_new(flush_queued_events_cb, NULL); + tor_assert(flush_queued_events_event); + } + } + + if (queued_control_events_lock == NULL) { + queued_control_events_lock = tor_mutex_new(); + tor_threadlocal_init(&block_event_queue_flag); + } +} + +static int * +get_block_event_queue(void) +{ + int *val = tor_threadlocal_get(&block_event_queue_flag); + if (PREDICT_UNLIKELY(val == NULL)) { + val = tor_malloc_zero(sizeof(int)); + tor_threadlocal_set(&block_event_queue_flag, val); + } + return val; +} + +/** Helper: inserts an event on the list of events queued to be sent to + * one or more controllers, and schedules the events to be flushed if needed. + * + * This function takes ownership of msg, and may free it. + * + * We queue these events rather than send them immediately in order to break + * the dependency in our callgraph from code that generates events for the + * controller, and the network layer at large. Otherwise, nearly every + * interesting part of Tor would potentially call every other interesting part + * of Tor. + */ +MOCK_IMPL(STATIC void, +queue_control_event_string,(uint16_t event, char *msg)) +{ + /* This is redundant with checks done elsewhere, but it's a last-ditch + * attempt to avoid queueing something we shouldn't have to queue. */ + if (PREDICT_UNLIKELY( ! EVENT_IS_INTERESTING(event) )) { + tor_free(msg); + return; + } + + int *block_event_queue = get_block_event_queue(); + if (*block_event_queue) { + tor_free(msg); + return; + } + + queued_event_t *ev = tor_malloc(sizeof(*ev)); + ev->event = event; + ev->msg = msg; + + /* No queueing an event while queueing an event */ + ++*block_event_queue; + + tor_mutex_acquire(queued_control_events_lock); + tor_assert(queued_control_events); + smartlist_add(queued_control_events, ev); + + int activate_event = 0; + if (! flush_queued_event_pending && in_main_thread()) { + activate_event = 1; + flush_queued_event_pending = 1; + } + + tor_mutex_release(queued_control_events_lock); + + --*block_event_queue; + + /* We just put an event on the queue; mark the queue to be + * flushed. We only do this from the main thread for now; otherwise, + * we'd need to incur locking overhead in Libevent or use a socket. + */ + if (activate_event) { + tor_assert(flush_queued_events_event); + mainloop_event_activate(flush_queued_events_event); + } +} + +#define queued_event_free(ev) \ + FREE_AND_NULL(queued_event_t, queued_event_free_, (ev)) + +/** Release all storage held by ev. */ +static void +queued_event_free_(queued_event_t *ev) +{ + if (ev == NULL) + return; + + tor_free(ev->msg); + tor_free(ev); +} + +/** Send every queued event to every controller that's interested in it, + * and remove the events from the queue. If force is true, + * then make all controllers send their data out immediately, since we + * may be about to shut down. */ +static void +queued_events_flush_all(int force) +{ + /* Make sure that we get all the pending log events, if there are any. */ + flush_pending_log_callbacks(); + + if (PREDICT_UNLIKELY(queued_control_events == NULL)) { + return; + } + smartlist_t *all_conns = get_connection_array(); + smartlist_t *controllers = smartlist_new(); + smartlist_t *queued_events; + + int *block_event_queue = get_block_event_queue(); + ++*block_event_queue; + + tor_mutex_acquire(queued_control_events_lock); + /* No queueing an event while flushing events. */ + flush_queued_event_pending = 0; + queued_events = queued_control_events; + queued_control_events = smartlist_new(); + tor_mutex_release(queued_control_events_lock); + + /* Gather all the controllers that will care... */ + SMARTLIST_FOREACH_BEGIN(all_conns, connection_t *, conn) { + if (conn->type == CONN_TYPE_CONTROL && + !conn->marked_for_close && + conn->state == CONTROL_CONN_STATE_OPEN) { + control_connection_t *control_conn = TO_CONTROL_CONN(conn); + + smartlist_add(controllers, control_conn); + } + } SMARTLIST_FOREACH_END(conn); + + SMARTLIST_FOREACH_BEGIN(queued_events, queued_event_t *, ev) { + const event_mask_t bit = ((event_mask_t)1) << ev->event; + const size_t msg_len = strlen(ev->msg); + SMARTLIST_FOREACH_BEGIN(controllers, control_connection_t *, + control_conn) { + if (control_conn->event_mask & bit) { + connection_buf_add(ev->msg, msg_len, TO_CONN(control_conn)); + } + } SMARTLIST_FOREACH_END(control_conn); + + queued_event_free(ev); + } SMARTLIST_FOREACH_END(ev); + + if (force) { + SMARTLIST_FOREACH_BEGIN(controllers, control_connection_t *, + control_conn) { + connection_flush(TO_CONN(control_conn)); + } SMARTLIST_FOREACH_END(control_conn); + } + + smartlist_free(queued_events); + smartlist_free(controllers); + + --*block_event_queue; +} + +/** Libevent callback: Flushes pending events to controllers that are + * interested in them. */ +static void +flush_queued_events_cb(mainloop_event_t *event, void *arg) +{ + (void) event; + (void) arg; + queued_events_flush_all(0); +} + +/** Send an event to all v1 controllers that are listening for code + * event. The event's body is given by msg. + * + * The EXTENDED_FORMAT and NONEXTENDED_FORMAT flags behave similarly with + * respect to the EXTENDED_EVENTS feature. */ +MOCK_IMPL(STATIC void, +send_control_event_string,(uint16_t event, + const char *msg)) +{ + tor_assert(event >= EVENT_MIN_ && event <= EVENT_MAX_); + queue_control_event_string(event, tor_strdup(msg)); +} + +/** Helper for send_control_event and control_event_status: + * Send an event to all v1 controllers that are listening for code + * event. The event's body is created by the printf-style format in + * format, and other arguments as provided. */ +static void +send_control_event_impl(uint16_t event, + const char *format, va_list ap) +{ + char *buf = NULL; + int len; + + len = tor_vasprintf(&buf, format, ap); + if (len < 0) { + log_warn(LD_BUG, "Unable to format event for controller."); + return; + } + + queue_control_event_string(event, buf); +} + +/** Send an event to all v1 controllers that are listening for code + * event. The event's body is created by the printf-style format in + * format, and other arguments as provided. */ +static void +send_control_event(uint16_t event, + const char *format, ...) +{ + va_list ap; + va_start(ap, format); + send_control_event_impl(event, format, ap); + va_end(ap); +} + +/** Something major has happened to circuit circ: tell any + * interested control connections. */ +int +control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp, + int reason_code) +{ + const char *status; + char reasons[64] = ""; + + if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS)) + return 0; + tor_assert(circ); + + switch (tp) + { + case CIRC_EVENT_LAUNCHED: status = "LAUNCHED"; break; + case CIRC_EVENT_BUILT: status = "BUILT"; break; + case CIRC_EVENT_EXTENDED: status = "EXTENDED"; break; + case CIRC_EVENT_FAILED: status = "FAILED"; break; + case CIRC_EVENT_CLOSED: status = "CLOSED"; break; + default: + log_warn(LD_BUG, "Unrecognized status code %d", (int)tp); + tor_fragile_assert(); + return 0; + } + + if (tp == CIRC_EVENT_FAILED || tp == CIRC_EVENT_CLOSED) { + const char *reason_str = circuit_end_reason_to_control_string(reason_code); + char unk_reason_buf[16]; + if (!reason_str) { + tor_snprintf(unk_reason_buf, 16, "UNKNOWN_%d", reason_code); + reason_str = unk_reason_buf; + } + if (reason_code > 0 && reason_code & END_CIRC_REASON_FLAG_REMOTE) { + tor_snprintf(reasons, sizeof(reasons), + " REASON=DESTROYED REMOTE_REASON=%s", reason_str); + } else { + tor_snprintf(reasons, sizeof(reasons), + " REASON=%s", reason_str); + } + } + + { + char *circdesc = circuit_describe_status_for_controller(circ); + const char *sp = strlen(circdesc) ? " " : ""; + send_control_event(EVENT_CIRCUIT_STATUS, + "650 CIRC %lu %s%s%s%s\r\n", + (unsigned long)circ->global_identifier, + status, sp, + circdesc, + reasons); + tor_free(circdesc); + } + + return 0; +} + +/** Something minor has happened to circuit circ: tell any + * interested control connections. */ +static int +control_event_circuit_status_minor(origin_circuit_t *circ, + circuit_status_minor_event_t e, + int purpose, const struct timeval *tv) +{ + const char *event_desc; + char event_tail[160] = ""; + if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS_MINOR)) + return 0; + tor_assert(circ); + + switch (e) + { + case CIRC_MINOR_EVENT_PURPOSE_CHANGED: + event_desc = "PURPOSE_CHANGED"; + + { + /* event_tail can currently be up to 68 chars long */ + const char *hs_state_str = + circuit_purpose_to_controller_hs_state_string(purpose); + tor_snprintf(event_tail, sizeof(event_tail), + " OLD_PURPOSE=%s%s%s", + circuit_purpose_to_controller_string(purpose), + (hs_state_str != NULL) ? " OLD_HS_STATE=" : "", + (hs_state_str != NULL) ? hs_state_str : ""); + } + + break; + case CIRC_MINOR_EVENT_CANNIBALIZED: + event_desc = "CANNIBALIZED"; + + { + /* event_tail can currently be up to 130 chars long */ + const char *hs_state_str = + circuit_purpose_to_controller_hs_state_string(purpose); + const struct timeval *old_timestamp_began = tv; + char tbuf[ISO_TIME_USEC_LEN+1]; + format_iso_time_nospace_usec(tbuf, old_timestamp_began); + + tor_snprintf(event_tail, sizeof(event_tail), + " OLD_PURPOSE=%s%s%s OLD_TIME_CREATED=%s", + circuit_purpose_to_controller_string(purpose), + (hs_state_str != NULL) ? " OLD_HS_STATE=" : "", + (hs_state_str != NULL) ? hs_state_str : "", + tbuf); + } + + break; + default: + log_warn(LD_BUG, "Unrecognized status code %d", (int)e); + tor_fragile_assert(); + return 0; + } + + { + char *circdesc = circuit_describe_status_for_controller(circ); + const char *sp = strlen(circdesc) ? " " : ""; + send_control_event(EVENT_CIRCUIT_STATUS_MINOR, + "650 CIRC_MINOR %lu %s%s%s%s\r\n", + (unsigned long)circ->global_identifier, + event_desc, sp, + circdesc, + event_tail); + tor_free(circdesc); + } + + return 0; +} + +/** + * circ has changed its purpose from old_purpose: tell any + * interested controllers. + */ +int +control_event_circuit_purpose_changed(origin_circuit_t *circ, + int old_purpose) +{ + return control_event_circuit_status_minor(circ, + CIRC_MINOR_EVENT_PURPOSE_CHANGED, + old_purpose, + NULL); +} + +/** + * circ has changed its purpose from old_purpose, and its + * created-time from old_tv_created: tell any interested controllers. + */ +int +control_event_circuit_cannibalized(origin_circuit_t *circ, + int old_purpose, + const struct timeval *old_tv_created) +{ + return control_event_circuit_status_minor(circ, + CIRC_MINOR_EVENT_CANNIBALIZED, + old_purpose, + old_tv_created); +} + +/** Something has happened to the stream associated with AP connection + * conn: tell any interested control connections. */ +int +control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp, + int reason_code) +{ + char reason_buf[64]; + char addrport_buf[64]; + const char *status; + circuit_t *circ; + origin_circuit_t *origin_circ = NULL; + char buf[256]; + const char *purpose = ""; + tor_assert(conn->socks_request); + + if (!EVENT_IS_INTERESTING(EVENT_STREAM_STATUS)) + return 0; + + if (tp == STREAM_EVENT_CLOSED && + (reason_code & END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED)) + return 0; + + write_stream_target_to_buf(conn, buf, sizeof(buf)); + + reason_buf[0] = '\0'; + switch (tp) + { + case STREAM_EVENT_SENT_CONNECT: status = "SENTCONNECT"; break; + case STREAM_EVENT_SENT_RESOLVE: status = "SENTRESOLVE"; break; + case STREAM_EVENT_SUCCEEDED: status = "SUCCEEDED"; break; + case STREAM_EVENT_FAILED: status = "FAILED"; break; + case STREAM_EVENT_CLOSED: status = "CLOSED"; break; + case STREAM_EVENT_NEW: status = "NEW"; break; + case STREAM_EVENT_NEW_RESOLVE: status = "NEWRESOLVE"; break; + case STREAM_EVENT_FAILED_RETRIABLE: status = "DETACHED"; break; + case STREAM_EVENT_REMAP: status = "REMAP"; break; + default: + log_warn(LD_BUG, "Unrecognized status code %d", (int)tp); + return 0; + } + if (reason_code && (tp == STREAM_EVENT_FAILED || + tp == STREAM_EVENT_CLOSED || + tp == STREAM_EVENT_FAILED_RETRIABLE)) { + const char *reason_str = stream_end_reason_to_control_string(reason_code); + char *r = NULL; + if (!reason_str) { + tor_asprintf(&r, " UNKNOWN_%d", reason_code); + reason_str = r; + } + if (reason_code & END_STREAM_REASON_FLAG_REMOTE) + tor_snprintf(reason_buf, sizeof(reason_buf), + " REASON=END REMOTE_REASON=%s", reason_str); + else + tor_snprintf(reason_buf, sizeof(reason_buf), + " REASON=%s", reason_str); + tor_free(r); + } else if (reason_code && tp == STREAM_EVENT_REMAP) { + switch (reason_code) { + case REMAP_STREAM_SOURCE_CACHE: + strlcpy(reason_buf, " SOURCE=CACHE", sizeof(reason_buf)); + break; + case REMAP_STREAM_SOURCE_EXIT: + strlcpy(reason_buf, " SOURCE=EXIT", sizeof(reason_buf)); + break; + default: + tor_snprintf(reason_buf, sizeof(reason_buf), " REASON=UNKNOWN_%d", + reason_code); + /* XXX do we want SOURCE=UNKNOWN_%d above instead? -RD */ + break; + } + } + + if (tp == STREAM_EVENT_NEW || tp == STREAM_EVENT_NEW_RESOLVE) { + /* + * When the control conn is an AF_UNIX socket and we have no address, + * it gets set to "(Tor_internal)"; see dnsserv_launch_request() in + * dnsserv.c. + */ + if (strcmp(ENTRY_TO_CONN(conn)->address, "(Tor_internal)") != 0) { + tor_snprintf(addrport_buf,sizeof(addrport_buf), " SOURCE_ADDR=%s:%d", + ENTRY_TO_CONN(conn)->address, ENTRY_TO_CONN(conn)->port); + } else { + /* + * else leave it blank so control on AF_UNIX doesn't need to make + * something up. + */ + addrport_buf[0] = '\0'; + } + } else { + addrport_buf[0] = '\0'; + } + + if (tp == STREAM_EVENT_NEW_RESOLVE) { + purpose = " PURPOSE=DNS_REQUEST"; + } else if (tp == STREAM_EVENT_NEW) { + if (conn->use_begindir) { + connection_t *linked = ENTRY_TO_CONN(conn)->linked_conn; + int linked_dir_purpose = -1; + if (linked && linked->type == CONN_TYPE_DIR) + linked_dir_purpose = linked->purpose; + if (DIR_PURPOSE_IS_UPLOAD(linked_dir_purpose)) + purpose = " PURPOSE=DIR_UPLOAD"; + else + purpose = " PURPOSE=DIR_FETCH"; + } else + purpose = " PURPOSE=USER"; + } + + circ = circuit_get_by_edge_conn(ENTRY_TO_EDGE_CONN(conn)); + if (circ && CIRCUIT_IS_ORIGIN(circ)) + origin_circ = TO_ORIGIN_CIRCUIT(circ); + send_control_event(EVENT_STREAM_STATUS, + "650 STREAM %"PRIu64" %s %lu %s%s%s%s\r\n", + (ENTRY_TO_CONN(conn)->global_identifier), + status, + origin_circ? + (unsigned long)origin_circ->global_identifier : 0ul, + buf, reason_buf, addrport_buf, purpose); + + /* XXX need to specify its intended exit, etc? */ + + return 0; +} + +/** Called when the status of an OR connection conn changes: tell any + * interested control connections. tp is the new status for the + * connection. If conn has just closed or failed, then reason + * may be the reason why. + */ +int +control_event_or_conn_status(or_connection_t *conn, or_conn_status_event_t tp, + int reason) +{ + int ncircs = 0; + const char *status; + char name[128]; + char ncircs_buf[32] = {0}; /* > 8 + log10(2^32)=10 + 2 */ + + if (!EVENT_IS_INTERESTING(EVENT_OR_CONN_STATUS)) + return 0; + + switch (tp) + { + case OR_CONN_EVENT_LAUNCHED: status = "LAUNCHED"; break; + case OR_CONN_EVENT_CONNECTED: status = "CONNECTED"; break; + case OR_CONN_EVENT_FAILED: status = "FAILED"; break; + case OR_CONN_EVENT_CLOSED: status = "CLOSED"; break; + case OR_CONN_EVENT_NEW: status = "NEW"; break; + default: + log_warn(LD_BUG, "Unrecognized status code %d", (int)tp); + return 0; + } + if (conn->chan) { + ncircs = circuit_count_pending_on_channel(TLS_CHAN_TO_BASE(conn->chan)); + } else { + ncircs = 0; + } + ncircs += connection_or_get_num_circuits(conn); + if (ncircs && (tp == OR_CONN_EVENT_FAILED || tp == OR_CONN_EVENT_CLOSED)) { + tor_snprintf(ncircs_buf, sizeof(ncircs_buf), " NCIRCS=%d", ncircs); + } + + orconn_target_get_name(name, sizeof(name), conn); + send_control_event(EVENT_OR_CONN_STATUS, + "650 ORCONN %s %s%s%s%s ID=%"PRIu64"\r\n", + name, status, + reason ? " REASON=" : "", + orconn_end_reason_to_control_string(reason), + ncircs_buf, + (conn->base_.global_identifier)); + + return 0; +} + +/** + * Print out STREAM_BW event for a single conn + */ +int +control_event_stream_bandwidth(edge_connection_t *edge_conn) +{ + struct timeval now; + char tbuf[ISO_TIME_USEC_LEN+1]; + if (EVENT_IS_INTERESTING(EVENT_STREAM_BANDWIDTH_USED)) { + if (!edge_conn->n_read && !edge_conn->n_written) + return 0; + + tor_gettimeofday(&now); + format_iso_time_nospace_usec(tbuf, &now); + send_control_event(EVENT_STREAM_BANDWIDTH_USED, + "650 STREAM_BW %"PRIu64" %lu %lu %s\r\n", + (edge_conn->base_.global_identifier), + (unsigned long)edge_conn->n_read, + (unsigned long)edge_conn->n_written, + tbuf); + + edge_conn->n_written = edge_conn->n_read = 0; + } + + return 0; +} + +/** A second or more has elapsed: tell any interested control + * connections how much bandwidth streams have used. */ +int +control_event_stream_bandwidth_used(void) +{ + if (EVENT_IS_INTERESTING(EVENT_STREAM_BANDWIDTH_USED)) { + smartlist_t *conns = get_connection_array(); + edge_connection_t *edge_conn; + struct timeval now; + char tbuf[ISO_TIME_USEC_LEN+1]; + + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) + { + if (conn->type != CONN_TYPE_AP) + continue; + edge_conn = TO_EDGE_CONN(conn); + if (!edge_conn->n_read && !edge_conn->n_written) + continue; + + tor_gettimeofday(&now); + format_iso_time_nospace_usec(tbuf, &now); + send_control_event(EVENT_STREAM_BANDWIDTH_USED, + "650 STREAM_BW %"PRIu64" %lu %lu %s\r\n", + (edge_conn->base_.global_identifier), + (unsigned long)edge_conn->n_read, + (unsigned long)edge_conn->n_written, + tbuf); + + edge_conn->n_written = edge_conn->n_read = 0; + } + SMARTLIST_FOREACH_END(conn); + } + + return 0; +} + +/** A second or more has elapsed: tell any interested control connections + * how much bandwidth origin circuits have used. */ +int +control_event_circ_bandwidth_used(void) +{ + if (!EVENT_IS_INTERESTING(EVENT_CIRC_BANDWIDTH_USED)) + return 0; + + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { + if (!CIRCUIT_IS_ORIGIN(circ)) + continue; + + control_event_circ_bandwidth_used_for_circ(TO_ORIGIN_CIRCUIT(circ)); + } + SMARTLIST_FOREACH_END(circ); + + return 0; +} + +/** + * Emit a CIRC_BW event line for a specific circuit. + * + * This function sets the values it emits to 0, and does not emit + * an event if there is no new data to report since the last call. + * + * Therefore, it may be called at any frequency. + */ +int +control_event_circ_bandwidth_used_for_circ(origin_circuit_t *ocirc) +{ + struct timeval now; + char tbuf[ISO_TIME_USEC_LEN+1]; + + tor_assert(ocirc); + + if (!EVENT_IS_INTERESTING(EVENT_CIRC_BANDWIDTH_USED)) + return 0; + + /* n_read_circ_bw and n_written_circ_bw are always updated + * when there is any new cell on a circuit, and set to 0 after + * the event, below. + * + * Therefore, checking them is sufficient to determine if there + * is new data to report. */ + if (!ocirc->n_read_circ_bw && !ocirc->n_written_circ_bw) + return 0; + + tor_gettimeofday(&now); + format_iso_time_nospace_usec(tbuf, &now); + send_control_event(EVENT_CIRC_BANDWIDTH_USED, + "650 CIRC_BW ID=%d READ=%lu WRITTEN=%lu TIME=%s " + "DELIVERED_READ=%lu OVERHEAD_READ=%lu " + "DELIVERED_WRITTEN=%lu OVERHEAD_WRITTEN=%lu\r\n", + ocirc->global_identifier, + (unsigned long)ocirc->n_read_circ_bw, + (unsigned long)ocirc->n_written_circ_bw, + tbuf, + (unsigned long)ocirc->n_delivered_read_circ_bw, + (unsigned long)ocirc->n_overhead_read_circ_bw, + (unsigned long)ocirc->n_delivered_written_circ_bw, + (unsigned long)ocirc->n_overhead_written_circ_bw); + ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0; + ocirc->n_overhead_written_circ_bw = ocirc->n_overhead_read_circ_bw = 0; + ocirc->n_delivered_written_circ_bw = ocirc->n_delivered_read_circ_bw = 0; + + return 0; +} + +/** Print out CONN_BW event for a single OR/DIR/EXIT conn and reset + * bandwidth counters. */ +int +control_event_conn_bandwidth(connection_t *conn) +{ + const char *conn_type_str; + if (!get_options()->TestingEnableConnBwEvent || + !EVENT_IS_INTERESTING(EVENT_CONN_BW)) + return 0; + if (!conn->n_read_conn_bw && !conn->n_written_conn_bw) + return 0; + switch (conn->type) { + case CONN_TYPE_OR: + conn_type_str = "OR"; + break; + case CONN_TYPE_DIR: + conn_type_str = "DIR"; + break; + case CONN_TYPE_EXIT: + conn_type_str = "EXIT"; + break; + default: + return 0; + } + send_control_event(EVENT_CONN_BW, + "650 CONN_BW ID=%"PRIu64" TYPE=%s " + "READ=%lu WRITTEN=%lu\r\n", + (conn->global_identifier), + conn_type_str, + (unsigned long)conn->n_read_conn_bw, + (unsigned long)conn->n_written_conn_bw); + conn->n_written_conn_bw = conn->n_read_conn_bw = 0; + return 0; +} + +/** A second or more has elapsed: tell any interested control + * connections how much bandwidth connections have used. */ +int +control_event_conn_bandwidth_used(void) +{ + if (get_options()->TestingEnableConnBwEvent && + EVENT_IS_INTERESTING(EVENT_CONN_BW)) { + SMARTLIST_FOREACH(get_connection_array(), connection_t *, conn, + control_event_conn_bandwidth(conn)); + } + return 0; +} + +/** Helper: iterate over cell statistics of circ and sum up added + * cells, removed cells, and waiting times by cell command and direction. + * Store results in cell_stats. Free cell statistics of the + * circuit afterwards. */ +void +sum_up_cell_stats_by_command(circuit_t *circ, cell_stats_t *cell_stats) +{ + memset(cell_stats, 0, sizeof(cell_stats_t)); + SMARTLIST_FOREACH_BEGIN(circ->testing_cell_stats, + const testing_cell_stats_entry_t *, ent) { + tor_assert(ent->command <= CELL_COMMAND_MAX_); + if (!ent->removed && !ent->exitward) { + cell_stats->added_cells_appward[ent->command] += 1; + } else if (!ent->removed && ent->exitward) { + cell_stats->added_cells_exitward[ent->command] += 1; + } else if (!ent->exitward) { + cell_stats->removed_cells_appward[ent->command] += 1; + cell_stats->total_time_appward[ent->command] += ent->waiting_time * 10; + } else { + cell_stats->removed_cells_exitward[ent->command] += 1; + cell_stats->total_time_exitward[ent->command] += ent->waiting_time * 10; + } + } SMARTLIST_FOREACH_END(ent); + circuit_clear_testing_cell_stats(circ); +} + +/** Helper: append a cell statistics string to event_parts, + * prefixed with key=. Statistics consist of comma-separated + * key:value pairs with lower-case command strings as keys and cell + * numbers or total waiting times as values. A key:value pair is included + * if the entry in include_if_non_zero is not zero, but with + * the (possibly zero) entry from number_to_include. Both + * arrays are expected to have a length of CELL_COMMAND_MAX_ + 1. If no + * entry in include_if_non_zero is positive, no string will + * be added to event_parts. */ +void +append_cell_stats_by_command(smartlist_t *event_parts, const char *key, + const uint64_t *include_if_non_zero, + const uint64_t *number_to_include) +{ + smartlist_t *key_value_strings = smartlist_new(); + int i; + for (i = 0; i <= CELL_COMMAND_MAX_; i++) { + if (include_if_non_zero[i] > 0) { + smartlist_add_asprintf(key_value_strings, "%s:%"PRIu64, + cell_command_to_string(i), + (number_to_include[i])); + } + } + if (smartlist_len(key_value_strings) > 0) { + char *joined = smartlist_join_strings(key_value_strings, ",", 0, NULL); + smartlist_add_asprintf(event_parts, "%s=%s", key, joined); + SMARTLIST_FOREACH(key_value_strings, char *, cp, tor_free(cp)); + tor_free(joined); + } + smartlist_free(key_value_strings); +} + +/** Helper: format cell_stats for circ for inclusion in a + * CELL_STATS event and write result string to event_string. */ +void +format_cell_stats(char **event_string, circuit_t *circ, + cell_stats_t *cell_stats) +{ + smartlist_t *event_parts = smartlist_new(); + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + smartlist_add_asprintf(event_parts, "ID=%lu", + (unsigned long)ocirc->global_identifier); + } else if (TO_OR_CIRCUIT(circ)->p_chan) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + smartlist_add_asprintf(event_parts, "InboundQueue=%lu", + (unsigned long)or_circ->p_circ_id); + smartlist_add_asprintf(event_parts, "InboundConn=%"PRIu64, + (or_circ->p_chan->global_identifier)); + append_cell_stats_by_command(event_parts, "InboundAdded", + cell_stats->added_cells_appward, + cell_stats->added_cells_appward); + append_cell_stats_by_command(event_parts, "InboundRemoved", + cell_stats->removed_cells_appward, + cell_stats->removed_cells_appward); + append_cell_stats_by_command(event_parts, "InboundTime", + cell_stats->removed_cells_appward, + cell_stats->total_time_appward); + } + if (circ->n_chan) { + smartlist_add_asprintf(event_parts, "OutboundQueue=%lu", + (unsigned long)circ->n_circ_id); + smartlist_add_asprintf(event_parts, "OutboundConn=%"PRIu64, + (circ->n_chan->global_identifier)); + append_cell_stats_by_command(event_parts, "OutboundAdded", + cell_stats->added_cells_exitward, + cell_stats->added_cells_exitward); + append_cell_stats_by_command(event_parts, "OutboundRemoved", + cell_stats->removed_cells_exitward, + cell_stats->removed_cells_exitward); + append_cell_stats_by_command(event_parts, "OutboundTime", + cell_stats->removed_cells_exitward, + cell_stats->total_time_exitward); + } + *event_string = smartlist_join_strings(event_parts, " ", 0, NULL); + SMARTLIST_FOREACH(event_parts, char *, cp, tor_free(cp)); + smartlist_free(event_parts); +} + +/** A second or more has elapsed: tell any interested control connection + * how many cells have been processed for a given circuit. */ +int +control_event_circuit_cell_stats(void) +{ + cell_stats_t *cell_stats; + char *event_string; + if (!get_options()->TestingEnableCellStatsEvent || + !EVENT_IS_INTERESTING(EVENT_CELL_STATS)) + return 0; + cell_stats = tor_malloc(sizeof(cell_stats_t)); + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { + if (!circ->testing_cell_stats) + continue; + sum_up_cell_stats_by_command(circ, cell_stats); + format_cell_stats(&event_string, circ, cell_stats); + send_control_event(EVENT_CELL_STATS, + "650 CELL_STATS %s\r\n", event_string); + tor_free(event_string); + } + SMARTLIST_FOREACH_END(circ); + tor_free(cell_stats); + return 0; +} + +/* about 5 minutes worth. */ +#define N_BW_EVENTS_TO_CACHE 300 +/* Index into cached_bw_events to next write. */ +static int next_measurement_idx = 0; +/* number of entries set in n_measurements */ +static int n_measurements = 0; +static struct cached_bw_event_s { + uint32_t n_read; + uint32_t n_written; +} cached_bw_events[N_BW_EVENTS_TO_CACHE]; + +/** A second or more has elapsed: tell any interested control + * connections how much bandwidth we used. */ +int +control_event_bandwidth_used(uint32_t n_read, uint32_t n_written) +{ + cached_bw_events[next_measurement_idx].n_read = n_read; + cached_bw_events[next_measurement_idx].n_written = n_written; + if (++next_measurement_idx == N_BW_EVENTS_TO_CACHE) + next_measurement_idx = 0; + if (n_measurements < N_BW_EVENTS_TO_CACHE) + ++n_measurements; + + if (EVENT_IS_INTERESTING(EVENT_BANDWIDTH_USED)) { + send_control_event(EVENT_BANDWIDTH_USED, + "650 BW %lu %lu\r\n", + (unsigned long)n_read, + (unsigned long)n_written); + } + + return 0; +} + +char * +get_bw_samples(void) +{ + int i; + int idx = (next_measurement_idx + N_BW_EVENTS_TO_CACHE - n_measurements) + % N_BW_EVENTS_TO_CACHE; + tor_assert(0 <= idx && idx < N_BW_EVENTS_TO_CACHE); + + smartlist_t *elements = smartlist_new(); + + for (i = 0; i < n_measurements; ++i) { + tor_assert(0 <= idx && idx < N_BW_EVENTS_TO_CACHE); + const struct cached_bw_event_s *bwe = &cached_bw_events[idx]; + + smartlist_add_asprintf(elements, "%u,%u", + (unsigned)bwe->n_read, + (unsigned)bwe->n_written); + + idx = (idx + 1) % N_BW_EVENTS_TO_CACHE; + } + + char *result = smartlist_join_strings(elements, " ", 0, NULL); + + SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp)); + smartlist_free(elements); + + return result; +} + +/** Called when we are sending a log message to the controllers: suspend + * sending further log messages to the controllers until we're done. Used by + * CONN_LOG_PROTECT. */ +void +disable_control_logging(void) +{ + ++disable_log_messages; +} + +/** We're done sending a log message to the controllers: re-enable controller + * logging. Used by CONN_LOG_PROTECT. */ +void +enable_control_logging(void) +{ + if (--disable_log_messages < 0) + tor_assert(0); +} + +/** We got a log message: tell any interested control connections. */ +void +control_event_logmsg(int severity, log_domain_mask_t domain, const char *msg) +{ + int event; + + /* Don't even think of trying to add stuff to a buffer from a cpuworker + * thread. (See #25987 for plan to fix.) */ + if (! in_main_thread()) + return; + + if (disable_log_messages) + return; + + if (domain == LD_BUG && EVENT_IS_INTERESTING(EVENT_STATUS_GENERAL) && + severity <= LOG_NOTICE) { + char *esc = esc_for_log(msg); + ++disable_log_messages; + control_event_general_status(severity, "BUG REASON=%s", esc); + --disable_log_messages; + tor_free(esc); + } + + event = log_severity_to_event(severity); + if (event >= 0 && EVENT_IS_INTERESTING(event)) { + char *b = NULL; + const char *s; + if (strchr(msg, '\n')) { + char *cp; + b = tor_strdup(msg); + for (cp = b; *cp; ++cp) + if (*cp == '\r' || *cp == '\n') + *cp = ' '; + } + switch (severity) { + case LOG_DEBUG: s = "DEBUG"; break; + case LOG_INFO: s = "INFO"; break; + case LOG_NOTICE: s = "NOTICE"; break; + case LOG_WARN: s = "WARN"; break; + case LOG_ERR: s = "ERR"; break; + default: s = "UnknownLogSeverity"; break; + } + ++disable_log_messages; + send_control_event(event, "650 %s %s\r\n", s, b?b:msg); + if (severity == LOG_ERR) { + /* Force a flush, since we may be about to die horribly */ + queued_events_flush_all(1); + } + --disable_log_messages; + tor_free(b); + } +} + +/** + * Logging callback: called when there is a queued pending log callback. + */ +void +control_event_logmsg_pending(void) +{ + if (! in_main_thread()) { + /* We can't handle this case yet, since we're using a + * mainloop_event_t to invoke queued_events_flush_all. We ought to + * use a different mechanism instead: see #25987. + **/ + return; + } + tor_assert(flush_queued_events_event); + mainloop_event_activate(flush_queued_events_event); +} + +/** Called whenever we receive new router descriptors: tell any + * interested control connections. routers is a list of + * routerinfo_t's. + */ +int +control_event_descriptors_changed(smartlist_t *routers) +{ + char *msg; + + if (!EVENT_IS_INTERESTING(EVENT_NEW_DESC)) + return 0; + + { + smartlist_t *names = smartlist_new(); + char *ids; + SMARTLIST_FOREACH(routers, routerinfo_t *, ri, { + char *b = tor_malloc(MAX_VERBOSE_NICKNAME_LEN+1); + router_get_verbose_nickname(b, ri); + smartlist_add(names, b); + }); + ids = smartlist_join_strings(names, " ", 0, NULL); + tor_asprintf(&msg, "650 NEWDESC %s\r\n", ids); + send_control_event_string(EVENT_NEW_DESC, msg); + tor_free(ids); + tor_free(msg); + SMARTLIST_FOREACH(names, char *, cp, tor_free(cp)); + smartlist_free(names); + } + return 0; +} + +/** Called when an address mapping on from from changes to to. + * expires values less than 3 are special; see connection_edge.c. If + * error is non-NULL, it is an error code describing the failure + * mode of the mapping. + */ +int +control_event_address_mapped(const char *from, const char *to, time_t expires, + const char *error, const int cached) +{ + if (!EVENT_IS_INTERESTING(EVENT_ADDRMAP)) + return 0; + + if (expires < 3 || expires == TIME_MAX) + send_control_event(EVENT_ADDRMAP, + "650 ADDRMAP %s %s NEVER %s%s" + "CACHED=\"%s\"\r\n", + from, to, error?error:"", error?" ":"", + cached?"YES":"NO"); + else { + char buf[ISO_TIME_LEN+1]; + char buf2[ISO_TIME_LEN+1]; + format_local_iso_time(buf,expires); + format_iso_time(buf2,expires); + send_control_event(EVENT_ADDRMAP, + "650 ADDRMAP %s %s \"%s\"" + " %s%sEXPIRES=\"%s\" CACHED=\"%s\"\r\n", + from, to, buf, + error?error:"", error?" ":"", + buf2, cached?"YES":"NO"); + } + + return 0; +} +/** The network liveness has changed; this is called from circuitstats.c + * whenever we receive a cell, or when timeout expires and we assume the + * network is down. */ +int +control_event_network_liveness_update(int liveness) +{ + if (liveness > 0) { + if (get_cached_network_liveness() <= 0) { + /* Update cached liveness */ + set_cached_network_liveness(1); + log_debug(LD_CONTROL, "Sending NETWORK_LIVENESS UP"); + send_control_event_string(EVENT_NETWORK_LIVENESS, + "650 NETWORK_LIVENESS UP\r\n"); + } + /* else was already live, no-op */ + } else { + if (get_cached_network_liveness() > 0) { + /* Update cached liveness */ + set_cached_network_liveness(0); + log_debug(LD_CONTROL, "Sending NETWORK_LIVENESS DOWN"); + send_control_event_string(EVENT_NETWORK_LIVENESS, + "650 NETWORK_LIVENESS DOWN\r\n"); + } + /* else was already dead, no-op */ + } + + return 0; +} + +/** Helper function for NS-style events. Constructs and sends an event + * of type event with string event_string out of the set of + * networkstatuses statuses. Currently it is used for NS events + * and NEWCONSENSUS events. */ +static int +control_event_networkstatus_changed_helper(smartlist_t *statuses, + uint16_t event, + const char *event_string) +{ + smartlist_t *strs; + char *s, *esc = NULL; + if (!EVENT_IS_INTERESTING(event) || !smartlist_len(statuses)) + return 0; + + strs = smartlist_new(); + smartlist_add_strdup(strs, "650+"); + smartlist_add_strdup(strs, event_string); + smartlist_add_strdup(strs, "\r\n"); + SMARTLIST_FOREACH(statuses, const routerstatus_t *, rs, + { + s = networkstatus_getinfo_helper_single(rs); + if (!s) continue; + smartlist_add(strs, s); + }); + + s = smartlist_join_strings(strs, "", 0, NULL); + write_escaped_data(s, strlen(s), &esc); + SMARTLIST_FOREACH(strs, char *, cp, tor_free(cp)); + smartlist_free(strs); + tor_free(s); + send_control_event_string(event, esc); + send_control_event_string(event, + "650 OK\r\n"); + + tor_free(esc); + return 0; +} + +/** Called when the routerstatus_ts statuses have changed: sends + * an NS event to any controller that cares. */ +int +control_event_networkstatus_changed(smartlist_t *statuses) +{ + return control_event_networkstatus_changed_helper(statuses, EVENT_NS, "NS"); +} + +/** Called when we get a new consensus networkstatus. Sends a NEWCONSENSUS + * event consisting of an NS-style line for each relay in the consensus. */ +int +control_event_newconsensus(const networkstatus_t *consensus) +{ + if (!control_event_is_interesting(EVENT_NEWCONSENSUS)) + return 0; + return control_event_networkstatus_changed_helper( + consensus->routerstatus_list, EVENT_NEWCONSENSUS, "NEWCONSENSUS"); +} + +/** Called when we compute a new circuitbuildtimeout */ +int +control_event_buildtimeout_set(buildtimeout_set_event_t type, + const char *args) +{ + const char *type_string = NULL; + + if (!control_event_is_interesting(EVENT_BUILDTIMEOUT_SET)) + return 0; + + switch (type) { + case BUILDTIMEOUT_SET_EVENT_COMPUTED: + type_string = "COMPUTED"; + break; + case BUILDTIMEOUT_SET_EVENT_RESET: + type_string = "RESET"; + break; + case BUILDTIMEOUT_SET_EVENT_SUSPENDED: + type_string = "SUSPENDED"; + break; + case BUILDTIMEOUT_SET_EVENT_DISCARD: + type_string = "DISCARD"; + break; + case BUILDTIMEOUT_SET_EVENT_RESUME: + type_string = "RESUME"; + break; + default: + type_string = "UNKNOWN"; + break; + } + + send_control_event(EVENT_BUILDTIMEOUT_SET, + "650 BUILDTIMEOUT_SET %s %s\r\n", + type_string, args); + + return 0; +} + +/** Called when a signal has been processed from signal_callback */ +int +control_event_signal(uintptr_t signal_num) +{ + const char *signal_string = NULL; + + if (!control_event_is_interesting(EVENT_GOT_SIGNAL)) + return 0; + + switch (signal_num) { + case SIGHUP: + signal_string = "RELOAD"; + break; + case SIGUSR1: + signal_string = "DUMP"; + break; + case SIGUSR2: + signal_string = "DEBUG"; + break; + case SIGNEWNYM: + signal_string = "NEWNYM"; + break; + case SIGCLEARDNSCACHE: + signal_string = "CLEARDNSCACHE"; + break; + case SIGHEARTBEAT: + signal_string = "HEARTBEAT"; + break; + default: + log_warn(LD_BUG, "Unrecognized signal %lu in control_event_signal", + (unsigned long)signal_num); + return -1; + } + + send_control_event(EVENT_GOT_SIGNAL, "650 SIGNAL %s\r\n", + signal_string); + return 0; +} + +/** Called when a single local_routerstatus_t has changed: Sends an NS event + * to any controller that cares. */ +int +control_event_networkstatus_changed_single(const routerstatus_t *rs) +{ + smartlist_t *statuses; + int r; + + if (!EVENT_IS_INTERESTING(EVENT_NS)) + return 0; + + statuses = smartlist_new(); + smartlist_add(statuses, (void*)rs); + r = control_event_networkstatus_changed(statuses); + smartlist_free(statuses); + return r; +} + +/** Our own router descriptor has changed; tell any controllers that care. + */ +int +control_event_my_descriptor_changed(void) +{ + send_control_event(EVENT_DESCCHANGED, "650 DESCCHANGED\r\n"); + return 0; +} + +/** Helper: sends a status event where type is one of + * EVENT_STATUS_{GENERAL,CLIENT,SERVER}, where severity is one of + * LOG_{NOTICE,WARN,ERR}, and where format is a printf-style format + * string corresponding to args. */ +static int +control_event_status(int type, int severity, const char *format, va_list args) +{ + char *user_buf = NULL; + char format_buf[160]; + const char *status, *sev; + + switch (type) { + case EVENT_STATUS_GENERAL: + status = "STATUS_GENERAL"; + break; + case EVENT_STATUS_CLIENT: + status = "STATUS_CLIENT"; + break; + case EVENT_STATUS_SERVER: + status = "STATUS_SERVER"; + break; + default: + log_warn(LD_BUG, "Unrecognized status type %d", type); + return -1; + } + switch (severity) { + case LOG_NOTICE: + sev = "NOTICE"; + break; + case LOG_WARN: + sev = "WARN"; + break; + case LOG_ERR: + sev = "ERR"; + break; + default: + log_warn(LD_BUG, "Unrecognized status severity %d", severity); + return -1; + } + if (tor_snprintf(format_buf, sizeof(format_buf), "650 %s %s", + status, sev)<0) { + log_warn(LD_BUG, "Format string too long."); + return -1; + } + tor_vasprintf(&user_buf, format, args); + + send_control_event(type, "%s %s\r\n", format_buf, user_buf); + tor_free(user_buf); + return 0; +} + +#define CONTROL_EVENT_STATUS_BODY(event, sev) \ + int r; \ + do { \ + va_list ap; \ + if (!EVENT_IS_INTERESTING(event)) \ + return 0; \ + \ + va_start(ap, format); \ + r = control_event_status((event), (sev), format, ap); \ + va_end(ap); \ + } while (0) + +/** Format and send an EVENT_STATUS_GENERAL event whose main text is obtained + * by formatting the arguments using the printf-style format. */ +int +control_event_general_status(int severity, const char *format, ...) +{ + CONTROL_EVENT_STATUS_BODY(EVENT_STATUS_GENERAL, severity); + return r; +} + +/** Format and send an EVENT_STATUS_GENERAL LOG_ERR event, and flush it to the + * controller(s) immediately. */ +int +control_event_general_error(const char *format, ...) +{ + CONTROL_EVENT_STATUS_BODY(EVENT_STATUS_GENERAL, LOG_ERR); + /* Force a flush, since we may be about to die horribly */ + queued_events_flush_all(1); + return r; +} + +/** Format and send an EVENT_STATUS_CLIENT event whose main text is obtained + * by formatting the arguments using the printf-style format. */ +int +control_event_client_status(int severity, const char *format, ...) +{ + CONTROL_EVENT_STATUS_BODY(EVENT_STATUS_CLIENT, severity); + return r; +} + +/** Format and send an EVENT_STATUS_CLIENT LOG_ERR event, and flush it to the + * controller(s) immediately. */ +int +control_event_client_error(const char *format, ...) +{ + CONTROL_EVENT_STATUS_BODY(EVENT_STATUS_CLIENT, LOG_ERR); + /* Force a flush, since we may be about to die horribly */ + queued_events_flush_all(1); + return r; +} + +/** Format and send an EVENT_STATUS_SERVER event whose main text is obtained + * by formatting the arguments using the printf-style format. */ +int +control_event_server_status(int severity, const char *format, ...) +{ + CONTROL_EVENT_STATUS_BODY(EVENT_STATUS_SERVER, severity); + return r; +} + +/** Format and send an EVENT_STATUS_SERVER LOG_ERR event, and flush it to the + * controller(s) immediately. */ +int +control_event_server_error(const char *format, ...) +{ + CONTROL_EVENT_STATUS_BODY(EVENT_STATUS_SERVER, LOG_ERR); + /* Force a flush, since we may be about to die horribly */ + queued_events_flush_all(1); + return r; +} + +/** Called when the status of an entry guard with the given nickname + * and identity digest has changed to status: tells any + * controllers that care. */ +int +control_event_guard(const char *nickname, const char *digest, + const char *status) +{ + char hbuf[HEX_DIGEST_LEN+1]; + base16_encode(hbuf, sizeof(hbuf), digest, DIGEST_LEN); + if (!EVENT_IS_INTERESTING(EVENT_GUARD)) + return 0; + + { + char buf[MAX_VERBOSE_NICKNAME_LEN+1]; + const node_t *node = node_get_by_id(digest); + if (node) { + node_get_verbose_nickname(node, buf); + } else { + tor_snprintf(buf, sizeof(buf), "$%s~%s", hbuf, nickname); + } + send_control_event(EVENT_GUARD, + "650 GUARD ENTRY %s %s\r\n", buf, status); + } + return 0; +} + +/** Called when a configuration option changes. This is generally triggered + * by SETCONF requests and RELOAD/SIGHUP signals. The elements is + * a smartlist_t containing (key, value, ...) pairs in sequence. + * value can be NULL. */ +int +control_event_conf_changed(const smartlist_t *elements) +{ + int i; + char *result; + smartlist_t *lines; + if (!EVENT_IS_INTERESTING(EVENT_CONF_CHANGED) || + smartlist_len(elements) == 0) { + return 0; + } + lines = smartlist_new(); + for (i = 0; i < smartlist_len(elements); i += 2) { + char *k = smartlist_get(elements, i); + char *v = smartlist_get(elements, i+1); + if (v == NULL) { + smartlist_add_asprintf(lines, "650-%s", k); + } else { + smartlist_add_asprintf(lines, "650-%s=%s", k, v); + } + } + result = smartlist_join_strings(lines, "\r\n", 0, NULL); + send_control_event(EVENT_CONF_CHANGED, + "650-CONF_CHANGED\r\n%s\r\n650 OK\r\n", result); + tor_free(result); + SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); + smartlist_free(lines); + return 0; +} + +/** We just generated a new summary of which countries we've seen clients + * from recently. Send a copy to the controller in case it wants to + * display it for the user. */ +void +control_event_clients_seen(const char *controller_str) +{ + send_control_event(EVENT_CLIENTS_SEEN, + "650 CLIENTS_SEEN %s\r\n", controller_str); +} + +/** A new pluggable transport called transport_name was + * launched on addr:port. mode is either + * "server" or "client" depending on the mode of the pluggable + * transport. + * "650" SP "TRANSPORT_LAUNCHED" SP Mode SP Name SP Address SP Port + */ +void +control_event_transport_launched(const char *mode, const char *transport_name, + tor_addr_t *addr, uint16_t port) +{ + send_control_event(EVENT_TRANSPORT_LAUNCHED, + "650 TRANSPORT_LAUNCHED %s %s %s %u\r\n", + mode, transport_name, fmt_addr(addr), port); +} + +/** A pluggable transport called pt_name has emitted a log message + * found in message at severity log level. */ +void +control_event_pt_log(const char *log) +{ + send_control_event(EVENT_PT_LOG, + "650 PT_LOG %s\r\n", + log); +} + +/** A pluggable transport has emitted a STATUS message found in + * status. */ +void +control_event_pt_status(const char *status) +{ + send_control_event(EVENT_PT_STATUS, + "650 PT_STATUS %s\r\n", + status); +} + +/** Convert rendezvous auth type to string for HS_DESC control events + */ +const char * +rend_auth_type_to_string(rend_auth_type_t auth_type) +{ + const char *str; + + switch (auth_type) { + case REND_NO_AUTH: + str = "NO_AUTH"; + break; + case REND_BASIC_AUTH: + str = "BASIC_AUTH"; + break; + case REND_STEALTH_AUTH: + str = "STEALTH_AUTH"; + break; + default: + str = "UNKNOWN"; + } + + return str; +} + +/** Return either the onion address if the given pointer is a non empty + * string else the unknown string. */ +static const char * +rend_hsaddress_str_or_unknown(const char *onion_address) +{ + static const char *str_unknown = "UNKNOWN"; + const char *str_ret = str_unknown; + + /* No valid pointer, unknown it is. */ + if (!onion_address) { + goto end; + } + /* Empty onion address thus we don't know, unknown it is. */ + if (onion_address[0] == '\0') { + goto end; + } + /* All checks are good so return the given onion address. */ + str_ret = onion_address; + + end: + return str_ret; +} + +/** send HS_DESC requested event. + * + * rend_query is used to fetch requested onion address and auth type. + * hs_dir is the description of contacting hs directory. + * desc_id_base32 is the ID of requested hs descriptor. + * hsdir_index is the HSDir fetch index value for v3, an hex string. + */ +void +control_event_hs_descriptor_requested(const char *onion_address, + rend_auth_type_t auth_type, + const char *id_digest, + const char *desc_id, + const char *hsdir_index) +{ + char *hsdir_index_field = NULL; + + if (BUG(!id_digest || !desc_id)) { + return; + } + + if (hsdir_index) { + tor_asprintf(&hsdir_index_field, " HSDIR_INDEX=%s", hsdir_index); + } + + send_control_event(EVENT_HS_DESC, + "650 HS_DESC REQUESTED %s %s %s %s%s\r\n", + rend_hsaddress_str_or_unknown(onion_address), + rend_auth_type_to_string(auth_type), + node_describe_longname_by_id(id_digest), + desc_id, + hsdir_index_field ? hsdir_index_field : ""); + tor_free(hsdir_index_field); +} + +/** send HS_DESC CREATED event when a local service generates a descriptor. + * + * onion_address is service address. + * desc_id is the descriptor ID. + * replica is the the descriptor replica number. If it is negative, it + * is ignored. + */ +void +control_event_hs_descriptor_created(const char *onion_address, + const char *desc_id, + int replica) +{ + char *replica_field = NULL; + + if (BUG(!onion_address || !desc_id)) { + return; + } + + if (replica >= 0) { + tor_asprintf(&replica_field, " REPLICA=%d", replica); + } + + send_control_event(EVENT_HS_DESC, + "650 HS_DESC CREATED %s UNKNOWN UNKNOWN %s%s\r\n", + onion_address, desc_id, + replica_field ? replica_field : ""); + tor_free(replica_field); +} + +/** send HS_DESC upload event. + * + * onion_address is service address. + * hs_dir is the description of contacting hs directory. + * desc_id is the ID of requested hs descriptor. + */ +void +control_event_hs_descriptor_upload(const char *onion_address, + const char *id_digest, + const char *desc_id, + const char *hsdir_index) +{ + char *hsdir_index_field = NULL; + + if (BUG(!onion_address || !id_digest || !desc_id)) { + return; + } + + if (hsdir_index) { + tor_asprintf(&hsdir_index_field, " HSDIR_INDEX=%s", hsdir_index); + } + + send_control_event(EVENT_HS_DESC, + "650 HS_DESC UPLOAD %s UNKNOWN %s %s%s\r\n", + onion_address, + node_describe_longname_by_id(id_digest), + desc_id, + hsdir_index_field ? hsdir_index_field : ""); + tor_free(hsdir_index_field); +} + +/** send HS_DESC event after got response from hs directory. + * + * NOTE: this is an internal function used by following functions: + * control_event_hsv2_descriptor_received + * control_event_hsv2_descriptor_failed + * control_event_hsv3_descriptor_failed + * + * So do not call this function directly. + */ +static void +event_hs_descriptor_receive_end(const char *action, + const char *onion_address, + const char *desc_id, + rend_auth_type_t auth_type, + const char *hsdir_id_digest, + const char *reason) +{ + char *reason_field = NULL; + + if (BUG(!action || !onion_address)) { + return; + } + + if (reason) { + tor_asprintf(&reason_field, " REASON=%s", reason); + } + + send_control_event(EVENT_HS_DESC, + "650 HS_DESC %s %s %s %s%s%s\r\n", + action, + rend_hsaddress_str_or_unknown(onion_address), + rend_auth_type_to_string(auth_type), + hsdir_id_digest ? + node_describe_longname_by_id(hsdir_id_digest) : + "UNKNOWN", + desc_id ? desc_id : "", + reason_field ? reason_field : ""); + + tor_free(reason_field); +} + +/** send HS_DESC event after got response from hs directory. + * + * NOTE: this is an internal function used by following functions: + * control_event_hs_descriptor_uploaded + * control_event_hs_descriptor_upload_failed + * + * So do not call this function directly. + */ +void +control_event_hs_descriptor_upload_end(const char *action, + const char *onion_address, + const char *id_digest, + const char *reason) +{ + char *reason_field = NULL; + + if (BUG(!action || !id_digest)) { + return; + } + + if (reason) { + tor_asprintf(&reason_field, " REASON=%s", reason); + } + + send_control_event(EVENT_HS_DESC, + "650 HS_DESC %s %s UNKNOWN %s%s\r\n", + action, + rend_hsaddress_str_or_unknown(onion_address), + node_describe_longname_by_id(id_digest), + reason_field ? reason_field : ""); + + tor_free(reason_field); +} + +/** For an HS descriptor query rend_data, using the + * onion_address and HSDir fingerprint hsdir_fp, find out + * which descriptor ID in the query is the right one. + * + * Return a pointer of the binary descriptor ID found in the query's object + * or NULL if not found. */ +static const char * +get_desc_id_from_query(const rend_data_t *rend_data, const char *hsdir_fp) +{ + int replica; + const char *desc_id = NULL; + const rend_data_v2_t *rend_data_v2 = TO_REND_DATA_V2(rend_data); + + /* Possible if the fetch was done using a descriptor ID. This means that + * the HSFETCH command was used. */ + if (!tor_digest_is_zero(rend_data_v2->desc_id_fetch)) { + desc_id = rend_data_v2->desc_id_fetch; + goto end; + } + + /* Without a directory fingerprint at this stage, we can't do much. */ + if (hsdir_fp == NULL) { + goto end; + } + + /* OK, we have an onion address so now let's find which descriptor ID + * is the one associated with the HSDir fingerprint. */ + for (replica = 0; replica < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; + replica++) { + const char *digest = rend_data_get_desc_id(rend_data, replica, NULL); + + SMARTLIST_FOREACH_BEGIN(rend_data->hsdirs_fp, char *, fingerprint) { + if (tor_memcmp(fingerprint, hsdir_fp, DIGEST_LEN) == 0) { + /* Found it! This descriptor ID is the right one. */ + desc_id = digest; + goto end; + } + } SMARTLIST_FOREACH_END(fingerprint); + } + + end: + return desc_id; +} + +/** send HS_DESC RECEIVED event + * + * called when we successfully received a hidden service descriptor. + */ +void +control_event_hsv2_descriptor_received(const char *onion_address, + const rend_data_t *rend_data, + const char *hsdir_id_digest) +{ + char *desc_id_field = NULL; + const char *desc_id; + + if (BUG(!rend_data || !hsdir_id_digest || !onion_address)) { + return; + } + + desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest); + if (desc_id != NULL) { + char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; + /* Set the descriptor ID digest to base32 so we can send it. */ + base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id, + DIGEST_LEN); + /* Extra whitespace is needed before the value. */ + tor_asprintf(&desc_id_field, " %s", desc_id_base32); + } + + event_hs_descriptor_receive_end("RECEIVED", onion_address, desc_id_field, + TO_REND_DATA_V2(rend_data)->auth_type, + hsdir_id_digest, NULL); + tor_free(desc_id_field); +} + +/* Send HS_DESC RECEIVED event + * + * Called when we successfully received a hidden service descriptor. */ +void +control_event_hsv3_descriptor_received(const char *onion_address, + const char *desc_id, + const char *hsdir_id_digest) +{ + char *desc_id_field = NULL; + + if (BUG(!onion_address || !desc_id || !hsdir_id_digest)) { + return; + } + + /* Because DescriptorID is an optional positional value, we need to add a + * whitespace before in order to not be next to the HsDir value. */ + tor_asprintf(&desc_id_field, " %s", desc_id); + + event_hs_descriptor_receive_end("RECEIVED", onion_address, desc_id_field, + REND_NO_AUTH, hsdir_id_digest, NULL); + tor_free(desc_id_field); +} + +/** send HS_DESC UPLOADED event + * + * called when we successfully uploaded a hidden service descriptor. + */ +void +control_event_hs_descriptor_uploaded(const char *id_digest, + const char *onion_address) +{ + if (BUG(!id_digest)) { + return; + } + + control_event_hs_descriptor_upload_end("UPLOADED", onion_address, + id_digest, NULL); +} + +/** Send HS_DESC event to inform controller that query rend_data + * failed to retrieve hidden service descriptor from directory identified by + * id_digest. If NULL, "UNKNOWN" is used. If reason is not NULL, + * add it to REASON= field. + */ +void +control_event_hsv2_descriptor_failed(const rend_data_t *rend_data, + const char *hsdir_id_digest, + const char *reason) +{ + char *desc_id_field = NULL; + const char *desc_id; + + if (BUG(!rend_data)) { + return; + } + + desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest); + if (desc_id != NULL) { + char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; + /* Set the descriptor ID digest to base32 so we can send it. */ + base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id, + DIGEST_LEN); + /* Extra whitespace is needed before the value. */ + tor_asprintf(&desc_id_field, " %s", desc_id_base32); + } + + event_hs_descriptor_receive_end("FAILED", rend_data_get_address(rend_data), + desc_id_field, + TO_REND_DATA_V2(rend_data)->auth_type, + hsdir_id_digest, reason); + tor_free(desc_id_field); +} + +/** Send HS_DESC event to inform controller that the query to + * onion_address failed to retrieve hidden service descriptor + * desc_id from directory identified by hsdir_id_digest. If + * NULL, "UNKNOWN" is used. If reason is not NULL, add it to REASON= + * field. */ +void +control_event_hsv3_descriptor_failed(const char *onion_address, + const char *desc_id, + const char *hsdir_id_digest, + const char *reason) +{ + char *desc_id_field = NULL; + + if (BUG(!onion_address || !desc_id || !reason)) { + return; + } + + /* Because DescriptorID is an optional positional value, we need to add a + * whitespace before in order to not be next to the HsDir value. */ + tor_asprintf(&desc_id_field, " %s", desc_id); + + event_hs_descriptor_receive_end("FAILED", onion_address, desc_id_field, + REND_NO_AUTH, hsdir_id_digest, reason); + tor_free(desc_id_field); +} + +/** Send HS_DESC_CONTENT event after completion of a successful fetch + * from hs directory. If hsdir_id_digest is NULL, it is replaced + * by "UNKNOWN". If content is NULL, it is replaced by an empty + * string. The onion_address or desc_id set to NULL will + * not trigger the control event. */ +void +control_event_hs_descriptor_content(const char *onion_address, + const char *desc_id, + const char *hsdir_id_digest, + const char *content) +{ + static const char *event_name = "HS_DESC_CONTENT"; + char *esc_content = NULL; + + if (!onion_address || !desc_id) { + log_warn(LD_BUG, "Called with onion_address==%p, desc_id==%p, ", + onion_address, desc_id); + return; + } + + if (content == NULL) { + /* Point it to empty content so it can still be escaped. */ + content = ""; + } + write_escaped_data(content, strlen(content), &esc_content); + + send_control_event(EVENT_HS_DESC_CONTENT, + "650+%s %s %s %s\r\n%s650 OK\r\n", + event_name, + rend_hsaddress_str_or_unknown(onion_address), + desc_id, + hsdir_id_digest ? + node_describe_longname_by_id(hsdir_id_digest) : + "UNKNOWN", + esc_content); + tor_free(esc_content); +} + +/** Send HS_DESC event to inform controller upload of hidden service + * descriptor identified by id_digest failed. If reason + * is not NULL, add it to REASON= field. + */ +void +control_event_hs_descriptor_upload_failed(const char *id_digest, + const char *onion_address, + const char *reason) +{ + if (BUG(!id_digest)) { + return; + } + control_event_hs_descriptor_upload_end("FAILED", onion_address, + id_digest, reason); +} + +void +control_events_free_all(void) +{ + smartlist_t *queued_events = NULL; + + stats_prev_n_read = stats_prev_n_written = 0; + + if (queued_control_events_lock) { + tor_mutex_acquire(queued_control_events_lock); + flush_queued_event_pending = 0; + queued_events = queued_control_events; + queued_control_events = NULL; + tor_mutex_release(queued_control_events_lock); + } + if (queued_events) { + SMARTLIST_FOREACH(queued_events, queued_event_t *, ev, + queued_event_free(ev)); + smartlist_free(queued_events); + } + if (flush_queued_events_event) { + mainloop_event_free(flush_queued_events_event); + flush_queued_events_event = NULL; + } + global_event_mask = 0; + disable_log_messages = 0; +} + +#ifdef TOR_UNIT_TESTS +/* For testing: change the value of global_event_mask */ +void +control_testing_set_global_event_mask(uint64_t mask) +{ + global_event_mask = mask; +} +#endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/feature/control/control_events.h b/src/feature/control/control_events.h new file mode 100644 index 0000000000..34986fdb89 --- /dev/null +++ b/src/feature/control/control_events.h @@ -0,0 +1,352 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_events.h + * \brief Header file for control_events.c. + **/ + +#ifndef TOR_CONTROL_EVENTS_H +#define TOR_CONTROL_EVENTS_H + +#include "core/or/ocirc_event.h" + +/** Used to indicate the type of a CIRC_MINOR event passed to the controller. + * The various types are defined in control-spec.txt . */ +typedef enum circuit_status_minor_event_t { + CIRC_MINOR_EVENT_PURPOSE_CHANGED, + CIRC_MINOR_EVENT_CANNIBALIZED, +} circuit_status_minor_event_t; + +#include "core/or/orconn_event.h" + +/** Used to indicate the type of a stream event passed to the controller. + * The various types are defined in control-spec.txt */ +typedef enum stream_status_event_t { + STREAM_EVENT_SENT_CONNECT = 0, + STREAM_EVENT_SENT_RESOLVE = 1, + STREAM_EVENT_SUCCEEDED = 2, + STREAM_EVENT_FAILED = 3, + STREAM_EVENT_CLOSED = 4, + STREAM_EVENT_NEW = 5, + STREAM_EVENT_NEW_RESOLVE = 6, + STREAM_EVENT_FAILED_RETRIABLE = 7, + STREAM_EVENT_REMAP = 8 +} stream_status_event_t; + +/** Used to indicate the type of a buildtime event */ +typedef enum buildtimeout_set_event_t { + BUILDTIMEOUT_SET_EVENT_COMPUTED = 0, + BUILDTIMEOUT_SET_EVENT_RESET = 1, + BUILDTIMEOUT_SET_EVENT_SUSPENDED = 2, + BUILDTIMEOUT_SET_EVENT_DISCARD = 3, + BUILDTIMEOUT_SET_EVENT_RESUME = 4 +} buildtimeout_set_event_t; + +/** Enum describing various stages of bootstrapping, for use with controller + * bootstrap status events. The values range from 0 to 100. */ +typedef enum { + BOOTSTRAP_STATUS_UNDEF=-1, + BOOTSTRAP_STATUS_STARTING=0, + + /* Initial connection to any relay */ + + BOOTSTRAP_STATUS_CONN_PT=1, + BOOTSTRAP_STATUS_CONN_DONE_PT=2, + BOOTSTRAP_STATUS_CONN_PROXY=3, + BOOTSTRAP_STATUS_CONN_DONE_PROXY=4, + BOOTSTRAP_STATUS_CONN=5, + BOOTSTRAP_STATUS_CONN_DONE=10, + BOOTSTRAP_STATUS_HANDSHAKE=14, + BOOTSTRAP_STATUS_HANDSHAKE_DONE=15, + + /* Loading directory info */ + + BOOTSTRAP_STATUS_ONEHOP_CREATE=20, + BOOTSTRAP_STATUS_REQUESTING_STATUS=25, + BOOTSTRAP_STATUS_LOADING_STATUS=30, + BOOTSTRAP_STATUS_LOADING_KEYS=40, + BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS=45, + BOOTSTRAP_STATUS_LOADING_DESCRIPTORS=50, + BOOTSTRAP_STATUS_ENOUGH_DIRINFO=75, + + /* Connecting to a relay for AP circuits */ + + BOOTSTRAP_STATUS_AP_CONN_PT=76, + BOOTSTRAP_STATUS_AP_CONN_DONE_PT=77, + BOOTSTRAP_STATUS_AP_CONN_PROXY=78, + BOOTSTRAP_STATUS_AP_CONN_DONE_PROXY=79, + BOOTSTRAP_STATUS_AP_CONN=80, + BOOTSTRAP_STATUS_AP_CONN_DONE=85, + BOOTSTRAP_STATUS_AP_HANDSHAKE=89, + BOOTSTRAP_STATUS_AP_HANDSHAKE_DONE=90, + + /* Creating AP circuits */ + + BOOTSTRAP_STATUS_CIRCUIT_CREATE=95, + BOOTSTRAP_STATUS_DONE=100 +} bootstrap_status_t; + +/** Reason for remapping an AP connection's address: we have a cached + * answer. */ +#define REMAP_STREAM_SOURCE_CACHE 1 +/** Reason for remapping an AP connection's address: the exit node told us an + * answer. */ +#define REMAP_STREAM_SOURCE_EXIT 2 + +void control_initialize_event_queue(void); + +void control_update_global_event_mask(void); +void control_adjust_event_log_severity(void); + +#define EVENT_NS 0x000F +int control_event_is_interesting(int event); + +void control_per_second_events(void); +int control_any_per_second_event_enabled(void); + +int control_event_circuit_status(origin_circuit_t *circ, + circuit_status_event_t e, int reason); +int control_event_circuit_purpose_changed(origin_circuit_t *circ, + int old_purpose); +int control_event_circuit_cannibalized(origin_circuit_t *circ, + int old_purpose, + const struct timeval *old_tv_created); +int control_event_stream_status(entry_connection_t *conn, + stream_status_event_t e, + int reason); +int control_event_or_conn_status(or_connection_t *conn, + or_conn_status_event_t e, int reason); +int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written); +int control_event_stream_bandwidth(edge_connection_t *edge_conn); +int control_event_stream_bandwidth_used(void); +int control_event_circ_bandwidth_used(void); +int control_event_circ_bandwidth_used_for_circ(origin_circuit_t *ocirc); +int control_event_conn_bandwidth(connection_t *conn); +int control_event_conn_bandwidth_used(void); +int control_event_circuit_cell_stats(void); +void control_event_logmsg(int severity, log_domain_mask_t domain, + const char *msg); +void control_event_logmsg_pending(void); +int control_event_descriptors_changed(smartlist_t *routers); +int control_event_address_mapped(const char *from, const char *to, + time_t expires, const char *error, + const int cached); +int control_event_my_descriptor_changed(void); +int control_event_network_liveness_update(int liveness); +int control_event_networkstatus_changed(smartlist_t *statuses); + +int control_event_newconsensus(const networkstatus_t *consensus); +int control_event_networkstatus_changed_single(const routerstatus_t *rs); +int control_event_general_status(int severity, const char *format, ...) + CHECK_PRINTF(2,3); +int control_event_client_status(int severity, const char *format, ...) + CHECK_PRINTF(2,3); +int control_event_server_status(int severity, const char *format, ...) + CHECK_PRINTF(2,3); + +int control_event_general_error(const char *format, ...) + CHECK_PRINTF(1,2); +int control_event_client_error(const char *format, ...) + CHECK_PRINTF(1,2); +int control_event_server_error(const char *format, ...) + CHECK_PRINTF(1,2); + +int control_event_guard(const char *nickname, const char *digest, + const char *status); +int control_event_conf_changed(const smartlist_t *elements); +int control_event_buildtimeout_set(buildtimeout_set_event_t type, + const char *args); +int control_event_signal(uintptr_t signal); + +void control_event_bootstrap(bootstrap_status_t status, int progress); +MOCK_DECL(void, control_event_bootstrap_prob_or,(const char *warn, + int reason, + or_connection_t *or_conn)); +void control_event_boot_dir(bootstrap_status_t status, int progress); +void control_event_boot_first_orconn(void); +void control_event_bootstrap_problem(const char *warn, const char *reason, + const connection_t *conn, int dowarn); +char *control_event_boot_last_msg(void); +void control_event_bootstrap_reset(void); + +void control_event_clients_seen(const char *controller_str); +void control_event_transport_launched(const char *mode, + const char *transport_name, + tor_addr_t *addr, uint16_t port); +void control_event_pt_log(const char *log); +void control_event_pt_status(const char *status); + +void control_event_hs_descriptor_requested(const char *onion_address, + rend_auth_type_t auth_type, + const char *id_digest, + const char *desc_id, + const char *hsdir_index); +void control_event_hs_descriptor_created(const char *onion_address, + const char *desc_id, + int replica); +void control_event_hs_descriptor_upload(const char *onion_address, + const char *desc_id, + const char *hs_dir, + const char *hsdir_index); +void control_event_hs_descriptor_upload_end(const char *action, + const char *onion_address, + const char *hs_dir, + const char *reason); +void control_event_hs_descriptor_uploaded(const char *hs_dir, + const char *onion_address); +/* Hidden service v2 HS_DESC specific. */ +void control_event_hsv2_descriptor_failed(const rend_data_t *rend_data, + const char *id_digest, + const char *reason); +void control_event_hsv2_descriptor_received(const char *onion_address, + const rend_data_t *rend_data, + const char *id_digest); +/* Hidden service v3 HS_DESC specific. */ +void control_event_hsv3_descriptor_failed(const char *onion_address, + const char *desc_id, + const char *hsdir_id_digest, + const char *reason); +void control_event_hsv3_descriptor_received(const char *onion_address, + const char *desc_id, + const char *hsdir_id_digest); +void control_event_hs_descriptor_upload_failed(const char *hs_dir, + const char *onion_address, + const char *reason); +void control_event_hs_descriptor_content(const char *onion_address, + const char *desc_id, + const char *hsdir_fp, + const char *content); + +void control_events_free_all(void); + +#ifdef CONTROL_MODULE_PRIVATE +char *get_bw_samples(void); +#endif /* defined(CONTROL_MODULE_PRIVATE) */ + +#ifdef CONTROL_EVENTS_PRIVATE +/** Bitfield: The bit 1<<e is set if any open control + * connection is interested in events of type e. We use this + * so that we can decide to skip generating event messages that nobody + * has interest in without having to walk over the global connection + * list to find out. + **/ +typedef uint64_t event_mask_t; + +/* Recognized asynchronous event types. It's okay to expand this list + * because it is used both as a list of v0 event types, and as indices + * into the bitfield to determine which controllers want which events. + */ +/* This bitfield has no event zero 0x0000 */ +#define EVENT_MIN_ 0x0001 +#define EVENT_CIRCUIT_STATUS 0x0001 +#define EVENT_STREAM_STATUS 0x0002 +#define EVENT_OR_CONN_STATUS 0x0003 +#define EVENT_BANDWIDTH_USED 0x0004 +#define EVENT_CIRCUIT_STATUS_MINOR 0x0005 +#define EVENT_NEW_DESC 0x0006 +#define EVENT_DEBUG_MSG 0x0007 +#define EVENT_INFO_MSG 0x0008 +#define EVENT_NOTICE_MSG 0x0009 +#define EVENT_WARN_MSG 0x000A +#define EVENT_ERR_MSG 0x000B +#define EVENT_ADDRMAP 0x000C +/* There was an AUTHDIR_NEWDESCS event, but it no longer exists. We + can reclaim 0x000D. */ +#define EVENT_DESCCHANGED 0x000E +/* Exposed above */ +// #define EVENT_NS 0x000F +#define EVENT_STATUS_CLIENT 0x0010 +#define EVENT_STATUS_SERVER 0x0011 +#define EVENT_STATUS_GENERAL 0x0012 +#define EVENT_GUARD 0x0013 +#define EVENT_STREAM_BANDWIDTH_USED 0x0014 +#define EVENT_CLIENTS_SEEN 0x0015 +#define EVENT_NEWCONSENSUS 0x0016 +#define EVENT_BUILDTIMEOUT_SET 0x0017 +#define EVENT_GOT_SIGNAL 0x0018 +#define EVENT_CONF_CHANGED 0x0019 +#define EVENT_CONN_BW 0x001A +#define EVENT_CELL_STATS 0x001B +/* UNUSED : 0x001C */ +#define EVENT_CIRC_BANDWIDTH_USED 0x001D +#define EVENT_TRANSPORT_LAUNCHED 0x0020 +#define EVENT_HS_DESC 0x0021 +#define EVENT_HS_DESC_CONTENT 0x0022 +#define EVENT_NETWORK_LIVENESS 0x0023 +#define EVENT_PT_LOG 0x0024 +#define EVENT_PT_STATUS 0x0025 +#define EVENT_MAX_ 0x0025 + +/* sizeof(control_connection_t.event_mask) in bits, currently a uint64_t */ +#define EVENT_CAPACITY_ 0x0040 + +/* If EVENT_MAX_ ever hits 0x0040, we need to make the mask into a + * different structure, as it can only handle a maximum left shift of 1<<63. */ + +#if EVENT_MAX_ >= EVENT_CAPACITY_ +#error control_connection_t.event_mask has an event greater than its capacity +#endif + +#define EVENT_MASK_(e) (((uint64_t)1)<<(e)) + +#define EVENT_MASK_NONE_ ((uint64_t)0x0) + +#define EVENT_MASK_ABOVE_MIN_ ((~((uint64_t)0x0)) << EVENT_MIN_) +#define EVENT_MASK_BELOW_MAX_ ((~((uint64_t)0x0)) \ + >> (EVENT_CAPACITY_ - EVENT_MAX_ \ + - EVENT_MIN_)) + +#define EVENT_MASK_ALL_ (EVENT_MASK_ABOVE_MIN_ \ + & EVENT_MASK_BELOW_MAX_) + +/** Helper structure: temporarily stores cell statistics for a circuit. */ +typedef struct cell_stats_t { + /** Number of cells added in app-ward direction by command. */ + uint64_t added_cells_appward[CELL_COMMAND_MAX_ + 1]; + /** Number of cells added in exit-ward direction by command. */ + uint64_t added_cells_exitward[CELL_COMMAND_MAX_ + 1]; + /** Number of cells removed in app-ward direction by command. */ + uint64_t removed_cells_appward[CELL_COMMAND_MAX_ + 1]; + /** Number of cells removed in exit-ward direction by command. */ + uint64_t removed_cells_exitward[CELL_COMMAND_MAX_ + 1]; + /** Total waiting time of cells in app-ward direction by command. */ + uint64_t total_time_appward[CELL_COMMAND_MAX_ + 1]; + /** Total waiting time of cells in exit-ward direction by command. */ + uint64_t total_time_exitward[CELL_COMMAND_MAX_ + 1]; +} cell_stats_t; + +void sum_up_cell_stats_by_command(circuit_t *circ, + cell_stats_t *cell_stats); +void append_cell_stats_by_command(smartlist_t *event_parts, + const char *key, + const uint64_t *include_if_non_zero, + const uint64_t *number_to_include); +void format_cell_stats(char **event_string, circuit_t *circ, + cell_stats_t *cell_stats); + +/** Helper structure: maps event values to their names. */ +struct control_event_t { + uint16_t event_code; + const char *event_name; +}; + +extern const struct control_event_t control_event_table[]; + +#ifdef TOR_UNIT_TESTS +MOCK_DECL(STATIC void, + send_control_event_string,(uint16_t event, const char *msg)); + +MOCK_DECL(STATIC void, + queue_control_event_string,(uint16_t event, char *msg)); + +void control_testing_set_global_event_mask(uint64_t mask); + +#endif /* defined(TOR_UNIT_TESTS) */ + +#endif /* defined(CONTROL_EVENTS_PRIVATE) */ + +#endif /* !defined(TOR_CONTROL_EVENTS_H) */ diff --git a/src/feature/control/control_fmt.c b/src/feature/control/control_fmt.c new file mode 100644 index 0000000000..e0e77eb2d0 --- /dev/null +++ b/src/feature/control/control_fmt.c @@ -0,0 +1,181 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_fmt.c + * \brief Formatting functions for controller data. + */ + +#include "core/or/or.h" + +#include "core/mainloop/connection.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/connection_edge.h" +#include "feature/control/control_fmt.h" +#include "feature/control/control_proto.h" +#include "feature/nodelist/nodelist.h" + +#include "core/or/cpath_build_state_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/or_connection_st.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/socks_request_st.h" +#include "feature/control/control_connection_st.h" + +/** Given an AP connection conn and a len-character buffer + * buf, determine the address:port combination requested on + * conn, and write it to buf. Return 0 on success, -1 on + * failure. */ +int +write_stream_target_to_buf(entry_connection_t *conn, char *buf, size_t len) +{ + char buf2[256]; + if (conn->chosen_exit_name) + if (tor_snprintf(buf2, sizeof(buf2), ".%s.exit", conn->chosen_exit_name)<0) + return -1; + if (!conn->socks_request) + return -1; + if (tor_snprintf(buf, len, "%s%s%s:%d", + conn->socks_request->address, + conn->chosen_exit_name ? buf2 : "", + !conn->chosen_exit_name && connection_edge_is_rendezvous_stream( + ENTRY_TO_EDGE_CONN(conn)) ? ".onion" : "", + conn->socks_request->port)<0) + return -1; + return 0; +} + +/** Figure out the best name for the target router of an OR connection + * conn, and write it into the len-character buffer + * name. */ +void +orconn_target_get_name(char *name, size_t len, or_connection_t *conn) +{ + const node_t *node = node_get_by_id(conn->identity_digest); + if (node) { + tor_assert(len > MAX_VERBOSE_NICKNAME_LEN); + node_get_verbose_nickname(node, name); + } else if (! tor_digest_is_zero(conn->identity_digest)) { + name[0] = '$'; + base16_encode(name+1, len-1, conn->identity_digest, + DIGEST_LEN); + } else { + tor_snprintf(name, len, "%s:%d", + conn->base_.address, conn->base_.port); + } +} + +/** Allocate and return a description of circ's current status, + * including its path (if any). */ +char * +circuit_describe_status_for_controller(origin_circuit_t *circ) +{ + char *rv; + smartlist_t *descparts = smartlist_new(); + + { + char *vpath = circuit_list_path_for_controller(circ); + if (*vpath) { + smartlist_add(descparts, vpath); + } else { + tor_free(vpath); /* empty path; don't put an extra space in the result */ + } + } + + { + cpath_build_state_t *build_state = circ->build_state; + smartlist_t *flaglist = smartlist_new(); + char *flaglist_joined; + + if (build_state->onehop_tunnel) + smartlist_add(flaglist, (void *)"ONEHOP_TUNNEL"); + if (build_state->is_internal) + smartlist_add(flaglist, (void *)"IS_INTERNAL"); + if (build_state->need_capacity) + smartlist_add(flaglist, (void *)"NEED_CAPACITY"); + if (build_state->need_uptime) + smartlist_add(flaglist, (void *)"NEED_UPTIME"); + + /* Only emit a BUILD_FLAGS argument if it will have a non-empty value. */ + if (smartlist_len(flaglist)) { + flaglist_joined = smartlist_join_strings(flaglist, ",", 0, NULL); + + smartlist_add_asprintf(descparts, "BUILD_FLAGS=%s", flaglist_joined); + + tor_free(flaglist_joined); + } + + smartlist_free(flaglist); + } + + smartlist_add_asprintf(descparts, "PURPOSE=%s", + circuit_purpose_to_controller_string(circ->base_.purpose)); + + { + const char *hs_state = + circuit_purpose_to_controller_hs_state_string(circ->base_.purpose); + + if (hs_state != NULL) { + smartlist_add_asprintf(descparts, "HS_STATE=%s", hs_state); + } + } + + if (circ->rend_data != NULL || circ->hs_ident != NULL) { + char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1]; + const char *onion_address; + if (circ->rend_data) { + onion_address = rend_data_get_address(circ->rend_data); + } else { + hs_build_address(&circ->hs_ident->identity_pk, HS_VERSION_THREE, addr); + onion_address = addr; + } + smartlist_add_asprintf(descparts, "REND_QUERY=%s", onion_address); + } + + { + char tbuf[ISO_TIME_USEC_LEN+1]; + format_iso_time_nospace_usec(tbuf, &circ->base_.timestamp_created); + + smartlist_add_asprintf(descparts, "TIME_CREATED=%s", tbuf); + } + + // Show username and/or password if available. + if (circ->socks_username_len > 0) { + char* socks_username_escaped = esc_for_log_len(circ->socks_username, + (size_t) circ->socks_username_len); + smartlist_add_asprintf(descparts, "SOCKS_USERNAME=%s", + socks_username_escaped); + tor_free(socks_username_escaped); + } + if (circ->socks_password_len > 0) { + char* socks_password_escaped = esc_for_log_len(circ->socks_password, + (size_t) circ->socks_password_len); + smartlist_add_asprintf(descparts, "SOCKS_PASSWORD=%s", + socks_password_escaped); + tor_free(socks_password_escaped); + } + + rv = smartlist_join_strings(descparts, " ", 0, NULL); + + SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp)); + smartlist_free(descparts); + + return rv; +} + +/** Return a longname the node whose identity is id_digest. If + * node_get_by_id() returns NULL, base 16 encoding of id_digest is + * returned instead. + * + * This function is not thread-safe. Each call to this function invalidates + * previous values returned by this function. + */ +MOCK_IMPL(const char *, +node_describe_longname_by_id,(const char *id_digest)) +{ + static char longname[MAX_VERBOSE_NICKNAME_LEN+1]; + node_get_verbose_nickname_by_id(id_digest, longname); + return longname; +} diff --git a/src/feature/control/control_fmt.h b/src/feature/control/control_fmt.h new file mode 100644 index 0000000000..6446e37079 --- /dev/null +++ b/src/feature/control/control_fmt.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_fmt.h + * \brief Header file for control_fmt.c. + **/ + +#ifndef TOR_CONTROL_FMT_H +#define TOR_CONTROL_FMT_H + +int write_stream_target_to_buf(entry_connection_t *conn, char *buf, + size_t len); +void orconn_target_get_name(char *buf, size_t len, + or_connection_t *conn); +char *circuit_describe_status_for_controller(origin_circuit_t *circ); + +MOCK_DECL(const char *, node_describe_longname_by_id,(const char *id_digest)); + +#endif /* !defined(TOR_CONTROL_FMT_H) */ diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c new file mode 100644 index 0000000000..3e31bb9e8f --- /dev/null +++ b/src/feature/control/control_getinfo.c @@ -0,0 +1,1654 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_getinfo.c + * \brief Implementation for miscellaneous controller getinfo commands. + */ + +#define CONTROL_EVENTS_PRIVATE +#define CONTROL_MODULE_PRIVATE +#define CONTROL_GETINFO_PRIVATE + +#include "core/or/or.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/mainloop/mainloop.h" +#include "core/or/circuitlist.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "core/or/policies.h" +#include "core/or/versions.h" +#include "feature/client/addressmap.h" +#include "feature/client/bridges.h" +#include "feature/client/entrynodes.h" +#include "feature/control/control.h" +#include "feature/control/control_cmd.h" +#include "feature/control/control_events.h" +#include "feature/control/control_fmt.h" +#include "feature/control/control_getinfo.h" +#include "feature/control/control_proto.h" +#include "feature/control/fmt_serverstatus.h" +#include "feature/control/getinfo_geoip.h" +#include "feature/dircache/dirserv.h" +#include "feature/dirclient/dirclient.h" +#include "feature/dirclient/dlstatus.h" +#include "feature/hibernate/hibernate.h" +#include "feature/hs/hs_cache.h" +#include "feature/hs_common/shared_random_client.h" +#include "feature/nodelist/authcert.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/routerinfo.h" +#include "feature/nodelist/routerlist.h" +#include "feature/relay/router.h" +#include "feature/relay/routermode.h" +#include "feature/relay/selftest.h" +#include "feature/rend/rendcache.h" +#include "feature/stats/geoip_stats.h" +#include "feature/stats/predict_ports.h" +#include "lib/version/torversion.h" + +#include "core/or/entry_connection_st.h" +#include "core/or/or_connection_st.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/socks_request_st.h" +#include "feature/control/control_connection_st.h" +#include "feature/control/control_cmd_args_st.h" +#include "feature/dircache/cached_dir_st.h" +#include "feature/nodelist/extrainfo_st.h" +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerlist_st.h" + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifndef _WIN32 +#include +#endif + +static char *list_getinfo_options(void); +static char *download_status_to_string(const download_status_t *dl); + +/** Implementation helper for GETINFO: knows the answers for various + * trivial-to-implement questions. */ +static int +getinfo_helper_misc(control_connection_t *conn, const char *question, + char **answer, const char **errmsg) +{ + (void) conn; + if (!strcmp(question, "version")) { + *answer = tor_strdup(get_version()); + } else if (!strcmp(question, "bw-event-cache")) { + *answer = get_bw_samples(); + } else if (!strcmp(question, "config-file")) { + const char *a = get_torrc_fname(0); + if (a) + *answer = tor_strdup(a); + } else if (!strcmp(question, "config-defaults-file")) { + const char *a = get_torrc_fname(1); + if (a) + *answer = tor_strdup(a); + } else if (!strcmp(question, "config-text")) { + *answer = options_dump(get_options(), OPTIONS_DUMP_MINIMAL); + } else if (!strcmp(question, "config-can-saveconf")) { + *answer = tor_strdup(get_options()->IncludeUsed ? "0" : "1"); + } else if (!strcmp(question, "info/names")) { + *answer = list_getinfo_options(); + } else if (!strcmp(question, "dormant")) { + int dormant = rep_hist_circbuilding_dormant(time(NULL)); + *answer = tor_strdup(dormant ? "1" : "0"); + } else if (!strcmp(question, "events/names")) { + int i; + smartlist_t *event_names = smartlist_new(); + + for (i = 0; control_event_table[i].event_name != NULL; ++i) { + smartlist_add(event_names, (char *)control_event_table[i].event_name); + } + + *answer = smartlist_join_strings(event_names, " ", 0, NULL); + + smartlist_free(event_names); + } else if (!strcmp(question, "signal/names")) { + smartlist_t *signal_names = smartlist_new(); + int j; + for (j = 0; signal_table[j].signal_name != NULL; ++j) { + smartlist_add(signal_names, (char*)signal_table[j].signal_name); + } + + *answer = smartlist_join_strings(signal_names, " ", 0, NULL); + + smartlist_free(signal_names); + } else if (!strcmp(question, "features/names")) { + *answer = tor_strdup("VERBOSE_NAMES EXTENDED_EVENTS"); + } else if (!strcmp(question, "address")) { + uint32_t addr; + if (router_pick_published_address(get_options(), &addr, 0) < 0) { + *errmsg = "Address unknown"; + return -1; + } + *answer = tor_dup_ip(addr); + } else if (!strcmp(question, "traffic/read")) { + tor_asprintf(answer, "%"PRIu64, (get_bytes_read())); + } else if (!strcmp(question, "traffic/written")) { + tor_asprintf(answer, "%"PRIu64, (get_bytes_written())); + } else if (!strcmp(question, "uptime")) { + long uptime_secs = get_uptime(); + tor_asprintf(answer, "%ld", uptime_secs); + } else if (!strcmp(question, "process/pid")) { + int myPid = -1; + +#ifdef _WIN32 + myPid = _getpid(); +#else + myPid = getpid(); +#endif + + tor_asprintf(answer, "%d", myPid); + } else if (!strcmp(question, "process/uid")) { +#ifdef _WIN32 + *answer = tor_strdup("-1"); +#else + int myUid = geteuid(); + tor_asprintf(answer, "%d", myUid); +#endif /* defined(_WIN32) */ + } else if (!strcmp(question, "process/user")) { +#ifdef _WIN32 + *answer = tor_strdup(""); +#else + int myUid = geteuid(); + const struct passwd *myPwEntry = tor_getpwuid(myUid); + + if (myPwEntry) { + *answer = tor_strdup(myPwEntry->pw_name); + } else { + *answer = tor_strdup(""); + } +#endif /* defined(_WIN32) */ + } else if (!strcmp(question, "process/descriptor-limit")) { + int max_fds = get_max_sockets(); + tor_asprintf(answer, "%d", max_fds); + } else if (!strcmp(question, "limits/max-mem-in-queues")) { + tor_asprintf(answer, "%"PRIu64, + (get_options()->MaxMemInQueues)); + } else if (!strcmp(question, "fingerprint")) { + crypto_pk_t *server_key; + if (!server_mode(get_options())) { + *errmsg = "Not running in server mode"; + return -1; + } + server_key = get_server_identity_key(); + *answer = tor_malloc(HEX_DIGEST_LEN+1); + crypto_pk_get_fingerprint(server_key, *answer, 0); + } + return 0; +} + +/** Awful hack: return a newly allocated string based on a routerinfo and + * (possibly) an extrainfo, sticking the read-history and write-history from + * ei into the resulting string. The thing you get back won't + * necessarily have a valid signature. + * + * New code should never use this; it's for backward compatibility. + * + * NOTE: ri_body is as returned by signed_descriptor_get_body: it might + * not be NUL-terminated. */ +static char * +munge_extrainfo_into_routerinfo(const char *ri_body, + const signed_descriptor_t *ri, + const signed_descriptor_t *ei) +{ + char *out = NULL, *outp; + int i; + const char *router_sig; + const char *ei_body = signed_descriptor_get_body(ei); + size_t ri_len = ri->signed_descriptor_len; + size_t ei_len = ei->signed_descriptor_len; + if (!ei_body) + goto bail; + + outp = out = tor_malloc(ri_len+ei_len+1); + if (!(router_sig = tor_memstr(ri_body, ri_len, "\nrouter-signature"))) + goto bail; + ++router_sig; + memcpy(out, ri_body, router_sig-ri_body); + outp += router_sig-ri_body; + + for (i=0; i < 2; ++i) { + const char *kwd = i ? "\nwrite-history " : "\nread-history "; + const char *cp, *eol; + if (!(cp = tor_memstr(ei_body, ei_len, kwd))) + continue; + ++cp; + if (!(eol = memchr(cp, '\n', ei_len - (cp-ei_body)))) + continue; + memcpy(outp, cp, eol-cp+1); + outp += eol-cp+1; + } + memcpy(outp, router_sig, ri_len - (router_sig-ri_body)); + *outp++ = '\0'; + tor_assert(outp-out < (int)(ri_len+ei_len+1)); + + return out; + bail: + tor_free(out); + return tor_strndup(ri_body, ri->signed_descriptor_len); +} + +/** Implementation helper for GETINFO: answers requests for information about + * which ports are bound. */ +static int +getinfo_helper_listeners(control_connection_t *control_conn, + const char *question, + char **answer, const char **errmsg) +{ + int type; + smartlist_t *res; + + (void)control_conn; + (void)errmsg; + + 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")) + type = CONN_TYPE_AP_LISTENER; + else if (!strcmp(question, "net/listeners/trans")) + 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")) + type = CONN_TYPE_CONTROL_LISTENER; + else + return 0; /* unknown key */ + + res = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { + struct sockaddr_storage ss; + socklen_t ss_len = sizeof(ss); + + if (conn->type != type || conn->marked_for_close || !SOCKET_OK(conn->s)) + continue; + + if (getsockname(conn->s, (struct sockaddr *)&ss, &ss_len) < 0) { + smartlist_add_asprintf(res, "%s:%d", conn->address, (int)conn->port); + } else { + char *tmp = tor_sockaddr_to_str((struct sockaddr *)&ss); + smartlist_add(res, esc_for_log(tmp)); + tor_free(tmp); + } + + } SMARTLIST_FOREACH_END(conn); + + *answer = smartlist_join_strings(res, " ", 0, NULL); + + SMARTLIST_FOREACH(res, char *, cp, tor_free(cp)); + smartlist_free(res); + return 0; +} + +/** Implementation helper for GETINFO: answers requests for information about + * the current time in both local and UTC forms. */ +STATIC int +getinfo_helper_current_time(control_connection_t *control_conn, + const char *question, + char **answer, const char **errmsg) +{ + (void)control_conn; + (void)errmsg; + + struct timeval now; + tor_gettimeofday(&now); + char timebuf[ISO_TIME_LEN+1]; + + if (!strcmp(question, "current-time/local")) + format_local_iso_time_nospace(timebuf, (time_t)now.tv_sec); + else if (!strcmp(question, "current-time/utc")) + format_iso_time_nospace(timebuf, (time_t)now.tv_sec); + else + return 0; + + *answer = tor_strdup(timebuf); + return 0; +} + +/** Implementation helper for GETINFO: knows the answers for questions about + * directory information. */ +STATIC int +getinfo_helper_dir(control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg) +{ + (void) control_conn; + if (!strcmpstart(question, "desc/id/")) { + const routerinfo_t *ri = NULL; + const node_t *node = node_get_by_hex_id(question+strlen("desc/id/"), 0); + if (node) + ri = node->ri; + if (ri) { + const char *body = signed_descriptor_get_body(&ri->cache_info); + if (body) + *answer = tor_strndup(body, ri->cache_info.signed_descriptor_len); + } else if (! we_fetch_router_descriptors(get_options())) { + /* Descriptors won't be available, provide proper error */ + *errmsg = "We fetch microdescriptors, not router " + "descriptors. You'll need to use md/id/* " + "instead of desc/id/*."; + return 0; + } + } else if (!strcmpstart(question, "desc/name/")) { + const routerinfo_t *ri = NULL; + /* XXX Setting 'warn_if_unnamed' here is a bit silly -- the + * warning goes to the user, not to the controller. */ + const node_t *node = + node_get_by_nickname(question+strlen("desc/name/"), 0); + if (node) + ri = node->ri; + if (ri) { + const char *body = signed_descriptor_get_body(&ri->cache_info); + if (body) + *answer = tor_strndup(body, ri->cache_info.signed_descriptor_len); + } else if (! we_fetch_router_descriptors(get_options())) { + /* Descriptors won't be available, provide proper error */ + *errmsg = "We fetch microdescriptors, not router " + "descriptors. You'll need to use md/name/* " + "instead of desc/name/*."; + return 0; + } + } else if (!strcmp(question, "desc/download-enabled")) { + int r = we_fetch_router_descriptors(get_options()); + tor_asprintf(answer, "%d", !!r); + } else if (!strcmp(question, "desc/all-recent")) { + routerlist_t *routerlist = router_get_routerlist(); + smartlist_t *sl = smartlist_new(); + if (routerlist && routerlist->routers) { + SMARTLIST_FOREACH(routerlist->routers, const routerinfo_t *, ri, + { + const char *body = signed_descriptor_get_body(&ri->cache_info); + if (body) + smartlist_add(sl, + tor_strndup(body, ri->cache_info.signed_descriptor_len)); + }); + } + *answer = smartlist_join_strings(sl, "", 0, NULL); + SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); + smartlist_free(sl); + } else if (!strcmp(question, "desc/all-recent-extrainfo-hack")) { + /* XXXX Remove this once Torstat asks for extrainfos. */ + routerlist_t *routerlist = router_get_routerlist(); + smartlist_t *sl = smartlist_new(); + if (routerlist && routerlist->routers) { + SMARTLIST_FOREACH_BEGIN(routerlist->routers, const routerinfo_t *, ri) { + const char *body = signed_descriptor_get_body(&ri->cache_info); + signed_descriptor_t *ei = extrainfo_get_by_descriptor_digest( + ri->cache_info.extra_info_digest); + if (ei && body) { + smartlist_add(sl, munge_extrainfo_into_routerinfo(body, + &ri->cache_info, ei)); + } else if (body) { + smartlist_add(sl, + tor_strndup(body, ri->cache_info.signed_descriptor_len)); + } + } SMARTLIST_FOREACH_END(ri); + } + *answer = smartlist_join_strings(sl, "", 0, NULL); + SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); + smartlist_free(sl); + } else if (!strcmpstart(question, "hs/client/desc/id/")) { + hostname_type_t addr_type; + + question += strlen("hs/client/desc/id/"); + if (rend_valid_v2_service_id(question)) { + addr_type = ONION_V2_HOSTNAME; + } else if (hs_address_is_valid(question)) { + addr_type = ONION_V3_HOSTNAME; + } else { + *errmsg = "Invalid address"; + return -1; + } + + if (addr_type == ONION_V2_HOSTNAME) { + rend_cache_entry_t *e = NULL; + if (!rend_cache_lookup_entry(question, -1, &e)) { + /* Descriptor found in cache */ + *answer = tor_strdup(e->desc); + } else { + *errmsg = "Not found in cache"; + return -1; + } + } else { + ed25519_public_key_t service_pk; + const char *desc; + + /* The check before this if/else makes sure of this. */ + tor_assert(addr_type == ONION_V3_HOSTNAME); + + if (hs_parse_address(question, &service_pk, NULL, NULL) < 0) { + *errmsg = "Invalid v3 address"; + return -1; + } + + desc = hs_cache_lookup_encoded_as_client(&service_pk); + if (desc) { + *answer = tor_strdup(desc); + } else { + *errmsg = "Not found in cache"; + return -1; + } + } + } else if (!strcmpstart(question, "hs/service/desc/id/")) { + hostname_type_t addr_type; + + question += strlen("hs/service/desc/id/"); + if (rend_valid_v2_service_id(question)) { + addr_type = ONION_V2_HOSTNAME; + } else if (hs_address_is_valid(question)) { + addr_type = ONION_V3_HOSTNAME; + } else { + *errmsg = "Invalid address"; + return -1; + } + rend_cache_entry_t *e = NULL; + + if (addr_type == ONION_V2_HOSTNAME) { + if (!rend_cache_lookup_v2_desc_as_service(question, &e)) { + /* Descriptor found in cache */ + *answer = tor_strdup(e->desc); + } else { + *errmsg = "Not found in cache"; + return -1; + } + } else { + ed25519_public_key_t service_pk; + char *desc; + + /* The check before this if/else makes sure of this. */ + tor_assert(addr_type == ONION_V3_HOSTNAME); + + if (hs_parse_address(question, &service_pk, NULL, NULL) < 0) { + *errmsg = "Invalid v3 address"; + return -1; + } + + desc = hs_service_lookup_current_desc(&service_pk); + if (desc) { + /* Newly allocated string, we have ownership. */ + *answer = desc; + } else { + *errmsg = "Not found in cache"; + return -1; + } + } + } else if (!strcmp(question, "md/all")) { + const smartlist_t *nodes = nodelist_get_list(); + tor_assert(nodes); + + if (smartlist_len(nodes) == 0) { + *answer = tor_strdup(""); + return 0; + } + + smartlist_t *microdescs = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(nodes, node_t *, n) { + if (n->md && n->md->body) { + char *copy = tor_strndup(n->md->body, n->md->bodylen); + smartlist_add(microdescs, copy); + } + } SMARTLIST_FOREACH_END(n); + + *answer = smartlist_join_strings(microdescs, "", 0, NULL); + SMARTLIST_FOREACH(microdescs, char *, md, tor_free(md)); + smartlist_free(microdescs); + } else if (!strcmpstart(question, "md/id/")) { + const node_t *node = node_get_by_hex_id(question+strlen("md/id/"), 0); + const microdesc_t *md = NULL; + if (node) md = node->md; + if (md && md->body) { + *answer = tor_strndup(md->body, md->bodylen); + } + } else if (!strcmpstart(question, "md/name/")) { + /* XXX Setting 'warn_if_unnamed' here is a bit silly -- the + * warning goes to the user, not to the controller. */ + const node_t *node = node_get_by_nickname(question+strlen("md/name/"), 0); + /* XXXX duplicated code */ + const microdesc_t *md = NULL; + if (node) md = node->md; + if (md && md->body) { + *answer = tor_strndup(md->body, md->bodylen); + } + } else if (!strcmp(question, "md/download-enabled")) { + int r = we_fetch_microdescriptors(get_options()); + tor_asprintf(answer, "%d", !!r); + } else if (!strcmpstart(question, "desc-annotations/id/")) { + const routerinfo_t *ri = NULL; + const node_t *node = + node_get_by_hex_id(question+strlen("desc-annotations/id/"), 0); + if (node) + ri = node->ri; + if (ri) { + const char *annotations = + signed_descriptor_get_annotations(&ri->cache_info); + if (annotations) + *answer = tor_strndup(annotations, + ri->cache_info.annotations_len); + } + } else if (!strcmpstart(question, "dir/server/")) { + size_t answer_len = 0; + char *url = NULL; + smartlist_t *descs = smartlist_new(); + const char *msg; + int res; + char *cp; + tor_asprintf(&url, "/tor/%s", question+4); + res = dirserv_get_routerdescs(descs, url, &msg); + if (res) { + log_warn(LD_CONTROL, "getinfo '%s': %s", question, msg); + smartlist_free(descs); + tor_free(url); + *errmsg = msg; + return -1; + } + SMARTLIST_FOREACH(descs, signed_descriptor_t *, sd, + answer_len += sd->signed_descriptor_len); + cp = *answer = tor_malloc(answer_len+1); + SMARTLIST_FOREACH(descs, signed_descriptor_t *, sd, + { + memcpy(cp, signed_descriptor_get_body(sd), + sd->signed_descriptor_len); + cp += sd->signed_descriptor_len; + }); + *cp = '\0'; + tor_free(url); + smartlist_free(descs); + } else if (!strcmpstart(question, "dir/status/")) { + *answer = tor_strdup(""); + } else if (!strcmp(question, "dir/status-vote/current/consensus")) { /* v3 */ + if (we_want_to_fetch_flavor(get_options(), FLAV_NS)) { + const cached_dir_t *consensus = dirserv_get_consensus("ns"); + if (consensus) + *answer = tor_strdup(consensus->dir); + } + if (!*answer) { /* try loading it from disk */ + tor_mmap_t *mapped = networkstatus_map_cached_consensus("ns"); + if (mapped) { + *answer = tor_memdup_nulterm(mapped->data, mapped->size); + tor_munmap_file(mapped); + } + if (!*answer) { /* generate an error */ + *errmsg = "Could not open cached consensus. " + "Make sure FetchUselessDescriptors is set to 1."; + return -1; + } + } + } else if (!strcmp(question, "network-status")) { /* v1 */ + static int network_status_warned = 0; + if (!network_status_warned) { + log_warn(LD_CONTROL, "GETINFO network-status is deprecated; it will " + "go away in a future version of Tor."); + network_status_warned = 1; + } + routerlist_t *routerlist = router_get_routerlist(); + if (!routerlist || !routerlist->routers || + list_server_status_v1(routerlist->routers, answer, 1) < 0) { + return -1; + } + } else if (!strcmpstart(question, "extra-info/digest/")) { + question += strlen("extra-info/digest/"); + if (strlen(question) == HEX_DIGEST_LEN) { + char d[DIGEST_LEN]; + signed_descriptor_t *sd = NULL; + if (base16_decode(d, sizeof(d), question, strlen(question)) + == sizeof(d)) { + /* XXXX this test should move into extrainfo_get_by_descriptor_digest, + * but I don't want to risk affecting other parts of the code, + * especially since the rules for using our own extrainfo (including + * when it might be freed) are different from those for using one + * we have downloaded. */ + if (router_extrainfo_digest_is_me(d)) + sd = &(router_get_my_extrainfo()->cache_info); + else + sd = extrainfo_get_by_descriptor_digest(d); + } + if (sd) { + const char *body = signed_descriptor_get_body(sd); + if (body) + *answer = tor_strndup(body, sd->signed_descriptor_len); + } + } + } + + return 0; +} + +/** Given a smartlist of 20-byte digests, return a newly allocated string + * containing each of those digests in order, formatted in HEX, and terminated + * with a newline. */ +static char * +digest_list_to_string(const smartlist_t *sl) +{ + int len; + char *result, *s; + + /* Allow for newlines, and a \0 at the end */ + len = smartlist_len(sl) * (HEX_DIGEST_LEN + 1) + 1; + result = tor_malloc_zero(len); + + s = result; + SMARTLIST_FOREACH_BEGIN(sl, const char *, digest) { + base16_encode(s, HEX_DIGEST_LEN + 1, digest, DIGEST_LEN); + s[HEX_DIGEST_LEN] = '\n'; + s += HEX_DIGEST_LEN + 1; + } SMARTLIST_FOREACH_END(digest); + *s = '\0'; + + return result; +} + +/** Turn a download_status_t into a human-readable description in a newly + * allocated string. The format is specified in control-spec.txt, under + * the documentation for "GETINFO download/..." . */ +static char * +download_status_to_string(const download_status_t *dl) +{ + char *rv = NULL; + char tbuf[ISO_TIME_LEN+1]; + const char *schedule_str, *want_authority_str; + const char *increment_on_str, *backoff_str; + + if (dl) { + /* Get some substrings of the eventual output ready */ + format_iso_time(tbuf, download_status_get_next_attempt_at(dl)); + + switch (dl->schedule) { + case DL_SCHED_GENERIC: + schedule_str = "DL_SCHED_GENERIC"; + break; + case DL_SCHED_CONSENSUS: + schedule_str = "DL_SCHED_CONSENSUS"; + break; + case DL_SCHED_BRIDGE: + schedule_str = "DL_SCHED_BRIDGE"; + break; + default: + schedule_str = "unknown"; + break; + } + + switch (dl->want_authority) { + case DL_WANT_ANY_DIRSERVER: + want_authority_str = "DL_WANT_ANY_DIRSERVER"; + break; + case DL_WANT_AUTHORITY: + want_authority_str = "DL_WANT_AUTHORITY"; + break; + default: + want_authority_str = "unknown"; + break; + } + + switch (dl->increment_on) { + case DL_SCHED_INCREMENT_FAILURE: + increment_on_str = "DL_SCHED_INCREMENT_FAILURE"; + break; + case DL_SCHED_INCREMENT_ATTEMPT: + increment_on_str = "DL_SCHED_INCREMENT_ATTEMPT"; + break; + default: + increment_on_str = "unknown"; + break; + } + + backoff_str = "DL_SCHED_RANDOM_EXPONENTIAL"; + + /* Now assemble them */ + tor_asprintf(&rv, + "next-attempt-at %s\n" + "n-download-failures %u\n" + "n-download-attempts %u\n" + "schedule %s\n" + "want-authority %s\n" + "increment-on %s\n" + "backoff %s\n" + "last-backoff-position %u\n" + "last-delay-used %d\n", + tbuf, + dl->n_download_failures, + dl->n_download_attempts, + schedule_str, + want_authority_str, + increment_on_str, + backoff_str, + dl->last_backoff_position, + dl->last_delay_used); + } + + return rv; +} + +/** Handle the consensus download cases for getinfo_helper_downloads() */ +STATIC void +getinfo_helper_downloads_networkstatus(const char *flavor, + download_status_t **dl_to_emit, + const char **errmsg) +{ + /* + * We get the one for the current bootstrapped status by default, or + * take an extra /bootstrap or /running suffix + */ + if (strcmp(flavor, "ns") == 0) { + *dl_to_emit = networkstatus_get_dl_status_by_flavor(FLAV_NS); + } else if (strcmp(flavor, "ns/bootstrap") == 0) { + *dl_to_emit = networkstatus_get_dl_status_by_flavor_bootstrap(FLAV_NS); + } else if (strcmp(flavor, "ns/running") == 0 ) { + *dl_to_emit = networkstatus_get_dl_status_by_flavor_running(FLAV_NS); + } else if (strcmp(flavor, "microdesc") == 0) { + *dl_to_emit = networkstatus_get_dl_status_by_flavor(FLAV_MICRODESC); + } else if (strcmp(flavor, "microdesc/bootstrap") == 0) { + *dl_to_emit = + networkstatus_get_dl_status_by_flavor_bootstrap(FLAV_MICRODESC); + } else if (strcmp(flavor, "microdesc/running") == 0) { + *dl_to_emit = + networkstatus_get_dl_status_by_flavor_running(FLAV_MICRODESC); + } else { + *errmsg = "Unknown flavor"; + } +} + +/** Handle the cert download cases for getinfo_helper_downloads() */ +STATIC void +getinfo_helper_downloads_cert(const char *fp_sk_req, + download_status_t **dl_to_emit, + smartlist_t **digest_list, + const char **errmsg) +{ + const char *sk_req; + char id_digest[DIGEST_LEN]; + char sk_digest[DIGEST_LEN]; + + /* + * We have to handle four cases; fp_sk_req is the request with + * a prefix of "downloads/cert/" snipped off. + * + * Case 1: fp_sk_req = "fps" + * - We should emit a digest_list with a list of all the identity + * fingerprints that can be queried for certificate download status; + * get it by calling list_authority_ids_with_downloads(). + * + * Case 2: fp_sk_req = "fp/" for some fingerprint fp + * - We want the default certificate for this identity fingerprint's + * download status; this is the download we get from URLs starting + * in /fp/ on the directory server. We can get it with + * id_only_download_status_for_authority_id(). + * + * Case 3: fp_sk_req = "fp//sks" for some fingerprint fp + * - We want a list of all signing key digests for this identity + * fingerprint which can be queried for certificate download status. + * Get it with list_sk_digests_for_authority_id(). + * + * Case 4: fp_sk_req = "fp//" for some fingerprint fp and + * signing key digest sk + * - We want the download status for the certificate for this specific + * signing key and fingerprint. These correspond to the ones we get + * from URLs starting in /fp-sk/ on the directory server. Get it with + * list_sk_digests_for_authority_id(). + */ + + if (strcmp(fp_sk_req, "fps") == 0) { + *digest_list = list_authority_ids_with_downloads(); + if (!(*digest_list)) { + *errmsg = "Failed to get list of authority identity digests (!)"; + } + } else if (!strcmpstart(fp_sk_req, "fp/")) { + fp_sk_req += strlen("fp/"); + /* Okay, look for another / to tell the fp from fp-sk cases */ + sk_req = strchr(fp_sk_req, '/'); + if (sk_req) { + /* okay, split it here and try to parse */ + if (base16_decode(id_digest, DIGEST_LEN, + fp_sk_req, sk_req - fp_sk_req) == DIGEST_LEN) { + /* Skip past the '/' */ + ++sk_req; + if (strcmp(sk_req, "sks") == 0) { + /* We're asking for the list of signing key fingerprints */ + *digest_list = list_sk_digests_for_authority_id(id_digest); + if (!(*digest_list)) { + *errmsg = "Failed to get list of signing key digests for this " + "authority identity digest"; + } + } else { + /* We've got a signing key digest */ + if (base16_decode(sk_digest, DIGEST_LEN, + sk_req, strlen(sk_req)) == DIGEST_LEN) { + *dl_to_emit = + download_status_for_authority_id_and_sk(id_digest, sk_digest); + if (!(*dl_to_emit)) { + *errmsg = "Failed to get download status for this identity/" + "signing key digest pair"; + } + } else { + *errmsg = "That didn't look like a signing key digest"; + } + } + } else { + *errmsg = "That didn't look like an identity digest"; + } + } else { + /* We're either in downloads/certs/fp/, or we can't parse */ + if (strlen(fp_sk_req) == HEX_DIGEST_LEN) { + if (base16_decode(id_digest, DIGEST_LEN, + fp_sk_req, strlen(fp_sk_req)) == DIGEST_LEN) { + *dl_to_emit = id_only_download_status_for_authority_id(id_digest); + if (!(*dl_to_emit)) { + *errmsg = "Failed to get download status for this authority " + "identity digest"; + } + } else { + *errmsg = "That didn't look like a digest"; + } + } else { + *errmsg = "That didn't look like a digest"; + } + } + } else { + *errmsg = "Unknown certificate download status query"; + } +} + +/** Handle the routerdesc download cases for getinfo_helper_downloads() */ +STATIC void +getinfo_helper_downloads_desc(const char *desc_req, + download_status_t **dl_to_emit, + smartlist_t **digest_list, + const char **errmsg) +{ + char desc_digest[DIGEST_LEN]; + /* + * Two cases to handle here: + * + * Case 1: desc_req = "descs" + * - Emit a list of all router descriptor digests, which we get by + * calling router_get_descriptor_digests(); this can return NULL + * if we have no current ns-flavor consensus. + * + * Case 2: desc_req = + * - Check on the specified fingerprint and emit its download_status_t + * using router_get_dl_status_by_descriptor_digest(). + */ + + if (strcmp(desc_req, "descs") == 0) { + *digest_list = router_get_descriptor_digests(); + if (!(*digest_list)) { + *errmsg = "We don't seem to have a networkstatus-flavored consensus"; + } + /* + * Microdescs don't use the download_status_t mechanism, so we don't + * answer queries about their downloads here; see microdesc.c. + */ + } else if (strlen(desc_req) == HEX_DIGEST_LEN) { + if (base16_decode(desc_digest, DIGEST_LEN, + desc_req, strlen(desc_req)) == DIGEST_LEN) { + /* Okay we got a digest-shaped thing; try asking for it */ + *dl_to_emit = router_get_dl_status_by_descriptor_digest(desc_digest); + if (!(*dl_to_emit)) { + *errmsg = "No such descriptor digest found"; + } + } else { + *errmsg = "That didn't look like a digest"; + } + } else { + *errmsg = "Unknown router descriptor download status query"; + } +} + +/** Handle the bridge download cases for getinfo_helper_downloads() */ +STATIC void +getinfo_helper_downloads_bridge(const char *bridge_req, + download_status_t **dl_to_emit, + smartlist_t **digest_list, + const char **errmsg) +{ + char bridge_digest[DIGEST_LEN]; + /* + * Two cases to handle here: + * + * Case 1: bridge_req = "bridges" + * - Emit a list of all bridge identity digests, which we get by + * calling list_bridge_identities(); this can return NULL if we are + * not using bridges. + * + * Case 2: bridge_req = + * - Check on the specified fingerprint and emit its download_status_t + * using get_bridge_dl_status_by_id(). + */ + + if (strcmp(bridge_req, "bridges") == 0) { + *digest_list = list_bridge_identities(); + if (!(*digest_list)) { + *errmsg = "We don't seem to be using bridges"; + } + } else if (strlen(bridge_req) == HEX_DIGEST_LEN) { + if (base16_decode(bridge_digest, DIGEST_LEN, + bridge_req, strlen(bridge_req)) == DIGEST_LEN) { + /* Okay we got a digest-shaped thing; try asking for it */ + *dl_to_emit = get_bridge_dl_status_by_id(bridge_digest); + if (!(*dl_to_emit)) { + *errmsg = "No such bridge identity digest found"; + } + } else { + *errmsg = "That didn't look like a digest"; + } + } else { + *errmsg = "Unknown bridge descriptor download status query"; + } +} + +/** Implementation helper for GETINFO: knows the answers for questions about + * download status information. */ +STATIC int +getinfo_helper_downloads(control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg) +{ + download_status_t *dl_to_emit = NULL; + smartlist_t *digest_list = NULL; + + /* Assert args are sane */ + tor_assert(control_conn != NULL); + tor_assert(question != NULL); + tor_assert(answer != NULL); + tor_assert(errmsg != NULL); + + /* We check for this later to see if we should supply a default */ + *errmsg = NULL; + + /* Are we after networkstatus downloads? */ + if (!strcmpstart(question, "downloads/networkstatus/")) { + getinfo_helper_downloads_networkstatus( + question + strlen("downloads/networkstatus/"), + &dl_to_emit, errmsg); + /* Certificates? */ + } else if (!strcmpstart(question, "downloads/cert/")) { + getinfo_helper_downloads_cert( + question + strlen("downloads/cert/"), + &dl_to_emit, &digest_list, errmsg); + /* Router descriptors? */ + } else if (!strcmpstart(question, "downloads/desc/")) { + getinfo_helper_downloads_desc( + question + strlen("downloads/desc/"), + &dl_to_emit, &digest_list, errmsg); + /* Bridge descriptors? */ + } else if (!strcmpstart(question, "downloads/bridge/")) { + getinfo_helper_downloads_bridge( + question + strlen("downloads/bridge/"), + &dl_to_emit, &digest_list, errmsg); + } else { + *errmsg = "Unknown download status query"; + } + + if (dl_to_emit) { + *answer = download_status_to_string(dl_to_emit); + + return 0; + } else if (digest_list) { + *answer = digest_list_to_string(digest_list); + SMARTLIST_FOREACH(digest_list, void *, s, tor_free(s)); + smartlist_free(digest_list); + + return 0; + } else { + if (!(*errmsg)) { + *errmsg = "Unknown error"; + } + + return -1; + } +} + +/** Implementation helper for GETINFO: knows how to generate summaries of the + * current states of things we send events about. */ +static int +getinfo_helper_events(control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg) +{ + const or_options_t *options = get_options(); + (void) control_conn; + if (!strcmp(question, "circuit-status")) { + smartlist_t *status = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ_) { + origin_circuit_t *circ; + char *circdesc; + const char *state; + if (! CIRCUIT_IS_ORIGIN(circ_) || circ_->marked_for_close) + continue; + circ = TO_ORIGIN_CIRCUIT(circ_); + + if (circ->base_.state == CIRCUIT_STATE_OPEN) + state = "BUILT"; + else if (circ->base_.state == CIRCUIT_STATE_GUARD_WAIT) + state = "GUARD_WAIT"; + else if (circ->cpath) + state = "EXTENDED"; + else + state = "LAUNCHED"; + + circdesc = circuit_describe_status_for_controller(circ); + + smartlist_add_asprintf(status, "%lu %s%s%s", + (unsigned long)circ->global_identifier, + state, *circdesc ? " " : "", circdesc); + tor_free(circdesc); + } + SMARTLIST_FOREACH_END(circ_); + *answer = smartlist_join_strings(status, "\r\n", 0, NULL); + SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); + smartlist_free(status); + } else if (!strcmp(question, "stream-status")) { + smartlist_t *conns = get_connection_array(); + smartlist_t *status = smartlist_new(); + char buf[256]; + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { + const char *state; + entry_connection_t *conn; + circuit_t *circ; + origin_circuit_t *origin_circ = NULL; + if (base_conn->type != CONN_TYPE_AP || + base_conn->marked_for_close || + base_conn->state == AP_CONN_STATE_SOCKS_WAIT || + base_conn->state == AP_CONN_STATE_NATD_WAIT) + continue; + conn = TO_ENTRY_CONN(base_conn); + switch (base_conn->state) + { + case AP_CONN_STATE_CONTROLLER_WAIT: + case AP_CONN_STATE_CIRCUIT_WAIT: + if (conn->socks_request && + SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) + state = "NEWRESOLVE"; + else + state = "NEW"; + break; + case AP_CONN_STATE_RENDDESC_WAIT: + case AP_CONN_STATE_CONNECT_WAIT: + state = "SENTCONNECT"; break; + case AP_CONN_STATE_RESOLVE_WAIT: + state = "SENTRESOLVE"; break; + case AP_CONN_STATE_OPEN: + state = "SUCCEEDED"; break; + default: + log_warn(LD_BUG, "Asked for stream in unknown state %d", + base_conn->state); + continue; + } + circ = circuit_get_by_edge_conn(ENTRY_TO_EDGE_CONN(conn)); + if (circ && CIRCUIT_IS_ORIGIN(circ)) + origin_circ = TO_ORIGIN_CIRCUIT(circ); + write_stream_target_to_buf(conn, buf, sizeof(buf)); + smartlist_add_asprintf(status, "%lu %s %lu %s", + (unsigned long) base_conn->global_identifier,state, + origin_circ? + (unsigned long)origin_circ->global_identifier : 0ul, + buf); + } SMARTLIST_FOREACH_END(base_conn); + *answer = smartlist_join_strings(status, "\r\n", 0, NULL); + SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); + smartlist_free(status); + } else if (!strcmp(question, "orconn-status")) { + smartlist_t *conns = get_connection_array(); + smartlist_t *status = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { + const char *state; + char name[128]; + or_connection_t *conn; + if (base_conn->type != CONN_TYPE_OR || base_conn->marked_for_close) + continue; + conn = TO_OR_CONN(base_conn); + if (conn->base_.state == OR_CONN_STATE_OPEN) + state = "CONNECTED"; + else if (conn->nickname) + state = "LAUNCHED"; + else + state = "NEW"; + orconn_target_get_name(name, sizeof(name), conn); + smartlist_add_asprintf(status, "%s %s", name, state); + } SMARTLIST_FOREACH_END(base_conn); + *answer = smartlist_join_strings(status, "\r\n", 0, NULL); + SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); + smartlist_free(status); + } else if (!strcmpstart(question, "address-mappings/")) { + time_t min_e, max_e; + smartlist_t *mappings; + question += strlen("address-mappings/"); + if (!strcmp(question, "all")) { + min_e = 0; max_e = TIME_MAX; + } else if (!strcmp(question, "cache")) { + min_e = 2; max_e = TIME_MAX; + } else if (!strcmp(question, "config")) { + min_e = 0; max_e = 0; + } else if (!strcmp(question, "control")) { + min_e = 1; max_e = 1; + } else { + return 0; + } + mappings = smartlist_new(); + addressmap_get_mappings(mappings, min_e, max_e, 1); + *answer = smartlist_join_strings(mappings, "\r\n", 0, NULL); + SMARTLIST_FOREACH(mappings, char *, cp, tor_free(cp)); + smartlist_free(mappings); + } else if (!strcmpstart(question, "status/")) { + /* Note that status/ is not a catch-all for events; there's only supposed + * to be a status GETINFO if there's a corresponding STATUS event. */ + if (!strcmp(question, "status/circuit-established")) { + *answer = tor_strdup(have_completed_a_circuit() ? "1" : "0"); + } else if (!strcmp(question, "status/enough-dir-info")) { + *answer = tor_strdup(router_have_minimum_dir_info() ? "1" : "0"); + } else if (!strcmp(question, "status/good-server-descriptor") || + !strcmp(question, "status/accepted-server-descriptor")) { + /* They're equivalent for now, until we can figure out how to make + * good-server-descriptor be what we want. See comment in + * control-spec.txt. */ + *answer = tor_strdup(directories_have_accepted_server_descriptor() + ? "1" : "0"); + } else if (!strcmp(question, "status/reachability-succeeded/or")) { + *answer = tor_strdup(check_whether_orport_reachable(options) ? + "1" : "0"); + } else if (!strcmp(question, "status/reachability-succeeded/dir")) { + *answer = tor_strdup(check_whether_dirport_reachable(options) ? + "1" : "0"); + } else if (!strcmp(question, "status/reachability-succeeded")) { + tor_asprintf(answer, "OR=%d DIR=%d", + check_whether_orport_reachable(options) ? 1 : 0, + check_whether_dirport_reachable(options) ? 1 : 0); + } else if (!strcmp(question, "status/bootstrap-phase")) { + *answer = control_event_boot_last_msg(); + } else if (!strcmpstart(question, "status/version/")) { + int is_server = server_mode(options); + networkstatus_t *c = networkstatus_get_latest_consensus(); + version_status_t status; + const char *recommended; + if (c) { + recommended = is_server ? c->server_versions : c->client_versions; + status = tor_version_is_obsolete(VERSION, recommended); + } else { + recommended = "?"; + status = VS_UNKNOWN; + } + + if (!strcmp(question, "status/version/recommended")) { + *answer = tor_strdup(recommended); + return 0; + } + if (!strcmp(question, "status/version/current")) { + switch (status) + { + case VS_RECOMMENDED: *answer = tor_strdup("recommended"); break; + case VS_OLD: *answer = tor_strdup("obsolete"); break; + case VS_NEW: *answer = tor_strdup("new"); break; + case VS_NEW_IN_SERIES: *answer = tor_strdup("new in series"); break; + case VS_UNRECOMMENDED: *answer = tor_strdup("unrecommended"); break; + case VS_EMPTY: *answer = tor_strdup("none recommended"); break; + case VS_UNKNOWN: *answer = tor_strdup("unknown"); break; + default: tor_fragile_assert(); + } + } + } else if (!strcmp(question, "status/clients-seen")) { + char *bridge_stats = geoip_get_bridge_stats_controller(time(NULL)); + if (!bridge_stats) { + *errmsg = "No bridge-client stats available"; + return -1; + } + *answer = bridge_stats; + } else if (!strcmp(question, "status/fresh-relay-descs")) { + if (!server_mode(options)) { + *errmsg = "Only relays have descriptors"; + return -1; + } + routerinfo_t *r; + extrainfo_t *e; + if (router_build_fresh_descriptor(&r, &e) < 0) { + *errmsg = "Error generating descriptor"; + return -1; + } + size_t size = r->cache_info.signed_descriptor_len + 1; + if (e) { + size += e->cache_info.signed_descriptor_len + 1; + } + tor_assert(r->cache_info.signed_descriptor_len); + char *descs = tor_malloc(size); + char *cp = descs; + memcpy(cp, signed_descriptor_get_body(&r->cache_info), + r->cache_info.signed_descriptor_len); + cp += r->cache_info.signed_descriptor_len - 1; + if (e) { + if (cp[0] == '\0') { + cp[0] = '\n'; + } else if (cp[0] != '\n') { + cp[1] = '\n'; + cp++; + } + memcpy(cp, signed_descriptor_get_body(&e->cache_info), + e->cache_info.signed_descriptor_len); + cp += e->cache_info.signed_descriptor_len - 1; + } + if (cp[0] == '\n') { + cp[0] = '\0'; + } else if (cp[0] != '\0') { + cp[1] = '\0'; + } + *answer = descs; + routerinfo_free(r); + extrainfo_free(e); + } else { + return 0; + } + } + return 0; +} + +/** Implementation helper for GETINFO: knows how to enumerate hidden services + * created via the control port. */ +STATIC int +getinfo_helper_onions(control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg) +{ + smartlist_t *onion_list = NULL; + (void) errmsg; /* no errors from this method */ + + if (control_conn && !strcmp(question, "onions/current")) { + onion_list = control_conn->ephemeral_onion_services; + } else if (!strcmp(question, "onions/detached")) { + onion_list = get_detached_onion_services(); + } else { + return 0; + } + if (!onion_list || smartlist_len(onion_list) == 0) { + if (answer) { + *answer = tor_strdup(""); + } + } else { + if (answer) { + *answer = smartlist_join_strings(onion_list, "\r\n", 0, NULL); + } + } + + return 0; +} + +/** Implementation helper for GETINFO: answers queries about network + * liveness. */ +static int +getinfo_helper_liveness(control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg) +{ + (void)control_conn; + (void)errmsg; + if (strcmp(question, "network-liveness") == 0) { + if (get_cached_network_liveness()) { + *answer = tor_strdup("up"); + } else { + *answer = tor_strdup("down"); + } + } + + return 0; +} + +/** Implementation helper for GETINFO: answers queries about shared random + * value. */ +static int +getinfo_helper_sr(control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg) +{ + (void) control_conn; + (void) errmsg; + + if (!strcmp(question, "sr/current")) { + *answer = sr_get_current_for_control(); + } else if (!strcmp(question, "sr/previous")) { + *answer = sr_get_previous_for_control(); + } + /* Else statement here is unrecognized key so do nothing. */ + + return 0; +} + +/** Callback function for GETINFO: on a given control connection, try to + * answer the question q and store the newly-allocated answer in + * *a. If an internal error occurs, return -1 and optionally set + * *error_out to point to an error message to be delivered to the + * controller. On success, _or if the key is not recognized_, return 0. Do not + * set a if the key is not recognized but you may set error_out + * to improve the error message. + */ +typedef int (*getinfo_helper_t)(control_connection_t *, + const char *q, char **a, + const char **error_out); + +/** A single item for the GETINFO question-to-answer-function table. */ +typedef struct getinfo_item_t { + const char *varname; /**< The value (or prefix) of the question. */ + getinfo_helper_t fn; /**< The function that knows the answer: NULL if + * this entry is documentation-only. */ + const char *desc; /**< Description of the variable. */ + int is_prefix; /** Must varname match exactly, or must it be a prefix? */ +} getinfo_item_t; + +#define ITEM(name, fn, desc) { name, getinfo_helper_##fn, desc, 0 } +#define PREFIX(name, fn, desc) { name, getinfo_helper_##fn, desc, 1 } +#define DOC(name, desc) { name, NULL, desc, 0 } + +/** Table mapping questions accepted by GETINFO to the functions that know how + * to answer them. */ +static const getinfo_item_t getinfo_items[] = { + ITEM("version", misc, "The current version of Tor."), + ITEM("bw-event-cache", misc, "Cached BW events for a short interval."), + ITEM("config-file", misc, "Current location of the \"torrc\" file."), + ITEM("config-defaults-file", misc, "Current location of the defaults file."), + ITEM("config-text", misc, + "Return the string that would be written by a saveconf command."), + ITEM("config-can-saveconf", misc, + "Is it possible to save the configuration to the \"torrc\" file?"), + ITEM("accounting/bytes", accounting, + "Number of bytes read/written so far in the accounting interval."), + ITEM("accounting/bytes-left", accounting, + "Number of bytes left to write/read so far in the accounting interval."), + ITEM("accounting/enabled", accounting, "Is accounting currently enabled?"), + ITEM("accounting/hibernating", accounting, "Are we hibernating or awake?"), + ITEM("accounting/interval-start", accounting, + "Time when the accounting period starts."), + ITEM("accounting/interval-end", accounting, + "Time when the accounting period ends."), + ITEM("accounting/interval-wake", accounting, + "Time to wake up in this accounting period."), + ITEM("helper-nodes", entry_guards, NULL), /* deprecated */ + ITEM("entry-guards", entry_guards, + "Which nodes are we using as entry guards?"), + ITEM("fingerprint", misc, NULL), + PREFIX("config/", config, "Current configuration values."), + DOC("config/names", + "List of configuration options, types, and documentation."), + DOC("config/defaults", + "List of default values for configuration options. " + "See also config/names"), + PREFIX("current-time/", current_time, "Current time."), + DOC("current-time/local", "Current time on the local system."), + DOC("current-time/utc", "Current UTC time."), + PREFIX("downloads/networkstatus/", downloads, + "Download statuses for networkstatus objects"), + DOC("downloads/networkstatus/ns", + "Download status for current-mode networkstatus download"), + DOC("downloads/networkstatus/ns/bootstrap", + "Download status for bootstrap-time networkstatus download"), + DOC("downloads/networkstatus/ns/running", + "Download status for run-time networkstatus download"), + DOC("downloads/networkstatus/microdesc", + "Download status for current-mode microdesc download"), + DOC("downloads/networkstatus/microdesc/bootstrap", + "Download status for bootstrap-time microdesc download"), + DOC("downloads/networkstatus/microdesc/running", + "Download status for run-time microdesc download"), + PREFIX("downloads/cert/", downloads, + "Download statuses for certificates, by id fingerprint and " + "signing key"), + DOC("downloads/cert/fps", + "List of authority fingerprints for which any download statuses " + "exist"), + DOC("downloads/cert/fp/", + "Download status for with the default signing key; corresponds " + "to /fp/ URLs on directory server."), + DOC("downloads/cert/fp//sks", + "List of signing keys for which specific download statuses are " + "available for this id fingerprint"), + DOC("downloads/cert/fp//", + "Download status for with signing key ; corresponds " + "to /fp-sk/ URLs on directory server."), + PREFIX("downloads/desc/", downloads, + "Download statuses for router descriptors, by descriptor digest"), + DOC("downloads/desc/descs", + "Return a list of known router descriptor digests"), + DOC("downloads/desc/", + "Return a download status for a given descriptor digest"), + PREFIX("downloads/bridge/", downloads, + "Download statuses for bridge descriptors, by bridge identity " + "digest"), + DOC("downloads/bridge/bridges", + "Return a list of configured bridge identity digests with download " + "statuses"), + DOC("downloads/bridge/", + "Return a download status for a given bridge identity digest"), + ITEM("info/names", misc, + "List of GETINFO options, types, and documentation."), + ITEM("events/names", misc, + "Events that the controller can ask for with SETEVENTS."), + ITEM("signal/names", misc, "Signal names recognized by the SIGNAL command"), + ITEM("features/names", misc, "What arguments can USEFEATURE take?"), + PREFIX("desc/id/", dir, "Router descriptors by ID."), + PREFIX("desc/name/", dir, "Router descriptors by nickname."), + ITEM("desc/all-recent", dir, + "All non-expired, non-superseded router descriptors."), + ITEM("desc/download-enabled", dir, + "Do we try to download router descriptors?"), + ITEM("desc/all-recent-extrainfo-hack", dir, NULL), /* Hack. */ + ITEM("md/all", dir, "All known microdescriptors."), + PREFIX("md/id/", dir, "Microdescriptors by ID"), + PREFIX("md/name/", dir, "Microdescriptors by name"), + ITEM("md/download-enabled", dir, + "Do we try to download microdescriptors?"), + PREFIX("extra-info/digest/", dir, "Extra-info documents by digest."), + PREFIX("hs/client/desc/id", dir, + "Hidden Service descriptor in client's cache by onion."), + PREFIX("hs/service/desc/id/", dir, + "Hidden Service descriptor in services's cache by onion."), + PREFIX("net/listeners/", listeners, "Bound addresses by type"), + ITEM("ns/all", networkstatus, + "Brief summary of router status (v2 directory format)"), + PREFIX("ns/id/", networkstatus, + "Brief summary of router status by ID (v2 directory format)."), + PREFIX("ns/name/", networkstatus, + "Brief summary of router status by nickname (v2 directory format)."), + PREFIX("ns/purpose/", networkstatus, + "Brief summary of router status by purpose (v2 directory format)."), + PREFIX("consensus/", networkstatus, + "Information about and from the ns consensus."), + ITEM("network-status", dir, + "Brief summary of router status (v1 directory format)"), + ITEM("network-liveness", liveness, + "Current opinion on whether the network is live"), + ITEM("circuit-status", events, "List of current circuits originating here."), + ITEM("stream-status", events,"List of current streams."), + ITEM("orconn-status", events, "A list of current OR connections."), + ITEM("dormant", misc, + "Is Tor dormant (not building circuits because it's idle)?"), + PREFIX("address-mappings/", events, NULL), + DOC("address-mappings/all", "Current address mappings."), + DOC("address-mappings/cache", "Current cached DNS replies."), + DOC("address-mappings/config", + "Current address mappings from configuration."), + DOC("address-mappings/control", "Current address mappings from controller."), + PREFIX("status/", events, NULL), + DOC("status/circuit-established", + "Whether we think client functionality is working."), + DOC("status/enough-dir-info", + "Whether we have enough up-to-date directory information to build " + "circuits."), + DOC("status/bootstrap-phase", + "The last bootstrap phase status event that Tor sent."), + DOC("status/clients-seen", + "Breakdown of client countries seen by a bridge."), + DOC("status/fresh-relay-descs", + "A fresh relay/ei descriptor pair for Tor's current state. Not stored."), + DOC("status/version/recommended", "List of currently recommended versions."), + DOC("status/version/current", "Status of the current version."), + ITEM("address", misc, "IP address of this Tor host, if we can guess it."), + ITEM("traffic/read", misc,"Bytes read since the process was started."), + ITEM("traffic/written", misc, + "Bytes written since the process was started."), + ITEM("uptime", misc, "Uptime of the Tor daemon in seconds."), + ITEM("process/pid", misc, "Process id belonging to the main tor process."), + ITEM("process/uid", misc, "User id running the tor process."), + ITEM("process/user", misc, + "Username under which the tor process is running."), + ITEM("process/descriptor-limit", misc, "File descriptor limit."), + ITEM("limits/max-mem-in-queues", misc, "Actual limit on memory in queues"), + PREFIX("desc-annotations/id/", dir, "Router annotations by hexdigest."), + PREFIX("dir/server/", dir,"Router descriptors as retrieved from a DirPort."), + PREFIX("dir/status/", dir, + "v2 networkstatus docs as retrieved from a DirPort."), + ITEM("dir/status-vote/current/consensus", dir, + "v3 Networkstatus consensus as retrieved from a DirPort."), + ITEM("exit-policy/default", policies, + "The default value appended to the configured exit policy."), + ITEM("exit-policy/reject-private/default", policies, + "The default rules appended to the configured exit policy by" + " ExitPolicyRejectPrivate."), + ITEM("exit-policy/reject-private/relay", policies, + "The relay-specific rules appended to the configured exit policy by" + " ExitPolicyRejectPrivate and/or ExitPolicyRejectLocalInterfaces."), + ITEM("exit-policy/full", policies, "The entire exit policy of onion router"), + ITEM("exit-policy/ipv4", policies, "IPv4 parts of exit policy"), + ITEM("exit-policy/ipv6", policies, "IPv6 parts of exit policy"), + PREFIX("ip-to-country/", geoip, "Perform a GEOIP lookup"), + ITEM("onions/current", onions, + "Onion services owned by the current control connection."), + ITEM("onions/detached", onions, + "Onion services detached from the control connection."), + ITEM("sr/current", sr, "Get current shared random value."), + ITEM("sr/previous", sr, "Get previous shared random value."), + { NULL, NULL, NULL, 0 } +}; + +/** Allocate and return a list of recognized GETINFO options. */ +static char * +list_getinfo_options(void) +{ + int i; + smartlist_t *lines = smartlist_new(); + char *ans; + for (i = 0; getinfo_items[i].varname; ++i) { + if (!getinfo_items[i].desc) + continue; + + smartlist_add_asprintf(lines, "%s%s -- %s\n", + getinfo_items[i].varname, + getinfo_items[i].is_prefix ? "*" : "", + getinfo_items[i].desc); + } + smartlist_sort_strings(lines); + + ans = smartlist_join_strings(lines, "", 0, NULL); + SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); + smartlist_free(lines); + + return ans; +} + +/** Lookup the 'getinfo' entry question, and return + * the answer in *answer (or NULL if key not recognized). + * Return 0 if success or unrecognized, or -1 if recognized but + * internal error. */ +static int +handle_getinfo_helper(control_connection_t *control_conn, + const char *question, char **answer, + const char **err_out) +{ + int i; + *answer = NULL; /* unrecognized key by default */ + + for (i = 0; getinfo_items[i].varname; ++i) { + int match; + if (getinfo_items[i].is_prefix) + match = !strcmpstart(question, getinfo_items[i].varname); + else + match = !strcmp(question, getinfo_items[i].varname); + if (match) { + tor_assert(getinfo_items[i].fn); + return getinfo_items[i].fn(control_conn, question, answer, err_out); + } + } + + return 0; /* unrecognized */ +} + +const control_cmd_syntax_t getinfo_syntax = { + .max_args = UINT_MAX, +}; + +/** Called when we receive a GETINFO command. Try to fetch all requested + * information, and reply with information or error message. */ +int +handle_control_getinfo(control_connection_t *conn, + const control_cmd_args_t *args) +{ + const smartlist_t *questions = args->args; + 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; + + if (handle_getinfo_helper(conn, q, &ans, &errmsg) < 0) { + if (!errmsg) + errmsg = "Internal error"; + control_write_endreply(conn, 551, errmsg); + 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); + } else { + smartlist_add_strdup(answers, q); + smartlist_add(answers, 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_write_endreply(conn, 552, (char *)smartlist_get(unrecognized, i)); + 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); + + done: + SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp)); + smartlist_free(answers); + SMARTLIST_FOREACH(unrecognized, char *, cp, tor_free(cp)); + smartlist_free(unrecognized); + + return 0; +} diff --git a/src/feature/control/control_getinfo.h b/src/feature/control/control_getinfo.h new file mode 100644 index 0000000000..52978686d8 --- /dev/null +++ b/src/feature/control/control_getinfo.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control.h + * \brief Header file for control.c. + **/ + +#ifndef TOR_CONTROL_GETINFO_H +#define TOR_CONTROL_GETINFO_H + +struct control_cmd_syntax_t; +struct control_cmd_args_t; +extern const struct control_cmd_syntax_t getinfo_syntax; + +int handle_control_getinfo(control_connection_t *conn, + const struct control_cmd_args_t *args); + +#ifdef CONTROL_GETINFO_PRIVATE +STATIC int getinfo_helper_onions( + control_connection_t *control_conn, + const char *question, + char **answer, + const char **errmsg); +STATIC void getinfo_helper_downloads_networkstatus( + const char *flavor, + download_status_t **dl_to_emit, + const char **errmsg); +STATIC void getinfo_helper_downloads_cert( + const char *fp_sk_req, + download_status_t **dl_to_emit, + smartlist_t **digest_list, + const char **errmsg); +STATIC void getinfo_helper_downloads_desc( + const char *desc_req, + download_status_t **dl_to_emit, + smartlist_t **digest_list, + const char **errmsg); +STATIC void getinfo_helper_downloads_bridge( + const char *bridge_req, + download_status_t **dl_to_emit, + smartlist_t **digest_list, + const char **errmsg); +STATIC int getinfo_helper_downloads( + control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg); +STATIC int getinfo_helper_dir( + control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg); +STATIC int getinfo_helper_current_time( + control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg); +#endif /* defined(CONTROL_GETINFO_PRIVATE) */ + +#endif /* !defined(TOR_CONTROL_GETINFO_H) */ diff --git a/src/feature/control/control_proto.c b/src/feature/control/control_proto.c new file mode 100644 index 0000000000..1dd62da2be --- /dev/null +++ b/src/feature/control/control_proto.c @@ -0,0 +1,276 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_proto.c + * \brief Formatting functions for controller data. + */ + +#include "core/or/or.h" + +#include "core/mainloop/connection.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/connection_edge.h" +#include "feature/control/control_proto.h" +#include "feature/nodelist/nodelist.h" + +#include "core/or/cpath_build_state_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/or_connection_st.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/socks_request_st.h" +#include "feature/control/control_connection_st.h" + +/** Append a NUL-terminated string s to the end of + * conn-\>outbuf. + */ +void +connection_write_str_to_buf(const char *s, control_connection_t *conn) +{ + size_t len = strlen(s); + connection_buf_add(s, len, TO_CONN(conn)); +} + +/** Acts like sprintf, but writes its formatted string to the end of + * conn-\>outbuf. */ +void +connection_printf_to_buf(control_connection_t *conn, const char *format, ...) +{ + va_list ap; + char *buf = NULL; + int len; + + va_start(ap,format); + len = tor_vasprintf(&buf, format, ap); + va_end(ap); + + if (len < 0) { + log_err(LD_BUG, "Unable to format string for controller."); + tor_assert(0); + } + + connection_buf_add(buf, (size_t)len, TO_CONN(conn)); + + tor_free(buf); +} + +/** Given a len-character string in data, made of lines + * terminated by CRLF, allocate a new string in *out, and copy the + * contents of data into *out, adding a period before any period + * that appears at the start of a line, and adding a period-CRLF line at + * the end. Replace all LF characters sequences with CRLF. Return the number + * of bytes in *out. + * + * This corresponds to CmdData in control-spec.txt. + */ +size_t +write_escaped_data(const char *data, size_t len, char **out) +{ + tor_assert(len < SIZE_MAX - 9); + size_t sz_out = len+8+1; + char *outp; + const char *start = data, *end; + size_t i; + int start_of_line; + for (i=0; i < len; ++i) { + if (data[i] == '\n') { + sz_out += 2; /* Maybe add a CR; maybe add a dot. */ + if (sz_out >= SIZE_T_CEILING) { + log_warn(LD_BUG, "Input to write_escaped_data was too long"); + *out = tor_strdup(".\r\n"); + return 3; + } + } + } + *out = outp = tor_malloc(sz_out); + end = data+len; + start_of_line = 1; + while (data < end) { + if (*data == '\n') { + if (data > start && data[-1] != '\r') + *outp++ = '\r'; + start_of_line = 1; + } else if (*data == '.') { + if (start_of_line) { + start_of_line = 0; + *outp++ = '.'; + } + } else { + start_of_line = 0; + } + *outp++ = *data++; + } + if (outp < *out+2 || fast_memcmp(outp-2, "\r\n", 2)) { + *outp++ = '\r'; + *outp++ = '\n'; + } + *outp++ = '.'; + *outp++ = '\r'; + *outp++ = '\n'; + *outp = '\0'; /* NUL-terminate just in case. */ + tor_assert(outp >= *out); + tor_assert((size_t)(outp - *out) <= sz_out); + return outp - *out; +} + +/** Given a len-character string in data, made of lines + * terminated by CRLF, allocate a new string in *out, and copy + * the contents of data into *out, removing any period + * that appears at the start of a line, and replacing all CRLF sequences + * with LF. Return the number of + * bytes in *out. + * + * This corresponds to CmdData in control-spec.txt. + */ +size_t +read_escaped_data(const char *data, size_t len, char **out) +{ + char *outp; + const char *next; + const char *end; + + *out = outp = tor_malloc(len+1); + + end = data+len; + + while (data < end) { + /* we're at the start of a line. */ + if (*data == '.') + ++data; + next = memchr(data, '\n', end-data); + if (next) { + size_t n_to_copy = next-data; + /* Don't copy a CR that precedes this LF. */ + if (n_to_copy && *(next-1) == '\r') + --n_to_copy; + memcpy(outp, data, n_to_copy); + outp += n_to_copy; + data = next+1; /* This will point at the start of the next line, + * or the end of the string, or a period. */ + } else { + memcpy(outp, data, end-data); + outp += (end-data); + *outp = '\0'; + return outp - *out; + } + *outp++ = '\n'; + } + + *outp = '\0'; + return outp - *out; +} + +/** Send a "DONE" message down the control connection conn. */ +void +send_control_done(control_connection_t *conn) +{ + control_write_endreply(conn, 250, "OK"); +} + +/** Write a reply to the control channel. + * + * @param conn control connection + * @param code numeric result code + * @param c separator character, usually ' ', '-', or '+' + * @param s string + */ +void +control_write_reply(control_connection_t *conn, int code, int c, const char *s) +{ + connection_printf_to_buf(conn, "%03d%c%s\r\n", code, c, s); +} + +/** Write a formatted reply to the control channel. + * + * @param conn control connection + * @param code numeric result code + * @param c separator character, usually ' ', '-', or '+' + * @param fmt format string + * @param ap va_list from caller + */ +void +control_vprintf_reply(control_connection_t *conn, int code, int c, + const char *fmt, va_list ap) +{ + char *buf = NULL; + int len; + + len = tor_vasprintf(&buf, fmt, ap); + if (len < 0) { + log_err(LD_BUG, "Unable to format string for controller."); + tor_assert(0); + } + control_write_reply(conn, code, c, buf); + tor_free(buf); +} + +/** Write an EndReplyLine */ +void +control_write_endreply(control_connection_t *conn, int code, const char *s) +{ + control_write_reply(conn, code, ' ', s); +} + +/** Write a formatted EndReplyLine */ +void +control_printf_endreply(control_connection_t *conn, int code, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + control_vprintf_reply(conn, code, ' ', fmt, ap); + va_end(ap); +} + +/** Write a MidReplyLine */ +void +control_write_midreply(control_connection_t *conn, int code, const char *s) +{ + control_write_reply(conn, code, '-', s); +} + +/** Write a formatted MidReplyLine */ +void +control_printf_midreply(control_connection_t *conn, int code, const char *fmt, + ...) +{ + va_list ap; + + va_start(ap, fmt); + control_vprintf_reply(conn, code, '-', fmt, ap); + va_end(ap); +} + +/** Write a DataReplyLine */ +void +control_write_datareply(control_connection_t *conn, int code, const char *s) +{ + control_write_reply(conn, code, '+', s); +} + +/** Write a formatted DataReplyLine */ +void +control_printf_datareply(control_connection_t *conn, int code, const char *fmt, + ...) +{ + va_list ap; + + va_start(ap, fmt); + control_vprintf_reply(conn, code, '+', fmt, ap); + va_end(ap); +} + +/** Write a CmdData */ +void +control_write_data(control_connection_t *conn, const char *data) +{ + char *esc = NULL; + size_t esc_len; + + esc_len = write_escaped_data(data, strlen(data), &esc); + connection_buf_add(esc, esc_len, TO_CONN(conn)); + tor_free(esc); +} diff --git a/src/feature/control/control_proto.h b/src/feature/control/control_proto.h new file mode 100644 index 0000000000..101b808d88 --- /dev/null +++ b/src/feature/control/control_proto.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control_proto.h + * \brief Header file for control_proto.c. + **/ + +#ifndef TOR_CONTROL_PROTO_H +#define TOR_CONTROL_PROTO_H + +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, ...) + CHECK_PRINTF(2,3); + +size_t write_escaped_data(const char *data, size_t len, char **out); +size_t read_escaped_data(const char *data, size_t len, char **out); +void send_control_done(control_connection_t *conn); + +void control_write_reply(control_connection_t *conn, int code, int c, + const char *s); +void control_vprintf_reply(control_connection_t *conn, int code, int c, + const char *fmt, va_list ap) + CHECK_PRINTF(4, 0); +void control_write_endreply(control_connection_t *conn, int code, + const char *s); +void control_printf_endreply(control_connection_t *conn, int code, + const char *fmt, ...) + CHECK_PRINTF(3, 4); +void control_write_midreply(control_connection_t *conn, int code, + const char *s); +void control_printf_midreply(control_connection_t *conn, int code, + const char *fmt, + ...) + CHECK_PRINTF(3, 4); +void control_write_datareply(control_connection_t *conn, int code, + const char *s); +void control_printf_datareply(control_connection_t *conn, int code, + const char *fmt, + ...) + CHECK_PRINTF(3, 4); +void control_write_data(control_connection_t *conn, const char *data); + +#endif /* !defined(TOR_CONTROL_PROTO_H) */ diff --git a/src/feature/control/fmt_serverstatus.c b/src/feature/control/fmt_serverstatus.c index a1ddd2119a..a80bf50ad9 100644 --- a/src/feature/control/fmt_serverstatus.c +++ b/src/feature/control/fmt_serverstatus.c @@ -66,11 +66,9 @@ list_server_status_v1(smartlist_t *routers, char **router_status_out, smartlist_t *rs_entries; time_t now = time(NULL); time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; - const or_options_t *options = get_options(); /* We include v2 dir auths here too, because they need to answer * controllers. Eventually we'll deprecate this whole function; * see also networkstatus_getinfo_by_purpose(). */ - int authdir = authdir_mode_publishes_statuses(options); tor_assert(router_status_out); rs_entries = smartlist_new(); @@ -78,10 +76,6 @@ list_server_status_v1(smartlist_t *routers, char **router_status_out, SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) { const node_t *node = node_get_by_id(ri->cache_info.identity_digest); tor_assert(node); - if (authdir) { - /* Update router status in routerinfo_t. */ - dirserv_set_router_is_running(ri, now); - } if (for_controller) { char name_buf[MAX_VERBOSE_NICKNAME_LEN+2]; char *cp = name_buf; diff --git a/src/feature/control/fmt_serverstatus.h b/src/feature/control/fmt_serverstatus.h index 4b95e5b59f..d9190cb7e1 100644 --- a/src/feature/control/fmt_serverstatus.h +++ b/src/feature/control/fmt_serverstatus.h @@ -15,4 +15,4 @@ int list_server_status_v1(smartlist_t *routers, char **router_status_out, int for_controller); -#endif +#endif /* !defined(TOR_FMT_SERVERSTATUS_H) */ diff --git a/src/feature/control/getinfo_geoip.h b/src/feature/control/getinfo_geoip.h index fe22137859..94759d0d18 100644 --- a/src/feature/control/getinfo_geoip.h +++ b/src/feature/control/getinfo_geoip.h @@ -11,4 +11,4 @@ int getinfo_helper_geoip(control_connection_t *control_conn, const char *question, char **answer, const char **errmsg); -#endif +#endif /* !defined(TOR_GETINFO_GEOIP_H) */ diff --git a/src/feature/dirauth/authmode.h b/src/feature/dirauth/authmode.h index 876a1f947b..48afc3cdb4 100644 --- a/src/feature/dirauth/authmode.h +++ b/src/feature/dirauth/authmode.h @@ -29,7 +29,7 @@ authdir_mode_v3(const or_options_t *options) #define have_module_dirauth() (1) -#else /* HAVE_MODULE_DIRAUTH */ +#else /* !(defined(HAVE_MODULE_DIRAUTH)) */ #define authdir_mode(options) (((void)(options)),0) #define authdir_mode_handles_descs(options,purpose) \ @@ -41,6 +41,6 @@ authdir_mode_v3(const or_options_t *options) #define have_module_dirauth() (0) -#endif /* HAVE_MODULE_DIRAUTH */ +#endif /* defined(HAVE_MODULE_DIRAUTH) */ -#endif /* TOR_MODE_H */ +#endif /* !defined(TOR_DIRAUTH_MODE_H) */ diff --git a/src/feature/dirauth/bridgeauth.c b/src/feature/dirauth/bridgeauth.c new file mode 100644 index 0000000000..4aaefc7a6d --- /dev/null +++ b/src/feature/dirauth/bridgeauth.c @@ -0,0 +1,55 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "core/or/or.h" +#include "feature/dirauth/bridgeauth.h" +#include "feature/dirauth/voteflags.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/relay/router.h" +#include "app/config/config.h" + +#include "feature/nodelist/routerinfo_st.h" + +/** Write out router status entries for all our bridge descriptors. Here, we + * also mark routers as running. */ +void +bridgeauth_dump_bridge_status_to_file(time_t now) +{ + char *status; + char *fname = NULL; + char *thresholds = NULL; + char *published_thresholds_and_status = NULL; + char published[ISO_TIME_LEN+1]; + const routerinfo_t *me = router_get_my_routerinfo(); + char fingerprint[FINGERPRINT_LEN+1]; + char *fingerprint_line = NULL; + + dirserv_set_bridges_running(now); + status = networkstatus_getinfo_by_purpose("bridge", now); + + if (me && crypto_pk_get_fingerprint(me->identity_pkey, + fingerprint, 0) >= 0) { + tor_asprintf(&fingerprint_line, "fingerprint %s\n", fingerprint); + } else { + log_warn(LD_BUG, "Error computing fingerprint for bridge status."); + } + format_iso_time(published, now); + dirserv_compute_bridge_flag_thresholds(); + thresholds = dirserv_get_flag_thresholds_line(); + tor_asprintf(&published_thresholds_and_status, + "published %s\nflag-thresholds %s\n%s%s", + published, thresholds, fingerprint_line ? fingerprint_line : "", + status); + fname = get_datadir_fname("networkstatus-bridges"); + if (write_str_to_file(fname,published_thresholds_and_status,0)<0) { + log_warn(LD_DIRSERV, "Unable to write networkstatus-bridges file."); + } + tor_free(thresholds); + tor_free(published_thresholds_and_status); + tor_free(fname); + tor_free(status); + tor_free(fingerprint_line); +} diff --git a/src/feature/dirauth/bridgeauth.h b/src/feature/dirauth/bridgeauth.h new file mode 100644 index 0000000000..4905e9c3ee --- /dev/null +++ b/src/feature/dirauth/bridgeauth.h @@ -0,0 +1,12 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_DIRAUTH_BRIDGEAUTH_H +#define TOR_DIRAUTH_BRIDGEAUTH_H + +void bridgeauth_dump_bridge_status_to_file(time_t now); + +#endif /* !defined(TOR_DIRAUTH_BRIDGEAUTH_H) */ diff --git a/src/feature/dirauth/bwauth.c b/src/feature/dirauth/bwauth.c index 1cfd8119df..e60c8b86bd 100644 --- a/src/feature/dirauth/bwauth.c +++ b/src/feature/dirauth/bwauth.c @@ -199,9 +199,32 @@ dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri) } /** - * Read the measured bandwidth list file, apply it to the list of - * vote_routerstatus_t and store all the headers in bw_file_headers. + * Read the measured bandwidth list from_file: + * - store all the headers in bw_file_headers, + * - apply bandwidth lines to the list of vote_routerstatus_t in + * routerstatuses, + * - cache bandwidth lines for dirserv_get_bandwidth_for_router(), + * - expire old entries in the measured bandwidth cache, and + * - store the DIGEST_SHA256 of the contents of the file in digest_out. + * * Returns -1 on error, 0 otherwise. + * + * If the file can't be read, or is empty: + * - bw_file_headers is empty, + * - routerstatuses is not modified, + * - the measured bandwidth cache is not modified, and + * - digest_out is the zero-byte digest. + * + * Otherwise, if there is an error later in the file: + * - bw_file_headers contains all the headers up to the error, + * - routerstatuses is updated with all the relay lines up to the error, + * - the measured bandwidth cache is updated with all the relay lines up to + * the error, + * - if the timestamp is valid and recent, old entries in the measured + * bandwidth cache are expired, and + * - digest_out is the digest up to the first read error (if any). + * The digest is taken over all the readable file contents, even if the + * file is outdated or unparseable. */ int dirserv_read_measured_bandwidths(const char *from_file, @@ -223,15 +246,12 @@ dirserv_read_measured_bandwidths(const char *from_file, size_t n = 0; crypto_digest_t *digest = crypto_digest256_new(DIGEST_SHA256); - /* Initialise line, so that we can't possibly run off the end. */ - if (fp == NULL) { log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s", from_file); goto err; } - /* If fgets fails, line is either unmodified, or indeterminate. */ if (tor_getline(&line,&n,fp) <= 0) { log_warn(LD_DIRSERV, "Empty bandwidth file"); goto err; @@ -345,6 +365,9 @@ dirserv_read_measured_bandwidths(const char *from_file, * the header block yet. If we encounter an incomplete bw line, return -1 but * don't warn since there could be additional header lines coming. If we * encounter a proper bw line, return 0 (and we got past the headers). + * + * If the line contains "vote=0", stop parsing it, and return -1, so that the + * line is ignored during voting. */ STATIC int measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line, diff --git a/src/feature/dirauth/bwauth.h b/src/feature/dirauth/bwauth.h index 8b7acc4a1c..81c8affbd7 100644 --- a/src/feature/dirauth/bwauth.h +++ b/src/feature/dirauth/bwauth.h @@ -55,4 +55,4 @@ STATIC void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line, STATIC void dirserv_expire_measured_bw_cache(time_t now); #endif /* defined(BWAUTH_PRIVATE) */ -#endif +#endif /* !defined(TOR_BWAUTH_H) */ diff --git a/src/feature/dirauth/dirauth_periodic.c b/src/feature/dirauth/dirauth_periodic.c new file mode 100644 index 0000000000..02727d61b4 --- /dev/null +++ b/src/feature/dirauth/dirauth_periodic.c @@ -0,0 +1,161 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "core/or/or.h" + +#include "app/config/or_options_st.h" +#include "core/mainloop/netstatus.h" +#include "feature/dirauth/reachability.h" +#include "feature/stats/rephist.h" + +#include "feature/dirauth/bridgeauth.h" +#include "feature/dirauth/dirvote.h" +#include "feature/dirauth/dirauth_periodic.h" +#include "feature/dirauth/authmode.h" + +#include "core/mainloop/periodic.h" + +#define DECLARE_EVENT(name, roles, flags) \ + static periodic_event_item_t name ## _event = \ + PERIODIC_EVENT(name, \ + PERIODIC_EVENT_ROLE_##roles, \ + flags) + +#define FL(name) (PERIODIC_EVENT_FLAG_##name) + +/** + * Periodic callback: if we're an authority, check on our authority + * certificate (the one that authenticates our authority signing key). + */ +static int +check_authority_cert_callback(time_t now, const or_options_t *options) +{ + (void)now; + (void)options; + /* 1e. Periodically, if we're a v3 authority, we check whether our cert is + * close to expiring and warn the admin if it is. */ + v3_authority_check_key_expiry(); +#define CHECK_V3_CERTIFICATE_INTERVAL (5*60) + return CHECK_V3_CERTIFICATE_INTERVAL; +} + +DECLARE_EVENT(check_authority_cert, DIRAUTH, 0); + +/** + * Scheduled callback: Run directory-authority voting functionality. + * + * The schedule is a bit complicated here, so dirvote_act() manages the + * schedule itself. + **/ +static int +dirvote_callback(time_t now, const or_options_t *options) +{ + if (!authdir_mode_v3(options)) { + tor_assert_nonfatal_unreached(); + return 3600; + } + + time_t next = dirvote_act(options, now); + if (BUG(next == TIME_MAX)) { + /* This shouldn't be returned unless we called dirvote_act() without + * being an authority. If it happens, maybe our configuration will + * fix itself in an hour or so? */ + return 3600; + } + return safe_timer_diff(now, next); +} + +DECLARE_EVENT(dirvote, DIRAUTH, FL(NEED_NET)); + +/** Reschedule the directory-authority voting event. Run this whenever the + * schedule has changed. */ +void +reschedule_dirvote(const or_options_t *options) +{ + if (authdir_mode_v3(options)) { + periodic_event_reschedule(&dirvote_event); + } +} + +/** + * Periodic callback: if we're an authority, record our measured stability + * information from rephist in an mtbf file. + */ +static int +save_stability_callback(time_t now, const or_options_t *options) +{ + if (authdir_mode_tests_reachability(options)) { + if (rep_hist_record_mtbf_data(now, 1)<0) { + log_warn(LD_GENERAL, "Couldn't store mtbf data."); + } + } +#define SAVE_STABILITY_INTERVAL (30*60) + return SAVE_STABILITY_INTERVAL; +} + +DECLARE_EVENT(save_stability, AUTHORITIES, 0); + +/** + * Periodic callback: if we're an authority, make sure we test + * the routers on the network for reachability. + */ +static int +launch_reachability_tests_callback(time_t now, const or_options_t *options) +{ + if (authdir_mode_tests_reachability(options) && + !net_is_disabled()) { + /* try to determine reachability of the other Tor relays */ + dirserv_test_reachability(now); + } + return REACHABILITY_TEST_INTERVAL; +} + +DECLARE_EVENT(launch_reachability_tests, AUTHORITIES, FL(NEED_NET)); + +/** + * Periodic callback: if we're an authority, discount the stability + * information (and other rephist information) that's older. + */ +static int +downrate_stability_callback(time_t now, const or_options_t *options) +{ + (void)options; + /* 1d. Periodically, we discount older stability information so that new + * stability info counts more, and save the stability information to disk as + * appropriate. */ + time_t next = rep_hist_downrate_old_runs(now); + return safe_timer_diff(now, next); +} + +DECLARE_EVENT(downrate_stability, AUTHORITIES, 0); + +/** + * Periodic callback: if we're the bridge authority, write a networkstatus + * file to disk. + */ +static int +write_bridge_ns_callback(time_t now, const or_options_t *options) +{ + if (options->BridgeAuthoritativeDir) { + bridgeauth_dump_bridge_status_to_file(now); +#define BRIDGE_STATUSFILE_INTERVAL (30*60) + return BRIDGE_STATUSFILE_INTERVAL; + } + return PERIODIC_EVENT_NO_UPDATE; +} + +DECLARE_EVENT(write_bridge_ns, BRIDGEAUTH, 0); + +void +dirauth_register_periodic_events(void) +{ + periodic_events_register(&downrate_stability_event); + periodic_events_register(&launch_reachability_tests_event); + periodic_events_register(&save_stability_event); + periodic_events_register(&check_authority_cert_event); + periodic_events_register(&dirvote_event); + periodic_events_register(&write_bridge_ns_event); +} diff --git a/src/feature/dirauth/dirauth_periodic.h b/src/feature/dirauth/dirauth_periodic.h new file mode 100644 index 0000000000..1124fae952 --- /dev/null +++ b/src/feature/dirauth/dirauth_periodic.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DIRVOTE_PERIODIC_H +#define DIRVOTE_PERIODIC_H + +#ifdef HAVE_MODULE_DIRAUTH + +void dirauth_register_periodic_events(void); +void reschedule_dirvote(const or_options_t *options); + +#else /* !(defined(HAVE_MODULE_DIRAUTH)) */ + +static inline void +reschedule_dirvote(const or_options_t *options) +{ + (void)options; +} + +#endif /* defined(HAVE_MODULE_DIRAUTH) */ + +#endif /* !defined(DIRVOTE_PERIODIC_H) */ diff --git a/src/feature/dirauth/dirauth_sys.c b/src/feature/dirauth/dirauth_sys.c new file mode 100644 index 0000000000..e38d391300 --- /dev/null +++ b/src/feature/dirauth/dirauth_sys.c @@ -0,0 +1,40 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "core/or/or.h" + +#include "feature/dirauth/bwauth.h" +#include "feature/dirauth/dirauth_sys.h" +#include "feature/dirauth/dirvote.h" +#include "feature/dirauth/dirauth_periodic.h" +#include "feature/dirauth/keypin.h" +#include "feature/dirauth/process_descs.h" + +#include "lib/subsys/subsys.h" + +static int +subsys_dirauth_initialize(void) +{ + dirauth_register_periodic_events(); + return 0; +} + +static void +subsys_dirauth_shutdown(void) +{ + dirserv_free_fingerprint_list(); + dirvote_free_all(); + dirserv_clear_measured_bw_cache(); + keypin_close_journal(); +} + +const struct subsys_fns_t sys_dirauth = { + .name = "dirauth", + .supported = true, + .level = 70, + .initialize = subsys_dirauth_initialize, + .shutdown = subsys_dirauth_shutdown, +}; diff --git a/src/feature/dirauth/dirauth_sys.h b/src/feature/dirauth/dirauth_sys.h new file mode 100644 index 0000000000..4e9b6a2ab4 --- /dev/null +++ b/src/feature/dirauth/dirauth_sys.h @@ -0,0 +1,12 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DIRAUTH_SYS_H +#define DIRAUTH_SYS_H + +extern const struct subsys_fns_t sys_dirauth; + +#endif /* !defined(DIRAUTH_SYS_H) */ diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index 755b99bae2..cdbdf5a216 100644 --- a/src/feature/dirauth/dirvote.c +++ b/src/feature/dirauth/dirvote.c @@ -2598,7 +2598,7 @@ networkstatus_add_detached_signatures(networkstatus_t *target, return -1; } for (alg = DIGEST_SHA1; alg < N_COMMON_DIGEST_ALGORITHMS; ++alg) { - if (!tor_mem_is_zero(digests->d[alg], DIGEST256_LEN)) { + if (!fast_mem_is_zero(digests->d[alg], DIGEST256_LEN)) { if (fast_memeq(target->digests.d[alg], digests->d[alg], DIGEST256_LEN)) { ++n_matches; @@ -2794,7 +2794,7 @@ networkstatus_get_detached_signatures(smartlist_t *consensuses) char d[HEX_DIGEST256_LEN+1]; const char *alg_name = crypto_digest_algorithm_get_name(alg); - if (tor_mem_is_zero(ns->digests.d[alg], DIGEST256_LEN)) + if (fast_mem_is_zero(ns->digests.d[alg], DIGEST256_LEN)) continue; base16_encode(d, sizeof(d), ns->digests.d[alg], DIGEST256_LEN); smartlist_add_asprintf(elements, "additional-digest %s %s %s\n", @@ -3913,8 +3913,7 @@ dirvote_format_microdesc_vote_line(char *out_buf, size_t out_buf_len, ","); tor_assert(microdesc_consensus_methods); - if (digest256_to_base64(d64, md->digest)<0) - goto out; + digest256_to_base64(d64, md->digest); if (tor_snprintf(out_buf, out_buf_len, "m %s sha256=%s\n", microdesc_consensus_methods, d64)<0) @@ -4545,8 +4544,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; - set_routerstatus_from_routerinfo(rs, node, ri, now, - listbadexits); + dirauth_set_routerstatus_from_routerinfo(rs, node, ri, now, + listbadexits); if (ri->cache_info.signing_key_cert) { memcpy(vrs->ed25519_id, diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h index f9de5ebc41..a0cfe0a34c 100644 --- a/src/feature/dirauth/dirvote.h +++ b/src/feature/dirauth/dirvote.h @@ -128,7 +128,7 @@ struct config_line_t; char *format_recommended_version_list(const struct config_line_t *line, int warn); -#else /* HAVE_MODULE_DIRAUTH */ +#else /* !(defined(HAVE_MODULE_DIRAUTH)) */ static inline time_t dirvote_act(const or_options_t *options, time_t now) @@ -193,7 +193,7 @@ dirvote_add_signatures(const char *detached_signatures_body, return 0; } -#endif /* HAVE_MODULE_DIRAUTH */ +#endif /* defined(HAVE_MODULE_DIRAUTH) */ /* Item access */ MOCK_DECL(const char*, dirvote_get_pending_consensus, diff --git a/src/feature/dirauth/dsigs_parse.c b/src/feature/dirauth/dsigs_parse.c index d88176fee9..c5c8e18866 100644 --- a/src/feature/dirauth/dsigs_parse.c +++ b/src/feature/dirauth/dsigs_parse.c @@ -127,7 +127,7 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos) } digests = detached_get_digests(sigs, flavor); tor_assert(digests); - if (!tor_mem_is_zero(digests->d[alg], digest_length)) { + if (!fast_mem_is_zero(digests->d[alg], digest_length)) { log_warn(LD_DIR, "Multiple digests for %s with %s on detached " "signatures document", flavor, algname); continue; diff --git a/src/feature/dirauth/dsigs_parse.h b/src/feature/dirauth/dsigs_parse.h index fec51ba488..0cc53072f8 100644 --- a/src/feature/dirauth/dsigs_parse.h +++ b/src/feature/dirauth/dsigs_parse.h @@ -19,4 +19,4 @@ void ns_detached_signatures_free_(ns_detached_signatures_t *s); #define ns_detached_signatures_free(s) \ FREE_AND_NULL(ns_detached_signatures_t, ns_detached_signatures_free_, (s)) -#endif +#endif /* !defined(TOR_DSIGS_PARSE_H) */ diff --git a/src/feature/dirauth/guardfraction.h b/src/feature/dirauth/guardfraction.h index 72404907a4..9f01ded838 100644 --- a/src/feature/dirauth/guardfraction.h +++ b/src/feature/dirauth/guardfraction.h @@ -21,4 +21,4 @@ dirserv_read_guardfraction_file_from_str(const char *guardfraction_file_str, int dirserv_read_guardfraction_file(const char *fname, smartlist_t *vote_routerstatuses); -#endif +#endif /* !defined(TOR_GUARDFRACTION_H) */ diff --git a/src/feature/dirauth/ns_detached_signatures_st.h b/src/feature/dirauth/ns_detached_signatures_st.h index 0f92be2f0d..61d20b7525 100644 --- a/src/feature/dirauth/ns_detached_signatures_st.h +++ b/src/feature/dirauth/ns_detached_signatures_st.h @@ -18,5 +18,5 @@ struct ns_detached_signatures_t { * document_signature_t */ }; -#endif +#endif /* !defined(NS_DETACHED_SIGNATURES_ST_H) */ diff --git a/src/feature/dirauth/process_descs.h b/src/feature/dirauth/process_descs.h index 510e54f813..001c866eba 100644 --- a/src/feature/dirauth/process_descs.h +++ b/src/feature/dirauth/process_descs.h @@ -36,4 +36,4 @@ void dirserv_set_node_flags_from_authoritative_status(node_t *node, int dirserv_would_reject_router(const routerstatus_t *rs); -#endif +#endif /* !defined(TOR_RECV_UPLOADS_H) */ diff --git a/src/feature/dirauth/reachability.h b/src/feature/dirauth/reachability.h index 5a938673ff..873a3f9a23 100644 --- a/src/feature/dirauth/reachability.h +++ b/src/feature/dirauth/reachability.h @@ -33,4 +33,4 @@ int dirserv_should_launch_reachability_test(const routerinfo_t *ri, void dirserv_single_reachability_test(time_t now, routerinfo_t *router); void dirserv_test_reachability(time_t now); -#endif +#endif /* !defined(TOR_REACHABILITY_H) */ diff --git a/src/feature/dirauth/recommend_pkg.h b/src/feature/dirauth/recommend_pkg.h index 8200d78f72..af17e945e8 100644 --- a/src/feature/dirauth/recommend_pkg.h +++ b/src/feature/dirauth/recommend_pkg.h @@ -12,6 +12,18 @@ #ifndef TOR_RECOMMEND_PKG_H #define TOR_RECOMMEND_PKG_H +#ifdef HAVE_MODULE_DIRAUTH int validate_recommended_package_line(const char *line); -#endif +#else + +static inline int +validate_recommended_package_line(const char *line) +{ + (void) line; + return 0; +} + +#endif /* defined(HAVE_MODULE_DIRAUTH) */ + +#endif /* !defined(TOR_RECOMMEND_PKG_H) */ diff --git a/src/feature/dirauth/shared_random.c b/src/feature/dirauth/shared_random.c index 137c49800f..5ccf1a95e5 100644 --- a/src/feature/dirauth/shared_random.c +++ b/src/feature/dirauth/shared_random.c @@ -224,7 +224,7 @@ verify_commit_and_reveal(const sr_commit_t *commit) STATIC int commit_has_reveal_value(const sr_commit_t *commit) { - return !tor_mem_is_zero(commit->encoded_reveal, + return !fast_mem_is_zero(commit->encoded_reveal, sizeof(commit->encoded_reveal)); } @@ -486,7 +486,7 @@ get_vote_line_from_commit(const sr_commit_t *commit, sr_phase_t phase) { /* Send a reveal value for this commit if we have one. */ const char *reveal_str = commit->encoded_reveal; - if (tor_mem_is_zero(commit->encoded_reveal, + if (fast_mem_is_zero(commit->encoded_reveal, sizeof(commit->encoded_reveal))) { reveal_str = ""; } diff --git a/src/feature/dirauth/shared_random.h b/src/feature/dirauth/shared_random.h index 0b45ad1ed7..1d8fa89b0f 100644 --- a/src/feature/dirauth/shared_random.h +++ b/src/feature/dirauth/shared_random.h @@ -110,7 +110,7 @@ int sr_init(int save_to_disk); void sr_save_and_cleanup(void); void sr_act_post_consensus(const networkstatus_t *consensus); -#else /* HAVE_MODULE_DIRAUTH */ +#else /* !(defined(HAVE_MODULE_DIRAUTH)) */ static inline int sr_init(int save_to_disk) @@ -131,7 +131,7 @@ sr_act_post_consensus(const networkstatus_t *consensus) (void) consensus; } -#endif /* HAVE_MODULE_DIRAUTH */ +#endif /* defined(HAVE_MODULE_DIRAUTH) */ /* Public methods used only by dirauth code. */ diff --git a/src/feature/dirauth/shared_random_state.c b/src/feature/dirauth/shared_random_state.c index a7b7480edd..b669e3836e 100644 --- a/src/feature/dirauth/shared_random_state.c +++ b/src/feature/dirauth/shared_random_state.c @@ -538,7 +538,7 @@ disk_state_put_commit_line(const sr_commit_t *commit, config_line_t *line) tor_assert(commit); tor_assert(line); - if (!tor_mem_is_zero(commit->encoded_reveal, + if (!fast_mem_is_zero(commit->encoded_reveal, sizeof(commit->encoded_reveal))) { /* Add extra whitespace so we can format the line correctly. */ tor_asprintf(&reveal_str, " %s", commit->encoded_reveal); @@ -937,7 +937,7 @@ state_query_del_all_(sr_state_object_t obj_type) } DIGESTMAP_FOREACH_END; break; } - /* The following object are _NOT_ suppose to be removed. */ + /* The following objects are _NOT_ supposed to be removed. */ case SR_STATE_OBJ_CURSRV: case SR_STATE_OBJ_PREVSRV: case SR_STATE_OBJ_PHASE: diff --git a/src/feature/dirauth/vote_microdesc_hash_st.h b/src/feature/dirauth/vote_microdesc_hash_st.h index 92acdf1157..7869f92b4f 100644 --- a/src/feature/dirauth/vote_microdesc_hash_st.h +++ b/src/feature/dirauth/vote_microdesc_hash_st.h @@ -18,5 +18,5 @@ struct vote_microdesc_hash_t { char *microdesc_hash_line; }; -#endif +#endif /* !defined(VOTE_MICRODESC_HASH_ST_H) */ diff --git a/src/feature/dirauth/voteflags.c b/src/feature/dirauth/voteflags.c index 4f7593a3e1..f552af98c4 100644 --- a/src/feature/dirauth/voteflags.c +++ b/src/feature/dirauth/voteflags.c @@ -29,6 +29,7 @@ #include "feature/nodelist/node_st.h" #include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerlist_st.h" #include "feature/nodelist/vote_routerstatus_st.h" #include "lib/container/order.h" @@ -238,7 +239,7 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil) uint32_t *uptimes, *bandwidths_kb, *bandwidths_excluding_exits_kb; long *tks; double *mtbfs, *wfus; - smartlist_t *nodelist; + const smartlist_t *nodelist; time_t now = time(NULL); const or_options_t *options = get_options(); @@ -531,38 +532,45 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now) node->is_running = answer; } -/** Extract status information from ri and from other authority - * functions and store it in rs. rs is zeroed out before it is - * set. - * - * We assume that ri-\>is_running has already been set, e.g. by - * dirserv_set_router_is_running(ri, now); +/* Check node and ri on whether or not we should publish a + * relay's IPv6 addresses. */ +static int +should_publish_node_ipv6(const node_t *node, const routerinfo_t *ri, + time_t now) +{ + const or_options_t *options = get_options(); + + return options->AuthDirHasIPv6Connectivity == 1 && + !tor_addr_is_null(&ri->ipv6_addr) && + ((node->last_reachable6 >= now - REACHABLE_TIMEOUT) || + router_is_me(ri)); +} + +/** + * Extract status information from ri and from other authority + * functions and store it in rs, as per + * set_routerstatus_from_routerinfo. Additionally, sets information + * in from the authority subsystem. */ void -set_routerstatus_from_routerinfo(routerstatus_t *rs, - node_t *node, - const routerinfo_t *ri, - time_t now, - int listbadexits) +dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs, + node_t *node, + const routerinfo_t *ri, + time_t now, + int listbadexits) { const or_options_t *options = get_options(); uint32_t routerbw_kb = dirserv_get_credible_bandwidth_kb(ri); - memset(rs, 0, sizeof(routerstatus_t)); - - rs->is_authority = - router_digest_is_trusted_dir(ri->cache_info.identity_digest); - - /* Already set by compute_performance_thresholds. */ - rs->is_exit = node->is_exit; - rs->is_stable = node->is_stable = - !dirserv_thinks_router_is_unreliable(now, ri, 1, 0); - rs->is_fast = node->is_fast = - !dirserv_thinks_router_is_unreliable(now, ri, 0, 1); - rs->is_flagged_running = node->is_running; /* computed above */ + /* Set these flags so that set_routerstatus_from_routerinfo can copy them. + */ + node->is_stable = !dirserv_thinks_router_is_unreliable(now, ri, 1, 0); + node->is_fast = !dirserv_thinks_router_is_unreliable(now, ri, 0, 1); + node->is_hs_dir = dirserv_thinks_router_is_hs_dir(ri, node, now); - rs->is_valid = node->is_valid; + set_routerstatus_from_routerinfo(rs, node, ri); + /* Override rs->is_possible_guard. */ if (node->is_fast && node->is_stable && ri->supports_tunnelled_dir_requests && ((options->AuthDirGuardBWGuarantee && @@ -578,33 +586,16 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs, rs->is_possible_guard = 0; } + /* Override rs->is_bad_exit */ rs->is_bad_exit = listbadexits && node->is_bad_exit; - rs->is_hs_dir = node->is_hs_dir = - dirserv_thinks_router_is_hs_dir(ri, node, now); - - rs->is_named = rs->is_unnamed = 0; - - rs->published_on = ri->cache_info.published_on; - memcpy(rs->identity_digest, node->identity, DIGEST_LEN); - memcpy(rs->descriptor_digest, ri->cache_info.signed_descriptor_digest, - DIGEST_LEN); - rs->addr = ri->addr; - strlcpy(rs->nickname, ri->nickname, sizeof(rs->nickname)); - rs->or_port = ri->or_port; - rs->dir_port = ri->dir_port; - rs->is_v2_dir = ri->supports_tunnelled_dir_requests; + /* Set rs->is_staledesc. */ rs->is_staledesc = (ri->cache_info.published_on + DESC_IS_STALE_INTERVAL) < now; - if (options->AuthDirHasIPv6Connectivity == 1 && - !tor_addr_is_null(&ri->ipv6_addr) && - node->last_reachable6 >= now - REACHABLE_TIMEOUT) { - /* We're configured as having IPv6 connectivity. There's an IPv6 - OR port and it's reachable so copy it to the routerstatus. */ - tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr); - rs->ipv6_orport = ri->ipv6_orport; - } else { + if (! should_publish_node_ipv6(node, ri, now)) { + /* We're not configured as having IPv6 connectivity or the node isn't: + * zero its IPv6 information. */ tor_addr_make_null(&rs->ipv6_addr, AF_INET6); rs->ipv6_orport = 0; } @@ -646,3 +637,20 @@ dirserv_set_routerstatus_testing(routerstatus_t *rs) rs->is_hs_dir = 0; } } + +/** Use dirserv_set_router_is_running() to set bridges as running if they're + * reachable. + * + * This function is called from set_bridge_running_callback() when running as + * a bridge authority. + */ +void +dirserv_set_bridges_running(time_t now) +{ + routerlist_t *rl = router_get_routerlist(); + + SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) { + if (ri->purpose == ROUTER_PURPOSE_BRIDGE) + dirserv_set_router_is_running(ri, now); + } SMARTLIST_FOREACH_END(ri); +} diff --git a/src/feature/dirauth/voteflags.h b/src/feature/dirauth/voteflags.h index cca6f53746..c4f36e7817 100644 --- a/src/feature/dirauth/voteflags.h +++ b/src/feature/dirauth/voteflags.h @@ -12,24 +12,28 @@ #ifndef TOR_VOTEFLAGS_H #define TOR_VOTEFLAGS_H +#ifdef HAVE_MODULE_DIRAUTH void dirserv_set_router_is_running(routerinfo_t *router, time_t now); char *dirserv_get_flag_thresholds_line(void); void dirserv_compute_bridge_flag_thresholds(void); int running_long_enough_to_decide_unreachable(void); -void set_routerstatus_from_routerinfo(routerstatus_t *rs, - node_t *node, - const routerinfo_t *ri, - time_t now, - int listbadexits); +void dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs, + node_t *node, + const routerinfo_t *ri, + time_t now, + int listbadexits); void dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil); +#endif /* defined(HAVE_MODULE_DIRAUTH) */ + +void dirserv_set_bridges_running(time_t now); #ifdef VOTEFLAGS_PRIVATE /** Any descriptor older than this age causes the authorities to set the * StaleDesc flag. */ #define DESC_IS_STALE_INTERVAL (18*60*60) STATIC void dirserv_set_routerstatus_testing(routerstatus_t *rs); -#endif +#endif /* defined(VOTEFLAGS_PRIVATE) */ -#endif +#endif /* !defined(TOR_VOTEFLAGS_H) */ diff --git a/src/feature/dircache/cached_dir_st.h b/src/feature/dircache/cached_dir_st.h index 71dca8c3a2..a28802f905 100644 --- a/src/feature/dircache/cached_dir_st.h +++ b/src/feature/dircache/cached_dir_st.h @@ -21,5 +21,5 @@ struct cached_dir_t { int refcnt; /**< Reference count for this cached_dir_t. */ }; -#endif +#endif /* !defined(CACHED_DIR_ST_H) */ diff --git a/src/feature/dircache/consdiffmgr.c b/src/feature/dircache/consdiffmgr.c index 6b16307e3c..397efa0341 100644 --- a/src/feature/dircache/consdiffmgr.c +++ b/src/feature/dircache/consdiffmgr.c @@ -525,7 +525,7 @@ consdiffmgr_add_consensus_nulterm(const char *consensus, tor_free(ctmp); return r; } -#endif +#endif /* defined(TOR_UNIT_TESTS) */ /** * Given a buffer containing a networkstatus consensus, and the results of diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c index eece1e6503..1b36f716f4 100644 --- a/src/feature/dircache/dircache.c +++ b/src/feature/dircache/dircache.c @@ -1072,13 +1072,11 @@ handle_get_status_vote(dir_connection_t *conn, const get_handler_args_t *args) if (compress_method != NO_METHOD) { conn->compress_state = tor_compress_new(1, compress_method, choose_compression_level(estimated_len)); - SMARTLIST_FOREACH(items, const char *, c, - connection_buf_add_compress(c, strlen(c), conn, 0)); - connection_buf_add_compress("", 0, conn, 1); - } else { - SMARTLIST_FOREACH(items, const char *, c, - connection_buf_add(c, strlen(c), TO_CONN(conn))); } + + SMARTLIST_FOREACH(items, const char *, c, + connection_dir_buf_add(c, strlen(c), conn, + c_sl_idx == c_sl_len - 1)); } else { SMARTLIST_FOREACH(dir_items, cached_dir_t *, d, connection_buf_add(compress_method != NO_METHOD ? @@ -1329,19 +1327,13 @@ handle_get_keys(dir_connection_t *conn, const get_handler_args_t *args) if (compress_method != NO_METHOD) { conn->compress_state = tor_compress_new(1, compress_method, choose_compression_level(len)); - SMARTLIST_FOREACH(certs, authority_cert_t *, c, - connection_buf_add_compress( - c->cache_info.signed_descriptor_body, - c->cache_info.signed_descriptor_len, - conn, 0)); - connection_buf_add_compress("", 0, conn, 1); - } else { - SMARTLIST_FOREACH(certs, authority_cert_t *, c, - connection_buf_add(c->cache_info.signed_descriptor_body, - c->cache_info.signed_descriptor_len, - TO_CONN(conn))); } - keys_done: + + SMARTLIST_FOREACH(certs, authority_cert_t *, c, + connection_dir_buf_add(c->cache_info.signed_descriptor_body, + c->cache_info.signed_descriptor_len, + conn, c_sl_idx == c_sl_len - 1)); + keys_done: smartlist_free(certs); goto done; } diff --git a/src/feature/dircache/dircache.h b/src/feature/dircache/dircache.h index 236ea649ef..de0d205f6a 100644 --- a/src/feature/dircache/dircache.h +++ b/src/feature/dircache/dircache.h @@ -38,6 +38,6 @@ STATIC int parse_hs_version_from_post(const char *url, const char *prefix, const char **end_pos); STATIC unsigned parse_accept_encoding_header(const char *h); -#endif +#endif /* defined(DIRCACHE_PRIVATE) */ #endif /* !defined(TOR_DIRCACHE_H) */ diff --git a/src/feature/dircache/dirserv.c b/src/feature/dircache/dirserv.c index 4be6836fe1..79400bf15f 100644 --- a/src/feature/dircache/dirserv.c +++ b/src/feature/dircache/dirserv.c @@ -583,11 +583,9 @@ spooled_resource_flush_some(spooled_resource_t *spooled, /* Absent objects count as "done". */ return SRFS_DONE; } - if (conn->compress_state) { - connection_buf_add_compress((const char*)body, bodylen, conn, 0); - } else { - connection_buf_add((const char*)body, bodylen, TO_CONN(conn)); - } + + connection_dir_buf_add((const char*)body, bodylen, conn, 0); + return SRFS_DONE; } else { cached_dir_t *cached = spooled->cached_dir_ref; @@ -622,14 +620,10 @@ spooled_resource_flush_some(spooled_resource_t *spooled, if (BUG(remaining < 0)) return SRFS_ERR; ssize_t bytes = (ssize_t) MIN(DIRSERV_CACHED_DIR_CHUNK_SIZE, remaining); - if (conn->compress_state) { - connection_buf_add_compress( - ptr + spooled->cached_dir_offset, - bytes, conn, 0); - } else { - connection_buf_add(ptr + spooled->cached_dir_offset, - bytes, TO_CONN(conn)); - } + + connection_dir_buf_add(ptr + spooled->cached_dir_offset, + bytes, conn, 0); + spooled->cached_dir_offset += bytes; if (spooled->cached_dir_offset >= (off_t)total_len) { return SRFS_DONE; diff --git a/src/feature/dirclient/dir_server_st.h b/src/feature/dirclient/dir_server_st.h index 2f5706cdd9..8e35532435 100644 --- a/src/feature/dirclient/dir_server_st.h +++ b/src/feature/dirclient/dir_server_st.h @@ -51,4 +51,4 @@ struct dir_server_t { **/ }; -#endif +#endif /* !defined(DIR_SERVER_ST_H) */ diff --git a/src/feature/dirclient/dirclient.c b/src/feature/dirclient/dirclient.c index 70b6a20028..1ea50fd350 100644 --- a/src/feature/dirclient/dirclient.c +++ b/src/feature/dirclient/dirclient.c @@ -14,7 +14,7 @@ #include "core/or/policies.h" #include "feature/client/bridges.h" #include "feature/client/entrynodes.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirauth/authmode.h" #include "feature/dirauth/dirvote.h" #include "feature/dirauth/shared_random.h" @@ -2531,7 +2531,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn, conn->base_.port); tor_assert(conn->requested_resource && !strcmpstart(conn->requested_resource, "d/")); - tor_assert_nonfatal(!tor_mem_is_zero(conn->identity_digest, DIGEST_LEN)); + tor_assert_nonfatal(!fast_mem_is_zero(conn->identity_digest, DIGEST_LEN)); which = smartlist_new(); dir_split_resource_into_fingerprints(conn->requested_resource+2, which, NULL, diff --git a/src/feature/dirclient/dirclient.h b/src/feature/dirclient/dirclient.h index 1a93265dc3..be4374c7cf 100644 --- a/src/feature/dirclient/dirclient.h +++ b/src/feature/dirclient/dirclient.h @@ -167,6 +167,6 @@ STATIC int handle_response_fetch_consensus(dir_connection_t *conn, STATIC dirinfo_type_t dir_fetch_type(int dir_purpose, int router_purpose, const char *resource); -#endif +#endif /* defined(DIRCLIENT_PRIVATE) */ #endif /* !defined(TOR_DIRCLIENT_H) */ diff --git a/src/feature/dirclient/dlstatus.h b/src/feature/dirclient/dlstatus.h index 99e0d0225b..681712b059 100644 --- a/src/feature/dirclient/dlstatus.h +++ b/src/feature/dirclient/dlstatus.h @@ -53,6 +53,6 @@ STATIC void next_random_exponential_delay_range(int *low_bound_out, /* no more than triple the previous delay */ #define DIR_TEST_NET_RANDOM_MULTIPLIER (2) -#endif +#endif /* defined(DLSTATUS_PRIVATE) */ #endif /* !defined(TOR_DLSTATUS_H) */ diff --git a/src/feature/dirclient/download_status_st.h b/src/feature/dirclient/download_status_st.h index 11555a1dcc..39a5ad2860 100644 --- a/src/feature/dirclient/download_status_st.h +++ b/src/feature/dirclient/download_status_st.h @@ -61,5 +61,5 @@ struct download_status_t { * only updated if backoff == 1 */ }; -#endif +#endif /* !defined(DOWNLOAD_STATUS_ST_H) */ diff --git a/src/feature/dircommon/dir_connection_st.h b/src/feature/dircommon/dir_connection_st.h index 8c59cc7a46..a858560c29 100644 --- a/src/feature/dircommon/dir_connection_st.h +++ b/src/feature/dircommon/dir_connection_st.h @@ -64,4 +64,4 @@ struct dir_connection_t { #endif /* defined(MEASUREMENTS_21206) */ }; -#endif +#endif /* !defined(DIR_CONNECTION_ST_H) */ diff --git a/src/feature/dircommon/vote_timing_st.h b/src/feature/dircommon/vote_timing_st.h index 47b90ab009..814a325314 100644 --- a/src/feature/dircommon/vote_timing_st.h +++ b/src/feature/dircommon/vote_timing_st.h @@ -20,5 +20,5 @@ struct vote_timing_t { int dist_delay; }; -#endif +#endif /* !defined(VOTE_TIMING_ST_H) */ diff --git a/src/feature/dircommon/voting_schedule.c b/src/feature/dircommon/voting_schedule.c index 0a7476eda7..5576ec69f7 100644 --- a/src/feature/dircommon/voting_schedule.c +++ b/src/feature/dircommon/voting_schedule.c @@ -150,7 +150,7 @@ voting_schedule_get_next_valid_after_time(void) /* This is a safe guard in order to make sure that the voting schedule * static object is at least initialized. Using this function with a zeroed * voting schedule can lead to bugs. */ - if (tor_mem_is_zero((const char *) &voting_schedule, + if (fast_mem_is_zero((const char *) &voting_schedule, sizeof(voting_schedule))) { need_to_recalculate_voting_schedule = true; goto done; /* no need for next check if we have to recalculate anyway */ diff --git a/src/feature/dircommon/voting_schedule.h b/src/feature/dircommon/voting_schedule.h index bafd81184e..d78c7ee2da 100644 --- a/src/feature/dircommon/voting_schedule.h +++ b/src/feature/dircommon/voting_schedule.h @@ -61,5 +61,5 @@ time_t voting_schedule_get_start_of_next_interval(time_t now, int offset); time_t voting_schedule_get_next_valid_after_time(void); -#endif /* TOR_VOTING_SCHEDULE_H */ +#endif /* !defined(TOR_VOTING_SCHEDULE_H) */ diff --git a/src/feature/dirparse/microdesc_parse.h b/src/feature/dirparse/microdesc_parse.h index 23a90084b1..95af85544a 100644 --- a/src/feature/dirparse/microdesc_parse.h +++ b/src/feature/dirparse/microdesc_parse.h @@ -17,4 +17,4 @@ smartlist_t *microdescs_parse_from_string(const char *s, const char *eos, saved_location_t where, smartlist_t *invalid_digests_out); -#endif +#endif /* !defined(TOR_MICRODESC_PARSE_H) */ diff --git a/src/feature/dirparse/ns_parse.c b/src/feature/dirparse/ns_parse.c index d653a59826..d5405e6464 100644 --- a/src/feature/dirparse/ns_parse.c +++ b/src/feature/dirparse/ns_parse.c @@ -1478,7 +1478,7 @@ networkstatus_parse_vote_from_string(const char *s, SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, vote_routerstatus_t *, vrs) { if (! vrs->has_ed25519_listing || - tor_mem_is_zero((const char *)vrs->ed25519_id, DIGEST256_LEN)) + fast_mem_is_zero((const char *)vrs->ed25519_id, DIGEST256_LEN)) continue; if (digest256map_get(ed_id_map, vrs->ed25519_id) != NULL) { log_warn(LD_DIR, "Vote networkstatus ed25519 identities were not " diff --git a/src/feature/dirparse/ns_parse.h b/src/feature/dirparse/ns_parse.h index dedfa6fc88..0cf2cc88d0 100644 --- a/src/feature/dirparse/ns_parse.h +++ b/src/feature/dirparse/ns_parse.h @@ -42,6 +42,6 @@ STATIC routerstatus_t *routerstatus_parse_entry_from_string( vote_routerstatus_t *vote_rs, int consensus_method, consensus_flavor_t flav); -#endif +#endif /* defined(NS_PARSE_PRIVATE) */ -#endif +#endif /* !defined(TOR_NS_PARSE_H) */ diff --git a/src/feature/dirparse/routerparse.c b/src/feature/dirparse/routerparse.c index ff7e15f1f2..f78c46f186 100644 --- a/src/feature/dirparse/routerparse.c +++ b/src/feature/dirparse/routerparse.c @@ -556,6 +556,9 @@ router_parse_entry_from_string(const char *s, const char *end, if ((tok = find_opt_by_keyword(tokens, A_PURPOSE))) { tor_assert(tok->n_args); router->purpose = router_purpose_from_string(tok->args[0]); + if (router->purpose == ROUTER_PURPOSE_UNKNOWN) { + goto err; + } } else { router->purpose = ROUTER_PURPOSE_GENERAL; } diff --git a/src/feature/dirparse/sigcommon.h b/src/feature/dirparse/sigcommon.h index fdd8e839a9..b6b34e8f62 100644 --- a/src/feature/dirparse/sigcommon.h +++ b/src/feature/dirparse/sigcommon.h @@ -43,6 +43,6 @@ MOCK_DECL(STATIC int, signed_digest_equals, MOCK_DECL(STATIC int, router_compute_hash_final,(char *digest, const char *start, size_t len, digest_algorithm_t alg)); -#endif +#endif /* defined(SIGCOMMON_PRIVATE) */ #endif /* !defined(TOR_SIGCOMMON_H) */ diff --git a/src/feature/dirparse/signing.h b/src/feature/dirparse/signing.h index 2e3699baf8..8b119b4eb2 100644 --- a/src/feature/dirparse/signing.h +++ b/src/feature/dirparse/signing.h @@ -20,4 +20,4 @@ int router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest, size_t digest_len, crypto_pk_t *private_key); -#endif +#endif /* !defined(TOR_SIGNING_H) */ diff --git a/src/feature/dirparse/unparseable.h b/src/feature/dirparse/unparseable.h index 853fe8cb0f..49e047961f 100644 --- a/src/feature/dirparse/unparseable.h +++ b/src/feature/dirparse/unparseable.h @@ -51,6 +51,6 @@ EXTERN(struct smartlist_t *, descs_dumped) MOCK_DECL(STATIC dumped_desc_t *, dump_desc_populate_one_file, (const char *dirname, const char *f)); STATIC void dump_desc_populate_fifo_from_directory(const char *dirname); -#endif +#endif /* defined(UNPARSEABLE_PRIVATE) */ #endif /* !defined(TOR_UNPARSEABLE_H) */ diff --git a/src/feature/hibernate/hibernate.c b/src/feature/hibernate/hibernate.c index 70c2b4f69f..674fe3c813 100644 --- a/src/feature/hibernate/hibernate.c +++ b/src/feature/hibernate/hibernate.c @@ -35,7 +35,7 @@ hibernating, phase 2: #include "core/mainloop/connection.h" #include "core/or/connection_edge.h" #include "core/or/connection_or.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/defs/time.h" #include "feature/hibernate/hibernate.h" @@ -57,7 +57,7 @@ hibernating, phase 2: * Coverity. Here's a kludge to unconfuse it. */ # define __INCLUDE_LEVEL__ 2 -# endif /* defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__) */ +#endif /* defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__) */ #include #endif /* defined(HAVE_SYSTEMD) */ @@ -893,7 +893,7 @@ hibernate_begin(hibernate_state_t new_state, time_t now) */ sd_notifyf(0, "EXTEND_TIMEOUT_USEC=%" PRIu64, ((uint64_t)(options->ShutdownWaitLength) + 30) * TOR_USEC_PER_SEC); -#endif +#endif /* defined(HAVE_SYSTEMD) */ } else { /* soft limit reached */ hibernate_end_time = interval_end_time; } diff --git a/src/feature/hibernate/hibernate.h b/src/feature/hibernate/hibernate.h index 3309ef0ce3..2e245f6ab1 100644 --- a/src/feature/hibernate/hibernate.h +++ b/src/feature/hibernate/hibernate.h @@ -32,6 +32,7 @@ int getinfo_helper_accounting(control_connection_t *conn, const char **errmsg); uint64_t get_accounting_max_total(void); void accounting_free_all(void); +bool accounting_tor_is_dormant(void); #ifdef HIBERNATE_PRIVATE /** Possible values of hibernate_state */ diff --git a/src/feature/hs/hs_cell.c b/src/feature/hs/hs_cell.c index 613ffe7260..69f1ccbef4 100644 --- a/src/feature/hs/hs_cell.c +++ b/src/feature/hs/hs_cell.c @@ -758,7 +758,14 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, idx < trn_cell_introduce_encrypted_get_nspec(enc_cell); idx++) { link_specifier_t *lspec = trn_cell_introduce_encrypted_get_nspecs(enc_cell, idx); - smartlist_add(data->link_specifiers, hs_link_specifier_dup(lspec)); + if (BUG(!lspec)) { + goto done; + } + link_specifier_t *lspec_dup = link_specifier_dup(lspec); + if (BUG(!lspec_dup)) { + goto done; + } + smartlist_add(data->link_specifiers, lspec_dup); } /* Success. */ diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c index e3873d2f18..716c4b1f17 100644 --- a/src/feature/hs/hs_circuit.c +++ b/src/feature/hs/hs_circuit.c @@ -15,6 +15,7 @@ #include "core/or/circuituse.h" #include "core/or/policies.h" #include "core/or/relay.h" +#include "core/or/crypt_path.h" #include "feature/client/circpathbias.h" #include "feature/hs/hs_cell.h" #include "feature/hs/hs_circuit.h" @@ -89,7 +90,7 @@ create_rend_cpath(const uint8_t *ntor_key_seed, size_t seed_len, cpath = tor_malloc_zero(sizeof(crypt_path_t)); cpath->magic = CRYPT_PATH_MAGIC; - if (circuit_init_cpath_crypto(cpath, (char*)keys, sizeof(keys), + if (cpath_init_circuit_crypto(cpath, (char*)keys, sizeof(keys), is_service_side, 1) < 0) { tor_free(cpath); goto err; @@ -126,7 +127,7 @@ create_rend_cpath_legacy(origin_circuit_t *circ, const uint8_t *rend_cell_body) goto err; } /* ... and set up cpath. */ - if (circuit_init_cpath_crypto(hop, + if (cpath_init_circuit_crypto(hop, keys+DIGEST_LEN, sizeof(keys)-DIGEST_LEN, 0, 0) < 0) goto err; @@ -177,7 +178,7 @@ finalize_rend_circuit(origin_circuit_t *circ, crypt_path_t *hop, circ->hs_circ_has_timed_out = 0; /* Append the hop to the cpath of this circuit */ - onion_append_to_cpath(&circ->cpath, hop); + cpath_extend_linked_list(&circ->cpath, hop); /* In legacy code, 'pending_final_cpath' points to the final hop we just * appended to the cpath. We set the original pointer to NULL so that we @@ -405,8 +406,12 @@ launch_rendezvous_point_circuit(const hs_service_t *service, if (circ_needs_uptime) { circ_flags |= CIRCLAUNCH_NEED_UPTIME; } - /* Firewall and policies are checked when getting the extend info. */ - if (service->config.is_single_onion) { + /* Firewall and policies are checked when getting the extend info. + * + * We only use a one-hop path on the first attempt. If the first attempt + * fails, we use a 3-hop path for reachability / reliability. + * See the comment in retry_service_rendezvous_point() for details. */ + if (service->config.is_single_onion && i == 0) { circ_flags |= CIRCLAUNCH_ONEHOP_TUNNEL; } @@ -565,81 +570,6 @@ 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; - * - 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) -{ - link_specifier_t *ls; - tor_addr_port_t ap; - - tor_assert(node); - tor_assert(lspecs); - - /* Get the relay's IPv4 address. */ - node_get_prim_orport(node, &ap); - - /* We expect the node's primary address to be a valid IPv4 address. - * This conforms to the protocol, which requires either an IPv4 or IPv6 - * address (or both). */ - if (BUG(!tor_addr_is_v4(&ap.addr)) || - BUG(!tor_addr_port_is_valid_ap(&ap, 0))) { - return; - } - - ls = link_specifier_new(); - link_specifier_set_ls_type(ls, LS_IPV4); - link_specifier_set_un_ipv4_addr(ls, tor_addr_to_ipv4h(&ap.addr)); - link_specifier_set_un_ipv4_port(ls, ap.port); - /* Four bytes IPv4 and two bytes port. */ - link_specifier_set_ls_len(ls, sizeof(ap.addr.addr.in_addr) + - sizeof(ap.port)); - smartlist_add(lspecs, ls); - - /* Legacy ID is mandatory and will always be present in node. */ - ls = link_specifier_new(); - link_specifier_set_ls_type(ls, LS_LEGACY_ID); - memcpy(link_specifier_getarray_un_legacy_id(ls), node->identity, - link_specifier_getlen_un_legacy_id(ls)); - 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, 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, - link_specifier_getlen_un_ed25519_id(ls)); - link_specifier_set_ls_len(ls, link_specifier_getlen_un_ed25519_id(ls)); - smartlist_add(lspecs, ls); - } - - /* Check for IPv6. If so, include it as well. */ - if (node_has_ipv6_orport(node)) { - ls = link_specifier_new(); - node_get_pref_ipv6_orport(node, &ap); - link_specifier_set_ls_type(ls, LS_IPV6); - size_t addr_len = link_specifier_getlen_un_ipv6_addr(ls); - const uint8_t *in6_addr = tor_addr_to_in6_addr8(&ap.addr); - uint8_t *ipv6_array = link_specifier_getarray_un_ipv6_addr(ls); - memcpy(ipv6_array, in6_addr, addr_len); - link_specifier_set_un_ipv6_port(ls, ap.port); - /* Sixteen bytes IPv6 and two bytes port. */ - link_specifier_set_ls_len(ls, addr_len + sizeof(ap.port)); - smartlist_add(lspecs, ls); - } -} - /* Using the given descriptor intro point ip, the node of the * rendezvous point rp_node and the service's subcredential, populate the * already allocated intro1_data object with the needed key material and link @@ -662,10 +592,9 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip, tor_assert(subcredential); tor_assert(intro1_data); - /* Build the link specifiers from the extend information of the rendezvous - * circuit that we've picked previously. */ - rp_lspecs = smartlist_new(); - get_lspecs_from_node(rp_node, rp_lspecs); + /* Build the link specifiers from the node at the end of the rendezvous + * circuit that we opened for this introduction. */ + rp_lspecs = node_get_link_specifier_smartlist(rp_node, 0); if (smartlist_len(rp_lspecs) == 0) { /* We can't rendezvous without link specifiers. */ smartlist_free(rp_lspecs); @@ -754,13 +683,16 @@ hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ) } /* For a given service and a service intro point, launch a circuit to the - * extend info ei. If the service is a single onion, a one-hop circuit will be - * requested. Return 0 if the circuit was successfully launched and tagged + * extend info ei. If the service is a single onion, and direct_conn is true, + * a one-hop circuit will be requested. + * + * Return 0 if the circuit was successfully launched and tagged * with the correct identifier. On error, a negative value is returned. */ int hs_circ_launch_intro_point(hs_service_t *service, const hs_service_intro_point_t *ip, - extend_info_t *ei) + extend_info_t *ei, + bool direct_conn) { /* Standard flags for introduction circuit. */ int ret = -1, circ_flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL; @@ -772,7 +704,16 @@ hs_circ_launch_intro_point(hs_service_t *service, /* Update circuit flags in case of a single onion service that requires a * direct connection. */ - if (service->config.is_single_onion) { + tor_assert_nonfatal(ip->circuit_retries > 0); + /* Only single onion services can make direct conns */ + if (BUG(!service->config.is_single_onion && direct_conn)) { + goto end; + } + /* We only use a one-hop path on the first attempt. If the first attempt + * fails, we use a 3-hop path for reachability / reliability. + * (Unlike v2, retries is incremented by the caller before it calls this + * function.) */ + if (direct_conn && ip->circuit_retries == 1) { circ_flags |= CIRCLAUNCH_ONEHOP_TUNNEL; } @@ -1044,9 +985,7 @@ hs_circ_handle_introduce2(const hs_service_t *service, ret = 0; done: - SMARTLIST_FOREACH(data.link_specifiers, link_specifier_t *, lspec, - link_specifier_free(lspec)); - smartlist_free(data.link_specifiers); + link_specifier_smartlist_free(data.link_specifiers); memwipe(&data, 0, sizeof(data)); return ret; } diff --git a/src/feature/hs/hs_circuit.h b/src/feature/hs/hs_circuit.h index b8d8b25add..e168b301f1 100644 --- a/src/feature/hs/hs_circuit.h +++ b/src/feature/hs/hs_circuit.h @@ -26,7 +26,8 @@ void hs_circ_service_rp_has_opened(const hs_service_t *service, origin_circuit_t *circ); int hs_circ_launch_intro_point(hs_service_t *service, const hs_service_intro_point_t *ip, - extend_info_t *ei); + extend_info_t *ei, + bool direct_conn); int hs_circ_launch_rendezvous_point(const hs_service_t *service, const curve25519_public_key_t *onion_key, const uint8_t *rendezvous_cookie); diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c index 2a5765aec2..f8d47f0114 100644 --- a/src/feature/hs/hs_client.c +++ b/src/feature/hs/hs_client.c @@ -167,9 +167,7 @@ purge_hid_serv_request(const ed25519_public_key_t *identity_pk) * some point and we don't care about those anymore. */ hs_build_blinded_pubkey(identity_pk, NULL, 0, hs_get_time_period_num(0), &blinded_pk); - if (BUG(ed25519_public_to_base64(base64_blinded_pk, &blinded_pk) < 0)) { - return; - } + ed25519_public_to_base64(base64_blinded_pk, &blinded_pk); /* Purge last hidden service request from cache for this blinded key. */ hs_purge_hid_serv_from_last_hid_serv_requests(base64_blinded_pk); } @@ -356,7 +354,6 @@ directory_launch_v3_desc_fetch(const ed25519_public_key_t *onion_identity_pk, ed25519_public_key_t blinded_pubkey; char base64_blinded_pubkey[ED25519_BASE64_LEN + 1]; hs_ident_dir_conn_t hs_conn_dir_ident; - int retval; tor_assert(hsdir); tor_assert(onion_identity_pk); @@ -365,10 +362,7 @@ directory_launch_v3_desc_fetch(const ed25519_public_key_t *onion_identity_pk, hs_build_blinded_pubkey(onion_identity_pk, NULL, 0, current_time_period, &blinded_pubkey); /* ...and base64 it. */ - retval = ed25519_public_to_base64(base64_blinded_pubkey, &blinded_pubkey); - if (BUG(retval < 0)) { - return HS_CLIENT_FETCH_ERROR; - } + ed25519_public_to_base64(base64_blinded_pubkey, &blinded_pubkey); /* Copy onion pk to a dir_ident so that we attach it to the dir conn */ hs_ident_dir_conn_init(onion_identity_pk, &blinded_pubkey, @@ -407,7 +401,6 @@ directory_launch_v3_desc_fetch(const ed25519_public_key_t *onion_identity_pk, STATIC routerstatus_t * pick_hsdir_v3(const ed25519_public_key_t *onion_identity_pk) { - int retval; char base64_blinded_pubkey[ED25519_BASE64_LEN + 1]; uint64_t current_time_period = hs_get_time_period_num(0); smartlist_t *responsible_hsdirs = NULL; @@ -420,10 +413,7 @@ pick_hsdir_v3(const ed25519_public_key_t *onion_identity_pk) hs_build_blinded_pubkey(onion_identity_pk, NULL, 0, current_time_period, &blinded_pubkey); /* ...and base64 it. */ - retval = ed25519_public_to_base64(base64_blinded_pubkey, &blinded_pubkey); - if (BUG(retval < 0)) { - return NULL; - } + ed25519_public_to_base64(base64_blinded_pubkey, &blinded_pubkey); /* Get responsible hsdirs of service for this time period */ responsible_hsdirs = smartlist_new(); @@ -436,7 +426,7 @@ pick_hsdir_v3(const ed25519_public_key_t *onion_identity_pk) /* Pick an HSDir from the responsible ones. The ownership of * responsible_hsdirs is given to this function so no need to free it. */ - hsdir_rs = hs_pick_hsdir(responsible_hsdirs, base64_blinded_pubkey); + hsdir_rs = hs_pick_hsdir(responsible_hsdirs, base64_blinded_pubkey, NULL); return hsdir_rs; } @@ -461,6 +451,24 @@ fetch_v3_desc, (const ed25519_public_key_t *onion_identity_pk)) return directory_launch_v3_desc_fetch(onion_identity_pk, hsdir_rs); } +/* With a given onion_identity_pk, fetch its descriptor. If + * hsdirs is specified, use the directory servers specified in the list. + * Else, use a random server. */ +void +hs_client_launch_v3_desc_fetch(const ed25519_public_key_t *onion_identity_pk, + const smartlist_t *hsdirs) +{ + tor_assert(onion_identity_pk); + + if (hsdirs != NULL) { + SMARTLIST_FOREACH_BEGIN(hsdirs, const routerstatus_t *, hsdir) { + directory_launch_v3_desc_fetch(onion_identity_pk, hsdir); + } SMARTLIST_FOREACH_END(hsdir); + } else { + fetch_v3_desc(onion_identity_pk); + } +} + /* Make sure that the given v3 origin circuit circ is a valid correct * introduction circuit. This will BUG() on any problems and hard assert if * the anonymity of the circuit is not ok. Return 0 on success else -1 where @@ -530,13 +538,15 @@ find_desc_intro_point_by_legacy_id(const char *legacy_id, SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points, hs_desc_intro_point_t *, ip) { SMARTLIST_FOREACH_BEGIN(ip->link_specifiers, - const hs_desc_link_specifier_t *, lspec) { + const link_specifier_t *, lspec) { /* Not all tor node have an ed25519 identity key so we still rely on the * legacy identity digest. */ - if (lspec->type != LS_LEGACY_ID) { + if (link_specifier_get_ls_type(lspec) != LS_LEGACY_ID) { continue; } - if (fast_memneq(legacy_id, lspec->u.legacy_id, DIGEST_LEN)) { + if (fast_memneq(legacy_id, + link_specifier_getconstarray_un_legacy_id(lspec), + DIGEST_LEN)) { break; } /* Found it. */ @@ -689,7 +699,7 @@ setup_intro_circ_auth_key(origin_circuit_t *circ) } /* Reaching this point means we didn't find any intro point for this circuit - * which is not suppose to happen. */ + * which is not supposed to happen. */ tor_assert_nonfatal_unreached(); end: @@ -755,24 +765,13 @@ STATIC extend_info_t * desc_intro_point_to_extend_info(const hs_desc_intro_point_t *ip) { extend_info_t *ei; - smartlist_t *lspecs = smartlist_new(); tor_assert(ip); - /* We first encode the descriptor link specifiers into the binary - * representation which is a trunnel object. */ - SMARTLIST_FOREACH_BEGIN(ip->link_specifiers, - const hs_desc_link_specifier_t *, desc_lspec) { - link_specifier_t *lspec = hs_desc_lspec_to_trunnel(desc_lspec); - smartlist_add(lspecs, lspec); - } SMARTLIST_FOREACH_END(desc_lspec); - /* Explicitly put the direct connection option to 0 because this is client * side and there is no such thing as a non anonymous client. */ - ei = hs_get_extend_info_from_lspecs(lspecs, &ip->onion_key, 0); + ei = hs_get_extend_info_from_lspecs(ip->link_specifiers, &ip->onion_key, 0); - SMARTLIST_FOREACH(lspecs, link_specifier_t *, ls, link_specifier_free(ls)); - smartlist_free(lspecs); return ei; } @@ -1543,7 +1542,10 @@ parse_auth_file_content(const char *client_key_str) auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t)); if (base32_decode((char *) auth->enc_seckey.secret_key, sizeof(auth->enc_seckey.secret_key), - seckey_b32, strlen(seckey_b32)) < 0) { + seckey_b32, strlen(seckey_b32)) != + sizeof(auth->enc_seckey.secret_key)) { + log_warn(LD_REND, "Client authorization encoded base32 private key " + "can't be decoded: %s", seckey_b32); goto err; } strncpy(auth->onion_address, onion_address, HS_SERVICE_ADDR_LEN_BASE32); diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h index dadfa024b8..96a96755fd 100644 --- a/src/feature/hs/hs_client.h +++ b/src/feature/hs/hs_client.h @@ -44,6 +44,10 @@ typedef struct hs_client_service_authorization_t { void hs_client_note_connection_attempt_succeeded( const edge_connection_t *conn); +void hs_client_launch_v3_desc_fetch( + const ed25519_public_key_t *onion_identity_pk, + const smartlist_t *hsdirs); + int hs_client_decode_descriptor( const char *desc_str, const ed25519_public_key_t *service_identity_pk, diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c index ebe49f09a5..a5747fe170 100644 --- a/src/feature/hs/hs_common.c +++ b/src/feature/hs/hs_common.c @@ -926,7 +926,8 @@ hs_parse_address(const char *address, ed25519_public_key_t *key_out, } /* Decode address so we can extract needed fields. */ - if (base32_decode(decoded, sizeof(decoded), address, strlen(address)) < 0) { + if (base32_decode(decoded, sizeof(decoded), address, strlen(address)) + != sizeof(decoded)) { log_warn(LD_REND, "Service address %s can't be decoded.", escaped_safe_str(address)); goto invalid; @@ -940,7 +941,7 @@ hs_parse_address(const char *address, ed25519_public_key_t *key_out, return -1; } -/* Validate a given onion address. The length, the base32 decoding and +/* Validate a given onion address. The length, the base32 decoding, and * checksum are validated. Return 1 if valid else 0. */ int hs_address_is_valid(const char *address) @@ -955,7 +956,7 @@ hs_address_is_valid(const char *address) goto invalid; } - /* Get the checksum it's suppose to be and compare it with what we have + /* Get the checksum it's supposed to be and compare it with what we have * encoded in the address. */ build_hs_checksum(&service_pubkey, version, target_checksum); if (tor_memcmp(checksum, target_checksum, sizeof(checksum))) { @@ -983,7 +984,7 @@ hs_address_is_valid(const char *address) * The returned address is base32 encoded and put in addr_out. The caller MUST * make sure the addr_out is at least HS_SERVICE_ADDR_LEN_BASE32 + 1 long. * - * Format is as follow: + * Format is as follows: * base32(PUBKEY || CHECKSUM || VERSION) * CHECKSUM = H(".onion checksum" || PUBKEY || VERSION) * */ @@ -1009,24 +1010,6 @@ hs_build_address(const ed25519_public_key_t *key, uint8_t version, tor_assert(hs_address_is_valid(addr_out)); } -/* Return a newly allocated copy of lspec. */ -link_specifier_t * -hs_link_specifier_dup(const link_specifier_t *lspec) -{ - link_specifier_t *result = link_specifier_new(); - memcpy(result, lspec, sizeof(*result)); - /* The unrecognized field is a dynamic array so make sure to copy its - * content and not the pointer. */ - link_specifier_setlen_un_unrecognized( - result, link_specifier_getlen_un_unrecognized(lspec)); - if (link_specifier_getlen_un_unrecognized(result)) { - memcpy(link_specifier_getarray_un_unrecognized(result), - link_specifier_getconstarray_un_unrecognized(lspec), - link_specifier_getlen_un_unrecognized(result)); - } - return result; -} - /* From a given ed25519 public key pk and an optional secret, compute a * blinded public key and put it in blinded_pk_out. This is only useful to * the client side because the client only has access to the identity public @@ -1042,7 +1025,7 @@ hs_build_blinded_pubkey(const ed25519_public_key_t *pk, tor_assert(pk); tor_assert(blinded_pk_out); - tor_assert(!tor_mem_is_zero((char *) pk, ED25519_PUBKEY_LEN)); + tor_assert(!fast_mem_is_zero((char *) pk, ED25519_PUBKEY_LEN)); build_blinded_key_param(pk, secret, secret_len, time_period_num, get_time_period_length(), param); @@ -1067,8 +1050,8 @@ hs_build_blinded_keypair(const ed25519_keypair_t *kp, tor_assert(kp); tor_assert(blinded_kp_out); /* Extra safety. A zeroed key is bad. */ - tor_assert(!tor_mem_is_zero((char *) &kp->pubkey, ED25519_PUBKEY_LEN)); - tor_assert(!tor_mem_is_zero((char *) &kp->seckey, ED25519_SECKEY_LEN)); + tor_assert(!fast_mem_is_zero((char *) &kp->pubkey, ED25519_PUBKEY_LEN)); + tor_assert(!fast_mem_is_zero((char *) &kp->seckey, ED25519_SECKEY_LEN)); build_blinded_key_param(&kp->pubkey, secret, secret_len, time_period_num, get_time_period_length(), param); @@ -1300,15 +1283,15 @@ node_has_hsdir_index(const node_t *node) /* At this point, since the node has a desc, this node must also have an * hsdir index. If not, something went wrong, so BUG out. */ - if (BUG(tor_mem_is_zero((const char*)node->hsdir_index.fetch, + if (BUG(fast_mem_is_zero((const char*)node->hsdir_index.fetch, DIGEST256_LEN))) { return 0; } - if (BUG(tor_mem_is_zero((const char*)node->hsdir_index.store_first, + if (BUG(fast_mem_is_zero((const char*)node->hsdir_index.store_first, DIGEST256_LEN))) { return 0; } - if (BUG(tor_mem_is_zero((const char*)node->hsdir_index.store_second, + if (BUG(fast_mem_is_zero((const char*)node->hsdir_index.store_second, DIGEST256_LEN))) { return 0; } @@ -1606,20 +1589,25 @@ hs_purge_last_hid_serv_requests(void) /** Given the list of responsible HSDirs in responsible_dirs, pick the * one that we should use to fetch a descriptor right now. Take into account * previous failed attempts at fetching this descriptor from HSDirs using the - * string identifier req_key_str. + * string identifier req_key_str. We return whether we are rate limited + * into *is_rate_limited_out if it is not NULL. * * Steals ownership of responsible_dirs. * * Return the routerstatus of the chosen HSDir if successful, otherwise return * NULL if no HSDirs are worth trying right now. */ routerstatus_t * -hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str) +hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str, + bool *is_rate_limited_out) { smartlist_t *usable_responsible_dirs = smartlist_new(); const or_options_t *options = get_options(); routerstatus_t *hs_dir; time_t now = time(NULL); int excluded_some; + bool rate_limited = false; + int rate_limited_count = 0; + int responsible_dirs_count = smartlist_len(responsible_dirs); tor_assert(req_key_str); @@ -1639,6 +1627,7 @@ hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str) if (last + hs_hsdir_requery_period(options) >= now || !node || !node_has_preferred_descriptor(node, 0)) { SMARTLIST_DEL_CURRENT(responsible_dirs, dir); + rate_limited_count++; continue; } if (!routerset_contains_node(options->ExcludeNodes, node)) { @@ -1646,6 +1635,10 @@ hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str) } } SMARTLIST_FOREACH_END(dir); + if (rate_limited_count > 0 || responsible_dirs_count > 0) { + rate_limited = rate_limited_count == responsible_dirs_count; + } + excluded_some = smartlist_len(usable_responsible_dirs) < smartlist_len(responsible_dirs); @@ -1657,9 +1650,10 @@ hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str) smartlist_free(responsible_dirs); smartlist_free(usable_responsible_dirs); if (!hs_dir) { + const char *warn_str = (rate_limited) ? "we are rate limited." : + "we requested them all recently without success"; log_info(LD_REND, "Could not pick one of the responsible hidden " - "service directories, because we requested them all " - "recently without success."); + "service directories, because %s.", warn_str); if (options->StrictNodes && excluded_some) { log_warn(LD_REND, "Could not pick a hidden service directory for the " "requested hidden service: they are all either down or " @@ -1671,17 +1665,23 @@ hs_pick_hsdir(smartlist_t *responsible_dirs, const char *req_key_str) hs_lookup_last_hid_serv_request(hs_dir, req_key_str, now, 1); } + if (is_rate_limited_out != NULL) { + *is_rate_limited_out = rate_limited; + } + return hs_dir; } -/* From a list of link specifier, an onion key and if we are requesting a - * direct connection (ex: single onion service), return a newly allocated - * extend_info_t object. This function always returns an extend info with - * an IPv4 address, or NULL. +/* Given a list of link specifiers lspecs, a curve 25519 onion_key, and + * a direct connection boolean direct_conn (true for single onion services), + * return a newly allocated extend_info_t object. + * + * This function always returns an extend info with a valid IP address and + * ORPort, or NULL. If direct_conn is false, the IP address is always IPv4. * * It performs the following checks: - * if either IPv4 or legacy ID is missing, return NULL. - * if direct_conn, and we can't reach the IPv4 address, return NULL. + * if there is no usable IP address, or legacy ID is missing, return NULL. + * if direct_conn, and we can't reach any IP address, return NULL. */ extend_info_t * hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, @@ -1690,21 +1690,40 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, { int have_v4 = 0, have_legacy_id = 0, have_ed25519_id = 0; char legacy_id[DIGEST_LEN] = {0}; - uint16_t port_v4 = 0; - tor_addr_t addr_v4; ed25519_public_key_t ed25519_pk; extend_info_t *info = NULL; + tor_addr_port_t ap; - tor_assert(lspecs); + tor_addr_make_null(&ap.addr, AF_UNSPEC); + ap.port = 0; + + if (lspecs == NULL) { + log_warn(LD_BUG, "Specified link specifiers is null"); + goto done; + } + + if (onion_key == NULL) { + log_warn(LD_BUG, "Specified onion key is null"); + goto done; + } + + if (smartlist_len(lspecs) == 0) { + log_fn(LOG_PROTOCOL_WARN, LD_REND, "Empty link specifier list."); + /* Return NULL. */ + goto done; + } SMARTLIST_FOREACH_BEGIN(lspecs, const link_specifier_t *, ls) { switch (link_specifier_get_ls_type(ls)) { case LS_IPV4: - /* Skip if we already seen a v4. */ - if (have_v4) continue; - tor_addr_from_ipv4h(&addr_v4, + /* Skip if we already seen a v4. If direct_conn is true, we skip this + * block because fascist_firewall_choose_address_ls() will set ap. If + * direct_conn is false, set ap to the first IPv4 address and port in + * the link specifiers.*/ + if (have_v4 || direct_conn) continue; + tor_addr_from_ipv4h(&ap.addr, link_specifier_get_un_ipv4_addr(ls)); - port_v4 = link_specifier_get_un_ipv4_port(ls); + ap.port = link_specifier_get_un_ipv4_port(ls); have_v4 = 1; break; case LS_LEGACY_ID: @@ -1728,45 +1747,38 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, } } SMARTLIST_FOREACH_END(ls); - /* Legacy ID is mandatory, and we require IPv4. */ - if (!have_v4 || !have_legacy_id) { + /* Choose a preferred address first, but fall back to an allowed address. */ + if (direct_conn) + fascist_firewall_choose_address_ls(lspecs, 0, &ap); + + /* Legacy ID is mandatory, and we require an IP address. */ + if (!tor_addr_port_is_valid_ap(&ap, 0)) { + /* If we're missing the IP address, log a warning and return NULL. */ + log_info(LD_NET, "Unreachable or invalid IP address in link state"); goto done; } - - /* We know we have IPv4, because we just checked. */ - if (!direct_conn) { - /* All clients can extend to any IPv4 via a 3-hop path. */ - goto validate; - } else if (direct_conn && - fascist_firewall_allows_address_addr(&addr_v4, port_v4, - FIREWALL_OR_CONNECTION, - 0, 0)) { - /* Direct connection and we can reach it in IPv4 so go for it. */ - goto validate; - - /* We will add support for falling back to a 3-hop path in a later - * release. */ - } else { - /* If we can't reach IPv4, return NULL. */ + if (!have_legacy_id) { + /* If we're missing the legacy ID, log a warning and return NULL. */ + log_warn(LD_PROTOCOL, "Missing Legacy ID in link state"); goto done; } - /* We will add support for IPv6 in a later release. */ + /* We will add support for falling back to a 3-hop path in a later + * release. */ - validate: /* We'll validate now that the address we've picked isn't a private one. If - * it is, are we allowing to extend to private address? */ - if (!extend_info_addr_is_allowed(&addr_v4)) { + * it is, are we allowed to extend to private addresses? */ + if (!extend_info_addr_is_allowed(&ap.addr)) { log_fn(LOG_PROTOCOL_WARN, LD_REND, "Requested address is private and we are not allowed to extend to " - "it: %s:%u", fmt_addr(&addr_v4), port_v4); + "it: %s:%u", fmt_addr(&ap.addr), ap.port); goto done; } /* We do have everything for which we think we can connect successfully. */ info = extend_info_new(NULL, legacy_id, (have_ed25519_id) ? &ed25519_pk : NULL, NULL, - onion_key, &addr_v4, port_v4); + onion_key, &ap.addr, ap.port); done: return info; } @@ -1827,3 +1839,42 @@ hs_inc_rdv_stream_counter(origin_circuit_t *circ) tor_assert_nonfatal_unreached(); } } + +/* Return a newly allocated link specifier object that is a copy of dst. */ +link_specifier_t * +link_specifier_dup(const link_specifier_t *src) +{ + link_specifier_t *dup = NULL; + uint8_t *buf = NULL; + + if (BUG(!src)) { + goto err; + } + + ssize_t encoded_len_alloc = link_specifier_encoded_len(src); + if (BUG(encoded_len_alloc < 0)) { + goto err; + } + + buf = tor_malloc_zero(encoded_len_alloc); + ssize_t encoded_len_data = link_specifier_encode(buf, + encoded_len_alloc, + src); + if (BUG(encoded_len_data < 0)) { + goto err; + } + + ssize_t parsed_len = link_specifier_parse(&dup, buf, encoded_len_alloc); + if (BUG(parsed_len < 0)) { + goto err; + } + + goto done; + + err: + dup = NULL; + + done: + tor_free(buf); + return dup; +} diff --git a/src/feature/hs/hs_common.h b/src/feature/hs/hs_common.h index a44505930a..3009780d90 100644 --- a/src/feature/hs/hs_common.h +++ b/src/feature/hs/hs_common.h @@ -217,8 +217,6 @@ uint64_t hs_get_time_period_num(time_t now); uint64_t hs_get_next_time_period_num(time_t now); time_t hs_get_start_time_of_next_time_period(time_t now); -link_specifier_t *hs_link_specifier_dup(const link_specifier_t *lspec); - MOCK_DECL(int, hs_in_period_between_tp_and_srv, (const networkstatus_t *consensus, time_t now)); @@ -243,7 +241,8 @@ void hs_get_responsible_hsdirs(const struct ed25519_public_key_t *blinded_pk, int use_second_hsdir_index, int for_fetching, smartlist_t *responsible_dirs); routerstatus_t *hs_pick_hsdir(smartlist_t *responsible_dirs, - const char *req_key_str); + const char *req_key_str, + bool *is_rate_limited_out); time_t hs_hsdir_requery_period(const or_options_t *options); time_t hs_lookup_last_hid_serv_request(routerstatus_t *hs_dir, @@ -262,6 +261,8 @@ extend_info_t *hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, const struct curve25519_public_key_t *onion_key, int direct_conn); +link_specifier_t *link_specifier_dup(const link_specifier_t *src); + #ifdef HS_COMMON_PRIVATE STATIC void get_disaster_srv(uint64_t time_period_num, uint8_t *srv_out); diff --git a/src/feature/hs/hs_config.c b/src/feature/hs/hs_config.c index ee4499ef5b..87f6257591 100644 --- a/src/feature/hs/hs_config.c +++ b/src/feature/hs/hs_config.c @@ -496,15 +496,6 @@ config_generic_service(const config_line_t *line_, * becomes a single onion service. */ if (rend_service_non_anonymous_mode_enabled(options)) { config->is_single_onion = 1; - /* We will add support for IPv6-only v3 single onion services in a future - * Tor version. This won't catch "ReachableAddresses reject *4", but that - * option doesn't work anyway. */ - if (options->ClientUseIPv4 == 0 && config->version == HS_VERSION_THREE) { - log_warn(LD_CONFIG, "IPv6-only v3 single onion services are not " - "supported. Set HiddenServiceSingleHopMode 0 and " - "HiddenServiceNonAnonymousMode 0, or set ClientUseIPv4 1."); - goto err; - } } /* Success */ diff --git a/src/feature/hs/hs_control.c b/src/feature/hs/hs_control.c index 9970fdd123..abb421345c 100644 --- a/src/feature/hs/hs_control.c +++ b/src/feature/hs/hs_control.c @@ -7,9 +7,10 @@ **/ #include "core/or/or.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "lib/crypt_ops/crypto_format.h" #include "lib/crypt_ops/crypto_util.h" +#include "feature/hs/hs_client.h" #include "feature/hs/hs_common.h" #include "feature/hs/hs_control.h" #include "feature/hs/hs_descriptor.h" @@ -73,10 +74,7 @@ hs_control_desc_event_failed(const hs_ident_dir_conn_t *ident, tor_assert(reason); /* Build onion address and encoded blinded key. */ - IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk, - &ident->blinded_pk) < 0) { - return; - } + ed25519_public_to_base64(base64_blinded_pk, &ident->blinded_pk); hs_build_address(&ident->identity_pk, HS_VERSION_THREE, onion_address); control_event_hsv3_descriptor_failed(onion_address, base64_blinded_pk, @@ -98,10 +96,7 @@ hs_control_desc_event_received(const hs_ident_dir_conn_t *ident, tor_assert(hsdir_id_digest); /* Build onion address and encoded blinded key. */ - IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk, - &ident->blinded_pk) < 0) { - return; - } + ed25519_public_to_base64(base64_blinded_pk, &ident->blinded_pk); hs_build_address(&ident->identity_pk, HS_VERSION_THREE, onion_address); control_event_hsv3_descriptor_received(onion_address, base64_blinded_pk, @@ -122,9 +117,7 @@ hs_control_desc_event_created(const char *onion_address, tor_assert(blinded_pk); /* Build base64 encoded blinded key. */ - IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk, blinded_pk) < 0) { - return; - } + ed25519_public_to_base64(base64_blinded_pk, blinded_pk); /* Version 3 doesn't use the replica number in its descriptor ID computation * so we pass negative value so the control port subsystem can ignore it. */ @@ -150,9 +143,7 @@ hs_control_desc_event_upload(const char *onion_address, tor_assert(hsdir_index); /* Build base64 encoded blinded key. */ - IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk, blinded_pk) < 0) { - return; - } + ed25519_public_to_base64(base64_blinded_pk, blinded_pk); control_event_hs_descriptor_upload(onion_address, hsdir_id_digest, base64_blinded_pk, @@ -195,10 +186,7 @@ hs_control_desc_event_content(const hs_ident_dir_conn_t *ident, tor_assert(hsdir_id_digest); /* Build onion address and encoded blinded key. */ - IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk, - &ident->blinded_pk) < 0) { - return; - } + ed25519_public_to_base64(base64_blinded_pk, &ident->blinded_pk); hs_build_address(&ident->identity_pk, HS_VERSION_THREE, onion_address); control_event_hs_descriptor_content(onion_address, base64_blinded_pk, @@ -259,3 +247,16 @@ hs_control_hspost_command(const char *body, const char *onion_address, smartlist_free(hsdirs); return ret; } + +/* With a given onion_identity_pk, fetch its descriptor, optionally + * using the list of directory servers given in hsdirs, or a random + * server if it is NULL. This function calls hs_client_launch_v3_desc_fetch(). + */ +void +hs_control_hsfetch_command(const ed25519_public_key_t *onion_identity_pk, + const smartlist_t *hsdirs) +{ + tor_assert(onion_identity_pk); + + hs_client_launch_v3_desc_fetch(onion_identity_pk, hsdirs); +} diff --git a/src/feature/hs/hs_control.h b/src/feature/hs/hs_control.h index f7ab642652..b55e4c53c9 100644 --- a/src/feature/hs/hs_control.h +++ b/src/feature/hs/hs_control.h @@ -48,5 +48,9 @@ void hs_control_desc_event_content(const hs_ident_dir_conn_t *ident, int hs_control_hspost_command(const char *body, const char *onion_address, const smartlist_t *hsdirs_rs); +/* Command "HSFETCH [...]" */ +void hs_control_hsfetch_command(const ed25519_public_key_t *onion_identity_pk, + const smartlist_t *hsdirs); + #endif /* !defined(TOR_HS_CONTROL_H) */ diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c index b09d50e010..a8796c0029 100644 --- a/src/feature/hs/hs_descriptor.c +++ b/src/feature/hs/hs_descriptor.c @@ -324,12 +324,11 @@ encode_link_specifiers(const smartlist_t *specs) link_specifier_list_set_n_spec(lslist, smartlist_len(specs)); - SMARTLIST_FOREACH_BEGIN(specs, const hs_desc_link_specifier_t *, + SMARTLIST_FOREACH_BEGIN(specs, const link_specifier_t *, spec) { - link_specifier_t *ls = hs_desc_lspec_to_trunnel(spec); - if (ls) { - link_specifier_list_add_spec(lslist, ls); - } + link_specifier_t *ls = link_specifier_dup(spec); + tor_assert(ls); + link_specifier_list_add_spec(lslist, ls); } SMARTLIST_FOREACH_END(spec); { @@ -404,9 +403,7 @@ encode_enc_key(const hs_desc_intro_point_t *ip) tor_assert(ip); /* Base64 encode the encryption key for the "enc-key" field. */ - if (curve25519_public_to_base64(key_b64, &ip->enc_key) < 0) { - goto done; - } + curve25519_public_to_base64(key_b64, &ip->enc_key); if (tor_cert_encode_ed22519(ip->enc_key_cert, &encoded_cert) < 0) { goto done; } @@ -422,7 +419,7 @@ encode_enc_key(const hs_desc_intro_point_t *ip) } /* Encode an introduction point onion key. Return a newly allocated string - * with it. On failure, return NULL. */ + * with it. Can not fail. */ static char * encode_onion_key(const hs_desc_intro_point_t *ip) { @@ -432,12 +429,9 @@ encode_onion_key(const hs_desc_intro_point_t *ip) tor_assert(ip); /* Base64 encode the encryption key for the "onion-key" field. */ - if (curve25519_public_to_base64(key_b64, &ip->onion_key) < 0) { - goto done; - } + curve25519_public_to_base64(key_b64, &ip->onion_key); tor_asprintf(&encoded, "%s ntor %s", str_ip_onion_key, key_b64); - done: return encoded; } @@ -684,7 +678,7 @@ get_auth_client_str(const hs_desc_authorized_client_t *client) char encrypted_cookie_b64[HS_DESC_ENCRYPED_COOKIE_LEN * 2]; #define ASSERT_AND_BASE64(field) STMT_BEGIN \ - tor_assert(!tor_mem_is_zero((char *) client->field, \ + tor_assert(!fast_mem_is_zero((char *) client->field, \ sizeof(client->field))); \ ret = base64_encode_nopad(field##_b64, sizeof(field##_b64), \ client->field, sizeof(client->field)); \ @@ -798,8 +792,8 @@ get_inner_encrypted_layer_plaintext(const hs_descriptor_t *desc) /* Create the middle layer of the descriptor, which includes the client auth * data and the encrypted inner layer (provided as a base64 string at * layer2_b64_ciphertext). Return a newly-allocated string with the - * layer plaintext, or NULL if an error occurred. It's the responsibility of - * the caller to free the returned string. */ + * layer plaintext. It's the responsibility of the caller to free the returned + * string. Can not fail. */ static char * get_outer_encrypted_layer_plaintext(const hs_descriptor_t *desc, const char *layer2_b64_ciphertext) @@ -815,13 +809,10 @@ get_outer_encrypted_layer_plaintext(const hs_descriptor_t *desc, const curve25519_public_key_t *ephemeral_pubkey; ephemeral_pubkey = &desc->superencrypted_data.auth_ephemeral_pubkey; - tor_assert(!tor_mem_is_zero((char *) ephemeral_pubkey->public_key, + tor_assert(!fast_mem_is_zero((char *) ephemeral_pubkey->public_key, CURVE25519_PUBKEY_LEN)); - if (curve25519_public_to_base64(ephemeral_key_base64, - ephemeral_pubkey) < 0) { - goto done; - } + curve25519_public_to_base64(ephemeral_key_base64, ephemeral_pubkey); smartlist_add_asprintf(lines, "%s %s\n", str_desc_auth_key, ephemeral_key_base64); @@ -846,7 +837,6 @@ get_outer_encrypted_layer_plaintext(const hs_descriptor_t *desc, layer1_str = smartlist_join_strings(lines, "", 0, NULL); - done: /* We need to memwipe all lines because it contains the ephemeral key */ SMARTLIST_FOREACH(lines, char *, a, memwipe(a, 0, strlen(a))); SMARTLIST_FOREACH(lines, char *, a, tor_free(a)); @@ -1092,11 +1082,7 @@ desc_encode_v3(const hs_descriptor_t *desc, tor_free(encoded_str); goto err; } - if (ed25519_signature_to_base64(ed_sig_b64, &sig) < 0) { - log_warn(LD_BUG, "Can't base64 encode descriptor signature!"); - tor_free(encoded_str); - goto err; - } + ed25519_signature_to_base64(ed_sig_b64, &sig); /* Create the signature line. */ smartlist_add_asprintf(lines, "%s %s", str_signature, ed_sig_b64); } @@ -1190,52 +1176,22 @@ decode_link_specifiers(const char *encoded) results = smartlist_new(); for (i = 0; i < link_specifier_list_getlen_spec(specs); i++) { - hs_desc_link_specifier_t *hs_spec; link_specifier_t *ls = link_specifier_list_get_spec(specs, i); - tor_assert(ls); - - hs_spec = tor_malloc_zero(sizeof(*hs_spec)); - hs_spec->type = link_specifier_get_ls_type(ls); - switch (hs_spec->type) { - case LS_IPV4: - tor_addr_from_ipv4h(&hs_spec->u.ap.addr, - link_specifier_get_un_ipv4_addr(ls)); - hs_spec->u.ap.port = link_specifier_get_un_ipv4_port(ls); - break; - case LS_IPV6: - tor_addr_from_ipv6_bytes(&hs_spec->u.ap.addr, (const char *) - link_specifier_getarray_un_ipv6_addr(ls)); - hs_spec->u.ap.port = link_specifier_get_un_ipv6_port(ls); - break; - case LS_LEGACY_ID: - /* Both are known at compile time so let's make sure they are the same - * else we can copy memory out of bound. */ - tor_assert(link_specifier_getlen_un_legacy_id(ls) == - sizeof(hs_spec->u.legacy_id)); - memcpy(hs_spec->u.legacy_id, link_specifier_getarray_un_legacy_id(ls), - sizeof(hs_spec->u.legacy_id)); - break; - case LS_ED25519_ID: - /* Both are known at compile time so let's make sure they are the same - * else we can copy memory out of bound. */ - tor_assert(link_specifier_getlen_un_ed25519_id(ls) == - sizeof(hs_spec->u.ed25519_id)); - memcpy(hs_spec->u.ed25519_id, - link_specifier_getconstarray_un_ed25519_id(ls), - sizeof(hs_spec->u.ed25519_id)); - break; - default: - tor_free(hs_spec); + if (BUG(!ls)) { goto err; } - - smartlist_add(results, hs_spec); + link_specifier_t *ls_dup = link_specifier_dup(ls); + if (BUG(!ls_dup)) { + goto err; + } + smartlist_add(results, ls_dup); } goto done; err: if (results) { - SMARTLIST_FOREACH(results, hs_desc_link_specifier_t *, s, tor_free(s)); + SMARTLIST_FOREACH(results, link_specifier_t *, s, + link_specifier_free(s)); smartlist_free(results); results = NULL; } @@ -1465,12 +1421,12 @@ decrypt_descriptor_cookie(const hs_descriptor_t *desc, tor_assert(desc); tor_assert(client); tor_assert(client_auth_sk); - tor_assert(!tor_mem_is_zero( + tor_assert(!fast_mem_is_zero( (char *) &desc->superencrypted_data.auth_ephemeral_pubkey, sizeof(desc->superencrypted_data.auth_ephemeral_pubkey))); - tor_assert(!tor_mem_is_zero((char *) client_auth_sk, + tor_assert(!fast_mem_is_zero((char *) client_auth_sk, sizeof(*client_auth_sk))); - tor_assert(!tor_mem_is_zero((char *) desc->subcredential, DIGEST256_LEN)); + tor_assert(!fast_mem_is_zero((char *) desc->subcredential, DIGEST256_LEN)); /* Get the KEYS component to derive the CLIENT-ID and COOKIE-KEY. */ keystream_length = @@ -2012,6 +1968,7 @@ decode_intro_points(const hs_descriptor_t *desc, SMARTLIST_FOREACH(intro_points, char *, a, tor_free(a)); smartlist_free(intro_points); } + /* Return 1 iff the given base64 encoded signature in b64_sig from the encoded * descriptor in encoded_desc validates the descriptor content. */ STATIC int @@ -2615,7 +2572,7 @@ hs_desc_decode_descriptor(const char *encoded, /* Subcredentials are not optional. */ if (BUG(!subcredential || - tor_mem_is_zero((char*)subcredential, DIGEST256_LEN))) { + fast_mem_is_zero((char*)subcredential, DIGEST256_LEN))) { log_warn(LD_GENERAL, "Tried to decrypt without subcred. Impossible!"); goto err; } @@ -2878,8 +2835,8 @@ hs_desc_intro_point_free_(hs_desc_intro_point_t *ip) return; } if (ip->link_specifiers) { - SMARTLIST_FOREACH(ip->link_specifiers, hs_desc_link_specifier_t *, - ls, hs_desc_link_specifier_free(ls)); + SMARTLIST_FOREACH(ip->link_specifiers, link_specifier_t *, + ls, link_specifier_free(ls)); smartlist_free(ip->link_specifiers); } tor_cert_free(ip->auth_key_cert); @@ -2928,13 +2885,13 @@ hs_desc_build_authorized_client(const uint8_t *subcredential, tor_assert(descriptor_cookie); tor_assert(client_out); tor_assert(subcredential); - tor_assert(!tor_mem_is_zero((char *) auth_ephemeral_sk, + tor_assert(!fast_mem_is_zero((char *) auth_ephemeral_sk, sizeof(*auth_ephemeral_sk))); - tor_assert(!tor_mem_is_zero((char *) client_auth_pk, + tor_assert(!fast_mem_is_zero((char *) client_auth_pk, sizeof(*client_auth_pk))); - tor_assert(!tor_mem_is_zero((char *) descriptor_cookie, + tor_assert(!fast_mem_is_zero((char *) descriptor_cookie, HS_DESC_DESCRIPTOR_COOKIE_LEN)); - tor_assert(!tor_mem_is_zero((char *) subcredential, + tor_assert(!fast_mem_is_zero((char *) subcredential, DIGEST256_LEN)); /* Get the KEYS part so we can derive the CLIENT-ID and COOKIE-KEY. */ @@ -2972,69 +2929,6 @@ hs_desc_authorized_client_free_(hs_desc_authorized_client_t *client) tor_free(client); } -/* Free the given descriptor link specifier. */ -void -hs_desc_link_specifier_free_(hs_desc_link_specifier_t *ls) -{ - if (ls == NULL) { - return; - } - tor_free(ls); -} - -/* Return a newly allocated descriptor link specifier using the given extend - * info and requested type. Return NULL on error. */ -hs_desc_link_specifier_t * -hs_desc_link_specifier_new(const extend_info_t *info, uint8_t type) -{ - hs_desc_link_specifier_t *ls = NULL; - - tor_assert(info); - - ls = tor_malloc_zero(sizeof(*ls)); - ls->type = type; - switch (ls->type) { - case LS_IPV4: - if (info->addr.family != AF_INET) { - goto err; - } - tor_addr_copy(&ls->u.ap.addr, &info->addr); - ls->u.ap.port = info->port; - break; - case LS_IPV6: - if (info->addr.family != AF_INET6) { - goto err; - } - tor_addr_copy(&ls->u.ap.addr, &info->addr); - ls->u.ap.port = info->port; - break; - case LS_LEGACY_ID: - /* Bug out if the identity digest is not set */ - if (BUG(tor_mem_is_zero(info->identity_digest, - sizeof(info->identity_digest)))) { - goto err; - } - memcpy(ls->u.legacy_id, info->identity_digest, sizeof(ls->u.legacy_id)); - break; - case LS_ED25519_ID: - /* ed25519 keys are optional for intro points */ - if (ed25519_public_key_is_zero(&info->ed_identity)) { - goto err; - } - memcpy(ls->u.ed25519_id, info->ed_identity.pubkey, - sizeof(ls->u.ed25519_id)); - break; - default: - /* Unknown type is code flow error. */ - tor_assert(0); - } - - return ls; - err: - tor_free(ls); - return NULL; -} - /* From the given descriptor, remove and free every introduction point. */ void hs_descriptor_clear_intro_points(hs_descriptor_t *desc) @@ -3050,59 +2944,3 @@ hs_descriptor_clear_intro_points(hs_descriptor_t *desc) smartlist_clear(ips); } } - -/* From a descriptor link specifier object spec, returned a newly allocated - * link specifier object that is the encoded representation of spec. Return - * NULL on error. */ -link_specifier_t * -hs_desc_lspec_to_trunnel(const hs_desc_link_specifier_t *spec) -{ - tor_assert(spec); - - link_specifier_t *ls = link_specifier_new(); - link_specifier_set_ls_type(ls, spec->type); - - switch (spec->type) { - case LS_IPV4: - link_specifier_set_un_ipv4_addr(ls, - tor_addr_to_ipv4h(&spec->u.ap.addr)); - link_specifier_set_un_ipv4_port(ls, spec->u.ap.port); - /* Four bytes IPv4 and two bytes port. */ - link_specifier_set_ls_len(ls, sizeof(spec->u.ap.addr.addr.in_addr) + - sizeof(spec->u.ap.port)); - break; - case LS_IPV6: - { - size_t addr_len = link_specifier_getlen_un_ipv6_addr(ls); - const uint8_t *in6_addr = tor_addr_to_in6_addr8(&spec->u.ap.addr); - uint8_t *ipv6_array = link_specifier_getarray_un_ipv6_addr(ls); - memcpy(ipv6_array, in6_addr, addr_len); - link_specifier_set_un_ipv6_port(ls, spec->u.ap.port); - /* Sixteen bytes IPv6 and two bytes port. */ - link_specifier_set_ls_len(ls, addr_len + sizeof(spec->u.ap.port)); - break; - } - case LS_LEGACY_ID: - { - size_t legacy_id_len = link_specifier_getlen_un_legacy_id(ls); - uint8_t *legacy_id_array = link_specifier_getarray_un_legacy_id(ls); - memcpy(legacy_id_array, spec->u.legacy_id, legacy_id_len); - link_specifier_set_ls_len(ls, legacy_id_len); - break; - } - case LS_ED25519_ID: - { - size_t ed25519_id_len = link_specifier_getlen_un_ed25519_id(ls); - uint8_t *ed25519_id_array = link_specifier_getarray_un_ed25519_id(ls); - memcpy(ed25519_id_array, spec->u.ed25519_id, ed25519_id_len); - link_specifier_set_ls_len(ls, ed25519_id_len); - break; - } - default: - tor_assert_nonfatal_unreached(); - link_specifier_free(ls); - ls = NULL; - } - - return ls; -} diff --git a/src/feature/hs/hs_descriptor.h b/src/feature/hs/hs_descriptor.h index 04a8e16d63..dbe0cb1c94 100644 --- a/src/feature/hs/hs_descriptor.h +++ b/src/feature/hs/hs_descriptor.h @@ -69,28 +69,10 @@ typedef enum { HS_DESC_AUTH_ED25519 = 1 } hs_desc_auth_type_t; -/* Link specifier object that contains information on how to extend to the - * relay that is the address, port and handshake type. */ -typedef struct hs_desc_link_specifier_t { - /* Indicate the type of link specifier. See trunnel ed25519_cert - * specification. */ - uint8_t type; - - /* It must be one of these types, can't be more than one. */ - union { - /* IP address and port of the relay use to extend. */ - tor_addr_port_t ap; - /* Legacy identity. A 20-byte SHA1 identity fingerprint. */ - uint8_t legacy_id[DIGEST_LEN]; - /* ed25519 identity. A 32-byte key. */ - uint8_t ed25519_id[ED25519_PUBKEY_LEN]; - } u; -} hs_desc_link_specifier_t; - /* Introduction point information located in a descriptor. */ typedef struct hs_desc_intro_point_t { /* Link specifier(s) which details how to extend to the relay. This list - * contains hs_desc_link_specifier_t object. It MUST have at least one. */ + * contains link_specifier_t objects. It MUST have at least one. */ smartlist_t *link_specifiers; /* Onion key of the introduction point used to extend to it for the ntor @@ -261,12 +243,6 @@ void hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc); #define hs_desc_encrypted_data_free(desc) \ FREE_AND_NULL(hs_desc_encrypted_data_t, hs_desc_encrypted_data_free_, (desc)) -void hs_desc_link_specifier_free_(hs_desc_link_specifier_t *ls); -#define hs_desc_link_specifier_free(ls) \ - FREE_AND_NULL(hs_desc_link_specifier_t, hs_desc_link_specifier_free_, (ls)) - -hs_desc_link_specifier_t *hs_desc_link_specifier_new( - const extend_info_t *info, uint8_t type); void hs_descriptor_clear_intro_points(hs_descriptor_t *desc); MOCK_DECL(int, @@ -299,9 +275,6 @@ void hs_desc_authorized_client_free_(hs_desc_authorized_client_t *client); FREE_AND_NULL(hs_desc_authorized_client_t, \ hs_desc_authorized_client_free_, (client)) -link_specifier_t *hs_desc_lspec_to_trunnel( - const hs_desc_link_specifier_t *spec); - hs_desc_authorized_client_t *hs_desc_build_fake_authorized_client(void); void hs_desc_build_authorized_client(const uint8_t *subcredential, const curve25519_public_key_t * diff --git a/src/feature/hs/hs_intropoint.c b/src/feature/hs/hs_intropoint.c index 7717ed53d4..9333060e7e 100644 --- a/src/feature/hs/hs_intropoint.c +++ b/src/feature/hs/hs_intropoint.c @@ -392,7 +392,7 @@ validate_introduce1_parsed_cell(const trn_cell_introduce1_t *cell) * safety net here. The legacy ID must be zeroes in this case. */ legacy_key_id_len = trn_cell_introduce1_getlen_legacy_key_id(cell); legacy_key_id = trn_cell_introduce1_getconstarray_legacy_key_id(cell); - if (BUG(!tor_mem_is_zero((char *) legacy_key_id, legacy_key_id_len))) { + if (BUG(!fast_mem_is_zero((char *) legacy_key_id, legacy_key_id_len))) { goto invalid; } @@ -518,7 +518,7 @@ introduce1_cell_is_legacy(const uint8_t *request) /* If the first 20 bytes of the cell (DIGEST_LEN) are NOT zeroes, it * indicates a legacy cell (v2). */ - if (!tor_mem_is_zero((const char *) request, DIGEST_LEN)) { + if (!fast_mem_is_zero((const char *) request, DIGEST_LEN)) { /* Legacy cell. */ return 1; } @@ -602,8 +602,8 @@ hs_intropoint_clear(hs_intropoint_t *ip) return; } tor_cert_free(ip->auth_key_cert); - SMARTLIST_FOREACH(ip->link_specifiers, hs_desc_link_specifier_t *, ls, - hs_desc_link_specifier_free(ls)); + SMARTLIST_FOREACH(ip->link_specifiers, link_specifier_t *, ls, + link_specifier_free(ls)); smartlist_free(ip->link_specifiers); memset(ip, 0, sizeof(hs_intropoint_t)); } diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index 21eadd2998..2835912742 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -280,9 +280,10 @@ describe_intro_point(const hs_service_intro_point_t *ip) const char *legacy_id = NULL; SMARTLIST_FOREACH_BEGIN(ip->base.link_specifiers, - const hs_desc_link_specifier_t *, lspec) { - if (lspec->type == LS_LEGACY_ID) { - legacy_id = (const char *) lspec->u.legacy_id; + const link_specifier_t *, lspec) { + if (link_specifier_get_ls_type(lspec) == LS_LEGACY_ID) { + legacy_id = (const char *) + link_specifier_getconstarray_un_legacy_id(lspec); break; } } SMARTLIST_FOREACH_END(lspec); @@ -426,23 +427,16 @@ 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. - * If supports_ed25519_link_handshake_any is true, we add the relay's ed25519 - * key to the link specifiers. + * given node_t node, if non NULL. * - * If ei is NULL, returns a hs_service_intro_point_t with an empty link + * If node 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. */ + * node must be an node_t with an IPv4 address. */ STATIC hs_service_intro_point_t * -service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy, - unsigned int supports_ed25519_link_handshake_any) +service_intro_point_new(const node_t *node) { - hs_desc_link_specifier_t *ls; hs_service_intro_point_t *ip; ip = tor_malloc_zero(sizeof(*ip)); @@ -472,12 +466,17 @@ service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy, ip->replay_cache = replaycache_new(0, 0); /* Initialize the base object. We don't need the certificate object. */ - ip->base.link_specifiers = smartlist_new(); + ip->base.link_specifiers = node_get_link_specifier_smartlist(node, 0); + + if (node == NULL) { + goto done; + } /* Generate the encryption key for this intro point. */ curve25519_keypair_generate(&ip->enc_key_kp, 0); - /* Figure out if this chosen node supports v3 or is legacy only. */ - if (is_legacy) { + /* Figure out if this chosen node supports v3 or is legacy only. + * NULL nodes are used in the unit tests. */ + if (!node_supports_ed25519_hs_intro(node)) { ip->base.is_only_legacy = 1; /* Legacy mode that is doesn't support v3+ with ed25519 auth key. */ ip->legacy_key = crypto_pk_new(); @@ -490,40 +489,9 @@ service_intro_point_new(const extend_info_t *ei, unsigned int is_legacy, } } - if (ei == NULL) { - goto done; - } - - /* We'll try to add all link specifiers. Legacy is mandatory. - * IPv4 or IPv6 is required, and we always send IPv4. */ - ls = hs_desc_link_specifier_new(ei, LS_IPV4); - /* It is impossible to have an extend info object without a v4. */ - if (BUG(!ls)) { - goto err; - } - smartlist_add(ip->base.link_specifiers, ls); - - ls = hs_desc_link_specifier_new(ei, LS_LEGACY_ID); - /* It is impossible to have an extend info object without an identity - * digest. */ - if (BUG(!ls)) { - goto err; - } - 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. */ - - /* Finally, copy onion key from the extend_info_t object. */ - memcpy(&ip->onion_key, &ei->curve25519_onion_key, sizeof(ip->onion_key)); + /* Finally, copy onion key from the node. */ + memcpy(&ip->onion_key, node_get_curve25519_onion_key(node), + sizeof(ip->onion_key)); done: return ip; @@ -656,16 +624,16 @@ get_objects_from_ident(const hs_ident_circuit_t *ident, * encountered in the link specifier list. Return NULL if it can't be found. * * The caller does NOT have ownership of the object, the intro point does. */ -static hs_desc_link_specifier_t * +static link_specifier_t * get_link_spec_by_type(const hs_service_intro_point_t *ip, uint8_t type) { - hs_desc_link_specifier_t *lnk_spec = NULL; + link_specifier_t *lnk_spec = NULL; tor_assert(ip); SMARTLIST_FOREACH_BEGIN(ip->base.link_specifiers, - hs_desc_link_specifier_t *, ls) { - if (ls->type == type) { + link_specifier_t *, ls) { + if (link_specifier_get_ls_type(ls) == type) { lnk_spec = ls; goto end; } @@ -681,7 +649,7 @@ get_link_spec_by_type(const hs_service_intro_point_t *ip, uint8_t type) STATIC const node_t * get_node_from_intro_point(const hs_service_intro_point_t *ip) { - const hs_desc_link_specifier_t *ls; + const link_specifier_t *ls; tor_assert(ip); @@ -690,7 +658,8 @@ get_node_from_intro_point(const hs_service_intro_point_t *ip) return NULL; } /* XXX In the future, we want to only use the ed25519 ID (#22173). */ - return node_get_by_id((const char *) ls->u.legacy_id); + return node_get_by_id( + (const char *) link_specifier_getconstarray_un_legacy_id(ls)); } /* Given a service intro point, return the extend_info_t for it. This can @@ -1179,7 +1148,8 @@ parse_authorized_client(const char *client_key_str) client = tor_malloc_zero(sizeof(hs_service_authorized_client_t)); if (base32_decode((char *) client->client_pk.public_key, sizeof(client->client_pk.public_key), - pubkey_b32, strlen(pubkey_b32)) < 0) { + pubkey_b32, strlen(pubkey_b32)) != + sizeof(client->client_pk.public_key)) { log_warn(LD_REND, "Client authorization public key cannot be decoded: %s", pubkey_b32); goto err; @@ -1261,7 +1231,7 @@ load_client_keys(hs_service_t *service) client_key_str = read_file_to_str(client_key_file_path, 0, NULL); /* If we cannot read the file, continue with the next file. */ - if (!client_key_str) { + if (!client_key_str) { log_warn(LD_REND, "Client authorization file %s can't be read. " "Corrupted or verify permission? Ignoring.", client_key_file_path); @@ -1556,7 +1526,7 @@ remember_failing_intro_point(const hs_service_intro_point_t *ip, hs_service_descriptor_t *desc, time_t now) { time_t *time_of_failure, *prev_ptr; - const hs_desc_link_specifier_t *legacy_ls; + const link_specifier_t *legacy_ls; tor_assert(ip); tor_assert(desc); @@ -1565,22 +1535,13 @@ remember_failing_intro_point(const hs_service_intro_point_t *ip, *time_of_failure = now; legacy_ls = get_link_spec_by_type(ip, LS_LEGACY_ID); tor_assert(legacy_ls); - prev_ptr = digestmap_set(desc->intro_points.failed_id, - (const char *) legacy_ls->u.legacy_id, - time_of_failure); + prev_ptr = digestmap_set( + desc->intro_points.failed_id, + (const char *) link_specifier_getconstarray_un_legacy_id(legacy_ls), + time_of_failure); tor_free(prev_ptr); } -/* Copy the descriptor link specifier object from src to dst. */ -static void -link_specifier_copy(hs_desc_link_specifier_t *dst, - const hs_desc_link_specifier_t *src) -{ - tor_assert(dst); - tor_assert(src); - memcpy(dst, src, sizeof(hs_desc_link_specifier_t)); -} - /* Using a given descriptor signing keypair signing_kp, a service intro point * object ip and the time now, setup the content of an already allocated * descriptor intro desc_ip. @@ -1615,9 +1576,14 @@ setup_desc_intro_point(const ed25519_keypair_t *signing_kp, /* Copy link specifier(s). */ SMARTLIST_FOREACH_BEGIN(ip->base.link_specifiers, - const hs_desc_link_specifier_t *, ls) { - hs_desc_link_specifier_t *copy = tor_malloc_zero(sizeof(*copy)); - link_specifier_copy(copy, ls); + const link_specifier_t *, ls) { + if (BUG(!ls)) { + goto done; + } + link_specifier_t *copy = link_specifier_dup(ls); + if (BUG(!copy)) { + goto done; + } smartlist_add(desc_ip->link_specifiers, copy); } SMARTLIST_FOREACH_END(ls); @@ -1780,7 +1746,7 @@ build_service_desc_superencrypted(const hs_service_t *service, sizeof(curve25519_public_key_t)); /* Test that subcred is not zero because we might use it below */ - if (BUG(tor_mem_is_zero((char*)desc->desc->subcredential, DIGEST256_LEN))) { + if (BUG(fast_mem_is_zero((char*)desc->desc->subcredential, DIGEST256_LEN))) { return -1; } @@ -1846,9 +1812,9 @@ build_service_desc_plaintext(const hs_service_t *service, tor_assert(service); tor_assert(desc); - tor_assert(!tor_mem_is_zero((char *) &desc->blinded_kp, + tor_assert(!fast_mem_is_zero((char *) &desc->blinded_kp, sizeof(desc->blinded_kp))); - tor_assert(!tor_mem_is_zero((char *) &desc->signing_kp, + tor_assert(!fast_mem_is_zero((char *) &desc->signing_kp, sizeof(desc->signing_kp))); /* Set the subcredential. */ @@ -1898,7 +1864,7 @@ build_service_desc_keys(const hs_service_t *service, ed25519_keypair_t kp; tor_assert(desc); - tor_assert(!tor_mem_is_zero((char *) &service->keys.identity_pk, + tor_assert(!fast_mem_is_zero((char *) &service->keys.identity_pk, ED25519_PUBKEY_LEN)); /* XXX: Support offline key feature (#18098). */ @@ -2105,19 +2071,27 @@ build_all_descriptors(time_t now) static hs_service_intro_point_t * pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes) { + const or_options_t *options = get_options(); const node_t *node; - extend_info_t *info = NULL; hs_service_intro_point_t *ip = NULL; /* Normal 3-hop introduction point flags. */ router_crn_flags_t flags = CRN_NEED_UPTIME | CRN_NEED_DESC; /* Single onion flags. */ router_crn_flags_t direct_flags = flags | CRN_PREF_ADDR | CRN_DIRECT_CONN; - node = router_choose_random_node(exclude_nodes, get_options()->ExcludeNodes, + node = router_choose_random_node(exclude_nodes, options->ExcludeNodes, direct_conn ? direct_flags : flags); - /* Unable to find a node. When looking for a node for a direct connection, - * we could try a 3-hop path instead. We'll add support for this in a later - * release. */ + + /* If we are in single onion mode, retry node selection for a 3-hop + * path */ + if (direct_conn && !node) { + log_info(LD_REND, + "Unable to find an intro point that we can connect to " + "directly, falling back to a 3-hop path."); + node = router_choose_random_node(exclude_nodes, options->ExcludeNodes, + flags); + } + if (!node) { goto err; } @@ -2127,43 +2101,17 @@ pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes) * we don't want to use that node anymore. */ smartlist_add(exclude_nodes, (void *) node); - /* We do this to ease our life but also this call makes appropriate checks - * of the node object such as validating ntor support for instance. - * - * We must provide an extend_info for clients to connect over a 3-hop path, - * so we don't pass direct_conn here. */ - info = extend_info_from_node(node, 0); - if (BUG(info == NULL)) { - goto err; - } - - /* Let's do a basic sanity check here so that we don't end up advertising the - * ed25519 identity key of relays that don't actually support the link - * protocol */ - if (!node_supports_ed25519_link_authentication(node, 0)) { - tor_assert_nonfatal(ed25519_public_key_is_zero(&info->ed_identity)); - } else { - /* Make sure we *do* have an ed key if we support the link authentication. - * Sending an empty key would result in a failure to extend. */ - 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(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; } - log_info(LD_REND, "Picked intro point: %s", extend_info_describe(info)); - extend_info_free(info); + log_info(LD_REND, "Picked intro point: %s", node_describe(node)); return ip; err: service_intro_point_free(ip); - extend_info_free(info); return NULL; } @@ -2644,7 +2592,7 @@ launch_intro_point_circuits(hs_service_t *service) * circuits using the current map. */ FOR_EACH_DESCRIPTOR_BEGIN(service, desc) { /* Keep a ref on if we need a direct connection. We use this often. */ - unsigned int direct_conn = service->config.is_single_onion; + bool direct_conn = service->config.is_single_onion; DIGEST256MAP_FOREACH_MODIFY(desc->intro_points.map, key, hs_service_intro_point_t *, ip) { @@ -2655,8 +2603,15 @@ launch_intro_point_circuits(hs_service_t *service) if (hs_circ_service_get_intro_circ(ip)) { continue; } - ei = get_extend_info_from_intro_point(ip, direct_conn); + + /* If we can't connect directly to the intro point, get an extend_info + * for a multi-hop path instead. */ + if (ei == NULL && direct_conn) { + direct_conn = false; + ei = get_extend_info_from_intro_point(ip, 0); + } + if (ei == NULL) { /* This is possible if we can get a node_t but not the extend info out * of it. In this case, we remove the intro point and a new one will @@ -2668,7 +2623,7 @@ launch_intro_point_circuits(hs_service_t *service) /* Launch a circuit to the intro point. */ ip->circuit_retries++; - if (hs_circ_launch_intro_point(service, ip, ei) < 0) { + if (hs_circ_launch_intro_point(service, ip, ei, direct_conn) < 0) { log_info(LD_REND, "Unable to launch intro circuit to node %s " "for service %s.", safe_str_client(extend_info_describe(ei)), diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h index ec53f2f23b..22aa00b2d7 100644 --- a/src/feature/hs/hs_service.h +++ b/src/feature/hs/hs_service.h @@ -361,7 +361,7 @@ STATIC hs_service_t *get_first_service(void); STATIC hs_service_intro_point_t *service_intro_point_find_by_ident( const hs_service_t *service, const hs_ident_circuit_t *ident); -#endif +#endif /* defined(TOR_UNIT_TESTS) */ /* Service accessors. */ STATIC hs_service_t *find_service(hs_service_ht *map, @@ -369,10 +369,7 @@ STATIC hs_service_t *find_service(hs_service_ht *map, 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, - unsigned int supports_ed25519_link_handshake_any); +STATIC hs_service_intro_point_t *service_intro_point_new(const node_t *node); 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/hs/hs_stats.h b/src/feature/hs/hs_stats.h index d89440faca..6700eca15b 100644 --- a/src/feature/hs/hs_stats.h +++ b/src/feature/hs/hs_stats.h @@ -6,9 +6,13 @@ * \brief Header file for hs_stats.c **/ +#ifndef TOR_HS_STATS_H +#define TOR_HS_STATS_H + void hs_stats_note_introduce2_cell(int is_hsv3); uint32_t hs_stats_get_n_introduce2_v3_cells(void); uint32_t hs_stats_get_n_introduce2_v2_cells(void); void hs_stats_note_service_rendezvous_launch(void); uint32_t hs_stats_get_n_rendezvous_launches(void); +#endif /* !defined(TOR_HS_STATS_H) */ diff --git a/src/feature/hs/hsdir_index_st.h b/src/feature/hs/hsdir_index_st.h index 7d4116d8bb..6c86c02f47 100644 --- a/src/feature/hs/hsdir_index_st.h +++ b/src/feature/hs/hsdir_index_st.h @@ -20,5 +20,5 @@ struct hsdir_index_t { uint8_t store_second[DIGEST256_LEN]; }; -#endif +#endif /* !defined(HSDIR_INDEX_ST_H) */ diff --git a/src/feature/hs_common/shared_random_client.h b/src/feature/hs_common/shared_random_client.h index 95fe2c65ab..c90c52cfea 100644 --- a/src/feature/hs_common/shared_random_client.h +++ b/src/feature/hs_common/shared_random_client.h @@ -44,5 +44,5 @@ time_t get_start_time_of_current_round(void); #endif /* TOR_UNIT_TESTS */ -#endif /* TOR_SHARED_RANDOM_CLIENT_H */ +#endif /* !defined(TOR_SHARED_RANDOM_CLIENT_H) */ diff --git a/src/feature/keymgt/loadkey.h b/src/feature/keymgt/loadkey.h index 8beee57a20..0a5af0b804 100644 --- a/src/feature/keymgt/loadkey.h +++ b/src/feature/keymgt/loadkey.h @@ -52,4 +52,4 @@ int read_encrypted_secret_key(ed25519_secret_key_t *out, int write_encrypted_secret_key(const ed25519_secret_key_t *out, const char *fname); -#endif +#endif /* !defined(TOR_LOADKEY_H) */ diff --git a/src/feature/nodelist/authcert.h b/src/feature/nodelist/authcert.h index 2effdb06e6..071293f9ee 100644 --- a/src/feature/nodelist/authcert.h +++ b/src/feature/nodelist/authcert.h @@ -57,4 +57,4 @@ MOCK_DECL(download_status_t *, download_status_for_authority_id_and_sk, void authcert_free_all(void); -#endif +#endif /* !defined(TOR_AUTHCERT_H) */ diff --git a/src/feature/nodelist/authority_cert_st.h b/src/feature/nodelist/authority_cert_st.h index 68a84bc452..bf9b690c24 100644 --- a/src/feature/nodelist/authority_cert_st.h +++ b/src/feature/nodelist/authority_cert_st.h @@ -28,5 +28,5 @@ struct authority_cert_t { uint16_t dir_port; }; -#endif +#endif /* !defined(AUTHORITY_CERT_ST_H) */ diff --git a/src/feature/nodelist/desc_store_st.h b/src/feature/nodelist/desc_store_st.h index b04a1abc7d..4d1378cdfa 100644 --- a/src/feature/nodelist/desc_store_st.h +++ b/src/feature/nodelist/desc_store_st.h @@ -36,4 +36,4 @@ struct desc_store_t { size_t bytes_dropped; }; -#endif +#endif /* !defined(DESC_STORE_ST_H) */ diff --git a/src/feature/nodelist/describe.h b/src/feature/nodelist/describe.h index 018af6470e..d29192200e 100644 --- a/src/feature/nodelist/describe.h +++ b/src/feature/nodelist/describe.h @@ -22,4 +22,4 @@ const char *node_describe(const struct node_t *node); const char *router_describe(const struct routerinfo_t *ri); const char *routerstatus_describe(const struct routerstatus_t *ri); -#endif +#endif /* !defined(TOR_DESCRIBE_H) */ diff --git a/src/feature/nodelist/dirlist.c b/src/feature/nodelist/dirlist.c index 93baa6e4e0..e2a1d6a9fa 100644 --- a/src/feature/nodelist/dirlist.c +++ b/src/feature/nodelist/dirlist.c @@ -28,7 +28,7 @@ #include "app/config/config.h" #include "core/or/policies.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirauth/authmode.h" #include "feature/dircommon/directory.h" #include "feature/nodelist/dirlist.h" diff --git a/src/feature/nodelist/dirlist.h b/src/feature/nodelist/dirlist.h index 9fabd0a44a..b6dda32d85 100644 --- a/src/feature/nodelist/dirlist.h +++ b/src/feature/nodelist/dirlist.h @@ -44,4 +44,4 @@ void dir_server_add(dir_server_t *ent); void clear_dir_servers(void); void dirlist_free_all(void); -#endif +#endif /* !defined(TOR_DIRLIST_H) */ diff --git a/src/feature/nodelist/document_signature_st.h b/src/feature/nodelist/document_signature_st.h index 66e32c422f..ac2a803252 100644 --- a/src/feature/nodelist/document_signature_st.h +++ b/src/feature/nodelist/document_signature_st.h @@ -25,5 +25,5 @@ struct document_signature_t { * as good. */ }; -#endif +#endif /* !defined(DOCUMENT_SIGNATURE_ST_H) */ diff --git a/src/feature/nodelist/extrainfo_st.h b/src/feature/nodelist/extrainfo_st.h index c54277b05e..22c708f018 100644 --- a/src/feature/nodelist/extrainfo_st.h +++ b/src/feature/nodelist/extrainfo_st.h @@ -26,5 +26,5 @@ struct extrainfo_t { size_t pending_sig_len; }; -#endif +#endif /* !defined(EXTRAINFO_ST_H) */ diff --git a/src/feature/nodelist/fmt_routerstatus.c b/src/feature/nodelist/fmt_routerstatus.c index 8c9212e05c..fea7cf4c65 100644 --- a/src/feature/nodelist/fmt_routerstatus.c +++ b/src/feature/nodelist/fmt_routerstatus.c @@ -14,55 +14,14 @@ #include "core/or/or.h" #include "feature/nodelist/fmt_routerstatus.h" -/* #include "lib/container/buffers.h" */ -/* #include "app/config/config.h" */ -/* #include "app/config/confparse.h" */ -/* #include "core/or/channel.h" */ -/* #include "core/or/channeltls.h" */ -/* #include "core/or/command.h" */ -/* #include "core/mainloop/connection.h" */ -/* #include "core/or/connection_or.h" */ -/* #include "feature/dircache/conscache.h" */ -/* #include "feature/dircache/consdiffmgr.h" */ -/* #include "feature/control/control.h" */ -/* #include "feature/dircache/directory.h" */ -/* #include "feature/dircache/dirserv.h" */ -/* #include "feature/hibernate/hibernate.h" */ -/* #include "feature/dirauth/keypin.h" */ -/* #include "core/mainloop/mainloop.h" */ -/* #include "feature/nodelist/microdesc.h" */ -/* #include "feature/nodelist/networkstatus.h" */ -/* #include "feature/nodelist/nodelist.h" */ #include "core/or/policies.h" -/* #include "core/or/protover.h" */ -/* #include "feature/stats/rephist.h" */ -/* #include "feature/relay/router.h" */ -/* #include "feature/nodelist/dirlist.h" */ #include "feature/nodelist/routerlist.h" - -/* #include "feature/nodelist/routerparse.h" */ -/* #include "feature/nodelist/routerset.h" */ -/* #include "feature/nodelist/torcert.h" */ -/* #include "feature/dircommon/voting_schedule.h" */ - #include "feature/dirauth/dirvote.h" -/* #include "feature/dircache/cached_dir_st.h" */ -/* #include "feature/dircommon/dir_connection_st.h" */ -/* #include "feature/nodelist/extrainfo_st.h" */ -/* #include "feature/nodelist/microdesc_st.h" */ -/* #include "feature/nodelist/node_st.h" */ #include "feature/nodelist/routerinfo_st.h" -/* #include "feature/nodelist/routerlist_st.h" */ -/* #include "core/or/tor_version_st.h" */ #include "feature/nodelist/vote_routerstatus_st.h" -/* #include "lib/compress/compress.h" */ -/* #include "lib/container/order.h" */ #include "lib/crypt_ops/crypto_format.h" -/* #include "lib/encoding/confline.h" */ - -/* #include "lib/encoding/keyval.h" */ /** Helper: write the router-status information in rs into a newly * allocated character buffer. Use the same format as in network-status @@ -233,7 +192,7 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version, } if (format == NS_V3_VOTE && vrs) { - if (tor_mem_is_zero((char*)vrs->ed25519_id, ED25519_PUBKEY_LEN)) { + if (fast_mem_is_zero((char*)vrs->ed25519_id, ED25519_PUBKEY_LEN)) { smartlist_add_strdup(chunks, "id ed25519 none\n"); } else { char ed_b64[BASE64_DIGEST256_LEN+1]; diff --git a/src/feature/nodelist/microdesc.c b/src/feature/nodelist/microdesc.c index 36922561a0..89ac0a2f83 100644 --- a/src/feature/nodelist/microdesc.c +++ b/src/feature/nodelist/microdesc.c @@ -536,8 +536,8 @@ microdesc_cache_reload(microdesc_cache_t *cache) journal_content = read_file_to_str(cache->journal_fname, RFTS_IGNORE_MISSING, &st); if (journal_content) { - cache->journal_len = (size_t) st.st_size; - warn_if_nul_found(journal_content, cache->journal_len, 0, + cache->journal_len = strlen(journal_content); + warn_if_nul_found(journal_content, (size_t)st.st_size, 0, "reading microdesc journal"); added = microdescs_add_to_cache(cache, journal_content, journal_content+st.st_size, @@ -970,7 +970,7 @@ microdesc_list_missing_digest256(networkstatus_t *ns, microdesc_cache_t *cache, continue; if (skip && digest256map_get(skip, (const uint8_t*)rs->descriptor_digest)) continue; - if (tor_mem_is_zero(rs->descriptor_digest, DIGEST256_LEN)) + if (fast_mem_is_zero(rs->descriptor_digest, DIGEST256_LEN)) continue; /* XXXX Also skip if we're a noncache and wouldn't use this router. * XXXX NM Microdesc diff --git a/src/feature/nodelist/microdesc_st.h b/src/feature/nodelist/microdesc_st.h index 367e6a3ef6..c8265cb778 100644 --- a/src/feature/nodelist/microdesc_st.h +++ b/src/feature/nodelist/microdesc_st.h @@ -78,4 +78,4 @@ struct microdesc_t { struct short_policy_t *ipv6_exit_policy; }; -#endif +#endif /* !defined(MICRODESC_ST_H) */ diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index 24e3b212f0..2db293a8af 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -58,7 +58,7 @@ #include "feature/client/bridges.h" #include "feature/client/entrynodes.h" #include "feature/client/transports.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirauth/reachability.h" #include "feature/dircache/consdiffmgr.h" #include "feature/dircache/dirserv.h" @@ -82,6 +82,7 @@ #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" +#include "feature/dirauth/dirauth_periodic.h" #include "feature/dirauth/dirvote.h" #include "feature/dirauth/authmode.h" #include "feature/dirauth/shared_random.h" @@ -1771,7 +1772,7 @@ reload_consensus_from_file(const char *fname, flavor, flags, source_dir); tor_free(content); } -#endif +#endif /* defined(_WIN32) */ if (rv < -1) { log_warn(LD_GENERAL, "Couldn't set consensus from cache file %s", escaped(fname)); @@ -2365,6 +2366,49 @@ networkstatus_getinfo_helper_single(const routerstatus_t *rs) NULL); } +/** + * Extract status information from ri and from other authority + * functions and store it in rs. rs is zeroed out before it is + * set. + * + * We assume that node-\>is_running has already been set, e.g. by + * dirserv_set_router_is_running(ri, now); + */ +void +set_routerstatus_from_routerinfo(routerstatus_t *rs, + const node_t *node, + const routerinfo_t *ri) +{ + memset(rs, 0, sizeof(routerstatus_t)); + + rs->is_authority = + router_digest_is_trusted_dir(ri->cache_info.identity_digest); + + /* Set by compute_performance_thresholds or from consensus */ + rs->is_exit = node->is_exit; + rs->is_stable = node->is_stable; + rs->is_fast = node->is_fast; + rs->is_flagged_running = node->is_running; + rs->is_valid = node->is_valid; + rs->is_possible_guard = node->is_possible_guard; + rs->is_bad_exit = node->is_bad_exit; + rs->is_hs_dir = node->is_hs_dir; + rs->is_named = rs->is_unnamed = 0; + + rs->published_on = ri->cache_info.published_on; + memcpy(rs->identity_digest, node->identity, DIGEST_LEN); + memcpy(rs->descriptor_digest, ri->cache_info.signed_descriptor_digest, + DIGEST_LEN); + rs->addr = ri->addr; + strlcpy(rs->nickname, ri->nickname, sizeof(rs->nickname)); + rs->or_port = ri->or_port; + rs->dir_port = ri->dir_port; + rs->is_v2_dir = ri->supports_tunnelled_dir_requests; + + tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr); + rs->ipv6_orport = ri->ipv6_orport; +} + /** Alloc and return a string describing routerstatuses for the most * recent info of each router we know about that is of purpose * purpose_string. Return NULL if unrecognized purpose. @@ -2381,7 +2425,6 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now) smartlist_t *statuses; const uint8_t purpose = router_purpose_from_string(purpose_string); routerstatus_t rs; - const int bridge_auth = authdir_mode_bridge(get_options()); if (purpose == ROUTER_PURPOSE_UNKNOWN) { log_info(LD_DIR, "Unrecognized purpose '%s' when listing router statuses.", @@ -2398,11 +2441,7 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now) continue; if (ri->purpose != purpose) continue; - /* TODO: modifying the running flag in a getinfo is a bad idea */ - if (bridge_auth && ri->purpose == ROUTER_PURPOSE_BRIDGE) - dirserv_set_router_is_running(ri, now); - /* then generate and write out status lines for each of them */ - set_routerstatus_from_routerinfo(&rs, node, ri, now, 0); + set_routerstatus_from_routerinfo(&rs, node, ri); smartlist_add(statuses, networkstatus_getinfo_helper_single(&rs)); } SMARTLIST_FOREACH_END(ri); @@ -2412,43 +2451,6 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now) return answer; } -/** Write out router status entries for all our bridge descriptors. */ -void -networkstatus_dump_bridge_status_to_file(time_t now) -{ - char *status = networkstatus_getinfo_by_purpose("bridge", now); - char *fname = NULL; - char *thresholds = NULL; - char *published_thresholds_and_status = NULL; - char published[ISO_TIME_LEN+1]; - const routerinfo_t *me = router_get_my_routerinfo(); - char fingerprint[FINGERPRINT_LEN+1]; - char *fingerprint_line = NULL; - - if (me && crypto_pk_get_fingerprint(me->identity_pkey, - fingerprint, 0) >= 0) { - tor_asprintf(&fingerprint_line, "fingerprint %s\n", fingerprint); - } else { - log_warn(LD_BUG, "Error computing fingerprint for bridge status."); - } - format_iso_time(published, now); - dirserv_compute_bridge_flag_thresholds(); - thresholds = dirserv_get_flag_thresholds_line(); - tor_asprintf(&published_thresholds_and_status, - "published %s\nflag-thresholds %s\n%s%s", - published, thresholds, fingerprint_line ? fingerprint_line : "", - status); - fname = get_datadir_fname("networkstatus-bridges"); - if (write_str_to_file(fname,published_thresholds_and_status,0)<0) { - log_warn(LD_DIRSERV, "Unable to write networkstatus-bridges file."); - } - tor_free(thresholds); - tor_free(published_thresholds_and_status); - tor_free(fname); - tor_free(status); - tor_free(fingerprint_line); -} - /* DOCDOC get_net_param_from_list */ static int32_t get_net_param_from_list(smartlist_t *net_params, const char *param_name, diff --git a/src/feature/nodelist/networkstatus.h b/src/feature/nodelist/networkstatus.h index 8269fc6182..600fd7fbd5 100644 --- a/src/feature/nodelist/networkstatus.h +++ b/src/feature/nodelist/networkstatus.h @@ -122,7 +122,6 @@ void signed_descs_update_status_from_consensus_networkstatus( char *networkstatus_getinfo_helper_single(const routerstatus_t *rs); char *networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now); -void networkstatus_dump_bridge_status_to_file(time_t now); MOCK_DECL(int32_t, networkstatus_get_param, (const networkstatus_t *ns, const char *param_name, int32_t default_val, int32_t min_val, int32_t max_val)); @@ -149,6 +148,10 @@ void vote_routerstatus_free_(vote_routerstatus_t *rs); #define vote_routerstatus_free(rs) \ FREE_AND_NULL(vote_routerstatus_t, vote_routerstatus_free_, (rs)) +void set_routerstatus_from_routerinfo(routerstatus_t *rs, + const node_t *node, + const routerinfo_t *ri); + #ifdef NETWORKSTATUS_PRIVATE #ifdef TOR_UNIT_TESTS STATIC int networkstatus_set_current_consensus_from_ns(networkstatus_t *c, diff --git a/src/feature/nodelist/networkstatus_sr_info_st.h b/src/feature/nodelist/networkstatus_sr_info_st.h index 677d8ed811..420c3d61e4 100644 --- a/src/feature/nodelist/networkstatus_sr_info_st.h +++ b/src/feature/nodelist/networkstatus_sr_info_st.h @@ -19,5 +19,5 @@ struct networkstatus_sr_info_t { smartlist_t *commits; }; -#endif +#endif /* !defined(NETWORKSTATUS_SR_INFO_ST_H) */ diff --git a/src/feature/nodelist/networkstatus_st.h b/src/feature/nodelist/networkstatus_st.h index 5c1eea3259..6e84c170d6 100644 --- a/src/feature/nodelist/networkstatus_st.h +++ b/src/feature/nodelist/networkstatus_st.h @@ -104,4 +104,4 @@ struct networkstatus_t { uint8_t bw_file_digest256[DIGEST256_LEN]; }; -#endif +#endif /* !defined(NETWORKSTATUS_ST_H) */ diff --git a/src/feature/nodelist/networkstatus_voter_info_st.h b/src/feature/nodelist/networkstatus_voter_info_st.h index 4037fcdeca..66af82a8e3 100644 --- a/src/feature/nodelist/networkstatus_voter_info_st.h +++ b/src/feature/nodelist/networkstatus_voter_info_st.h @@ -27,4 +27,4 @@ struct networkstatus_voter_info_t { smartlist_t *sigs; }; -#endif +#endif /* !defined(NETWORKSTATUS_VOTER_INFO_ST_H) */ diff --git a/src/feature/nodelist/nickname.h b/src/feature/nodelist/nickname.h index 9bdc6b50e8..78db2a5f91 100644 --- a/src/feature/nodelist/nickname.h +++ b/src/feature/nodelist/nickname.h @@ -16,4 +16,4 @@ int is_legal_nickname(const char *s); int is_legal_nickname_or_hexdigest(const char *s); int is_legal_hexdigest(const char *s); -#endif +#endif /* !defined(TOR_NICKNAME_H) */ diff --git a/src/feature/nodelist/node_select.c b/src/feature/nodelist/node_select.c index e31abb247f..719b4b1b27 100644 --- a/src/feature/nodelist/node_select.c +++ b/src/feature/nodelist/node_select.c @@ -30,6 +30,7 @@ #include "feature/nodelist/routerset.h" #include "feature/relay/router.h" #include "feature/relay/routermode.h" +#include "lib/container/bitarray.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/math/fp.h" @@ -585,6 +586,7 @@ compute_weighted_bandwidths(const smartlist_t *sl, } weight_scale = networkstatus_get_weight_scale_param(NULL); + tor_assert(weight_scale >= 1); if (rule == WEIGHT_FOR_GUARD) { Wg = networkstatus_get_bw_weight(NULL, "Wgg", -1); @@ -825,6 +827,58 @@ routerlist_add_node_and_family(smartlist_t *sl, const routerinfo_t *router) nodelist_add_node_and_family(sl, node); } +/** + * Remove every node_t that appears in excluded from sl. + * + * Behaves like smartlist_subtract, but uses nodelist_idx values to deliver + * linear performance when smartlist_subtract would be quadratic. + **/ +static void +nodelist_subtract(smartlist_t *sl, const smartlist_t *excluded) +{ + const smartlist_t *nodelist = nodelist_get_list(); + const int nodelist_len = smartlist_len(nodelist); + bitarray_t *excluded_idx = bitarray_init_zero(nodelist_len); + + /* We haven't used nodelist_idx in this way previously, so I'm going to be + * paranoid in this code, and check that nodelist_idx is correct for every + * node before we use it. If we fail, we fall back to smartlist_subtract(). + */ + + /* Set the excluded_idx bit corresponding to every excluded node... + */ + SMARTLIST_FOREACH_BEGIN(excluded, const node_t *, node) { + const int idx = node->nodelist_idx; + if (BUG(idx < 0) || BUG(idx >= nodelist_len) || + BUG(node != smartlist_get(nodelist, idx))) { + goto internal_error; + } + bitarray_set(excluded_idx, idx); + } SMARTLIST_FOREACH_END(node); + + /* Then remove them from sl. + */ + SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) { + const int idx = node->nodelist_idx; + if (BUG(idx < 0) || BUG(idx >= nodelist_len) || + BUG(node != smartlist_get(nodelist, idx))) { + goto internal_error; + } + if (bitarray_is_set(excluded_idx, idx)) { + SMARTLIST_DEL_CURRENT(sl, node); + } + } SMARTLIST_FOREACH_END(node); + + bitarray_free(excluded_idx); + return; + + internal_error: + log_warn(LD_BUG, "Internal error prevented us from using the fast method " + "for subtracting nodelists. Falling back to the quadratic way."); + smartlist_subtract(sl, excluded); + bitarray_free(excluded_idx); +} + /** Return a random running node from the nodelist. Never * pick a node that is in * excludedsmartlist, or which matches excludedset, @@ -859,6 +913,7 @@ router_choose_random_node(smartlist_t *excludedsmartlist, const int direct_conn = (flags & CRN_DIRECT_CONN) != 0; const int rendezvous_v3 = (flags & CRN_RENDEZVOUS_V3) != 0; + const smartlist_t *node_list = nodelist_get_list(); smartlist_t *sl=smartlist_new(), *excludednodes=smartlist_new(); const node_t *choice = NULL; @@ -869,17 +924,17 @@ router_choose_random_node(smartlist_t *excludedsmartlist, rule = weight_for_exit ? WEIGHT_FOR_EXIT : (need_guard ? WEIGHT_FOR_GUARD : WEIGHT_FOR_MID); - SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) { + SMARTLIST_FOREACH_BEGIN(node_list, const node_t *, node) { if (node_allows_single_hop_exits(node)) { /* Exclude relays that allow single hop exit circuits. This is an * obsolete option since 0.2.9.2-alpha and done by default in * 0.3.1.0-alpha. */ - smartlist_add(excludednodes, node); + smartlist_add(excludednodes, (node_t*)node); } else if (rendezvous_v3 && !node_supports_v3_rendezvous_point(node)) { /* Exclude relays that do not support to rendezvous for a hidden service * version 3. */ - smartlist_add(excludednodes, node); + smartlist_add(excludednodes, (node_t*)node); } } SMARTLIST_FOREACH_END(node); @@ -896,19 +951,11 @@ router_choose_random_node(smartlist_t *excludedsmartlist, "We found %d running nodes.", smartlist_len(sl)); - smartlist_subtract(sl,excludednodes); - log_debug(LD_CIRC, - "We removed %d excludednodes, leaving %d nodes.", - smartlist_len(excludednodes), - smartlist_len(sl)); - if (excludedsmartlist) { - smartlist_subtract(sl,excludedsmartlist); - log_debug(LD_CIRC, - "We removed %d excludedsmartlist, leaving %d nodes.", - smartlist_len(excludedsmartlist), - smartlist_len(sl)); + smartlist_add_all(excludednodes, excludedsmartlist); } + nodelist_subtract(sl, excludednodes); + if (excludedset) { routerset_subtract_nodes(sl,excludedset); log_debug(LD_CIRC, diff --git a/src/feature/nodelist/node_select.h b/src/feature/nodelist/node_select.h index ed7450b92c..d8b4aca5c1 100644 --- a/src/feature/nodelist/node_select.h +++ b/src/feature/nodelist/node_select.h @@ -97,6 +97,6 @@ STATIC const routerstatus_t *router_pick_directory_server_impl( int *n_busy_out); STATIC int router_is_already_dir_fetching(const tor_addr_port_t *ap, int serverdesc, int microdesc); -#endif +#endif /* defined(NODE_SELECT_PRIVATE) */ -#endif +#endif /* !defined(TOR_NODE_SELECT_H) */ diff --git a/src/feature/nodelist/node_st.h b/src/feature/nodelist/node_st.h index 53ffde29e4..c63a535a19 100644 --- a/src/feature/nodelist/node_st.h +++ b/src/feature/nodelist/node_st.h @@ -99,4 +99,4 @@ struct node_t { struct hsdir_index_t hsdir_index; }; -#endif +#endif /* !defined(NODE_ST_H) */ diff --git a/src/feature/nodelist/nodefamily.h b/src/feature/nodelist/nodefamily.h index bc5dafce03..31b71e77a0 100644 --- a/src/feature/nodelist/nodefamily.h +++ b/src/feature/nodelist/nodefamily.h @@ -47,4 +47,4 @@ char *nodefamily_canonicalize(const char *s, const uint8_t *rsa_id_self, void nodefamily_free_all(void); -#endif +#endif /* !defined(TOR_NODEFAMILY_H) */ diff --git a/src/feature/nodelist/nodefamily_st.h b/src/feature/nodelist/nodefamily_st.h index be533da824..20390c9308 100644 --- a/src/feature/nodelist/nodefamily_st.h +++ b/src/feature/nodelist/nodefamily_st.h @@ -45,4 +45,4 @@ struct nodefamily_t { #define NODEFAMILY_MEMBER_PTR(nf, i) \ (&((nf)->family_members[(i) * NODEFAMILY_MEMBER_LEN])) -#endif +#endif /* !defined(TOR_NODEFAMILY_ST_H) */ diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c index 8b02dd9c66..21914c6c6d 100644 --- a/src/feature/nodelist/nodelist.c +++ b/src/feature/nodelist/nodelist.c @@ -49,7 +49,7 @@ #include "core/or/protover.h" #include "feature/client/bridges.h" #include "feature/client/entrynodes.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirauth/process_descs.h" #include "feature/dircache/dirserv.h" #include "feature/hs/hs_client.h" @@ -944,7 +944,7 @@ nodelist_ensure_freshness(networkstatus_t *ns) /** Return a list of a node_t * for every node we know about. The caller * MUST NOT modify the list. (You can set and clear flags in the nodes if * you must, but you must not add or remove nodes.) */ -MOCK_IMPL(smartlist_t *, +MOCK_IMPL(const smartlist_t *, nodelist_get_list,(void)) { init_nodelist(); @@ -1189,6 +1189,102 @@ node_get_rsa_id_digest(const node_t *node) return (const uint8_t*)node->identity; } +/* Returns a new smartlist with all possible link specifiers from node: + * - 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, and: + * - if direct_conn is true, its link versions are compatible with us, + * - if direct_conn is false, regardless of its link versions; + * - 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. + * + * If node is NULL, returns an empty smartlist. + * + * The smartlist must be freed using link_specifier_smartlist_free(). */ +smartlist_t * +node_get_link_specifier_smartlist(const node_t *node, bool direct_conn) +{ + link_specifier_t *ls; + tor_addr_port_t ap; + smartlist_t *lspecs = smartlist_new(); + + if (!node) + return lspecs; + + /* Get the relay's IPv4 address. */ + node_get_prim_orport(node, &ap); + + /* We expect the node's primary address to be a valid IPv4 address. + * This conforms to the protocol, which requires either an IPv4 or IPv6 + * address (or both). */ + if (BUG(!tor_addr_is_v4(&ap.addr)) || + BUG(!tor_addr_port_is_valid_ap(&ap, 0))) { + return lspecs; + } + + ls = link_specifier_new(); + link_specifier_set_ls_type(ls, LS_IPV4); + link_specifier_set_un_ipv4_addr(ls, tor_addr_to_ipv4h(&ap.addr)); + link_specifier_set_un_ipv4_port(ls, ap.port); + /* Four bytes IPv4 and two bytes port. */ + link_specifier_set_ls_len(ls, sizeof(ap.addr.addr.in_addr) + + sizeof(ap.port)); + smartlist_add(lspecs, ls); + + /* Legacy ID is mandatory and will always be present in node. */ + ls = link_specifier_new(); + link_specifier_set_ls_type(ls, LS_LEGACY_ID); + memcpy(link_specifier_getarray_un_legacy_id(ls), node->identity, + link_specifier_getlen_un_legacy_id(ls)); + 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, and the node declares a + protocol version that supports ed25519 link authentication. + If direct_conn is true, we also require that the node's link version is + compatible with us. (Otherwise, we will be 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, direct_conn)) { + ls = link_specifier_new(); + link_specifier_set_ls_type(ls, LS_ED25519_ID); + memcpy(link_specifier_getarray_un_ed25519_id(ls), &node->ed25519_id, + link_specifier_getlen_un_ed25519_id(ls)); + link_specifier_set_ls_len(ls, link_specifier_getlen_un_ed25519_id(ls)); + smartlist_add(lspecs, ls); + } + + /* Check for IPv6. If so, include it as well. */ + if (node_has_ipv6_orport(node)) { + ls = link_specifier_new(); + node_get_pref_ipv6_orport(node, &ap); + link_specifier_set_ls_type(ls, LS_IPV6); + size_t addr_len = link_specifier_getlen_un_ipv6_addr(ls); + const uint8_t *in6_addr = tor_addr_to_in6_addr8(&ap.addr); + uint8_t *ipv6_array = link_specifier_getarray_un_ipv6_addr(ls); + memcpy(ipv6_array, in6_addr, addr_len); + link_specifier_set_un_ipv6_port(ls, ap.port); + /* Sixteen bytes IPv6 and two bytes port. */ + link_specifier_set_ls_len(ls, addr_len + sizeof(ap.port)); + smartlist_add(lspecs, ls); + } + + return lspecs; +} + +/* Free a link specifier list. */ +void +link_specifier_smartlist_free_(smartlist_t *ls_list) +{ + if (!ls_list) + return; + + SMARTLIST_FOREACH(ls_list, link_specifier_t *, lspec, + link_specifier_free(lspec)); + smartlist_free(ls_list); +} + /** Return the nickname of node, or NULL if we can't find one. */ const char * node_get_nickname(const node_t *node) @@ -1763,7 +1859,7 @@ microdesc_has_curve25519_onion_key(const microdesc_t *md) return 0; } - if (tor_mem_is_zero((const char*)md->onion_curve25519_pkey->public_key, + if (fast_mem_is_zero((const char*)md->onion_curve25519_pkey->public_key, CURVE25519_PUBKEY_LEN)) { return 0; } @@ -1843,7 +1939,7 @@ node_set_country(node_t *node) void nodelist_refresh_countries(void) { - smartlist_t *nodes = nodelist_get_list(); + const smartlist_t *nodes = nodelist_get_list(); SMARTLIST_FOREACH(nodes, node_t *, node, node_set_country(node)); } diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h index 3420959618..84ab5f7a54 100644 --- a/src/feature/nodelist/nodelist.h +++ b/src/feature/nodelist/nodelist.h @@ -77,6 +77,11 @@ int node_supports_v3_hsdir(const node_t *node); int node_supports_ed25519_hs_intro(const node_t *node); int node_supports_v3_rendezvous_point(const node_t *node); const uint8_t *node_get_rsa_id_digest(const node_t *node); +smartlist_t *node_get_link_specifier_smartlist(const node_t *node, + bool direct_conn); +void link_specifier_smartlist_free_(smartlist_t *ls_list); +#define link_specifier_smartlist_free(ls_list) \ + FREE_AND_NULL(smartlist_t, link_specifier_smartlist_free_, (ls_list)) int node_has_ipv6_addr(const node_t *node); int node_has_ipv6_orport(const node_t *node); @@ -96,7 +101,7 @@ const struct curve25519_public_key_t *node_get_curve25519_onion_key( const node_t *node); crypto_pk_t *node_get_rsa_onion_key(const node_t *node); -MOCK_DECL(smartlist_t *, nodelist_get_list, (void)); +MOCK_DECL(const smartlist_t *, nodelist_get_list, (void)); /* Temporary during transition to multiple addresses. */ void node_get_addr(const node_t *node, tor_addr_t *addr_out); diff --git a/src/feature/nodelist/routerinfo.h b/src/feature/nodelist/routerinfo.h index bfa28c7754..ca66e660b3 100644 --- a/src/feature/nodelist/routerinfo.h +++ b/src/feature/nodelist/routerinfo.h @@ -24,4 +24,4 @@ smartlist_t *router_get_all_orports(const routerinfo_t *ri); const char *router_purpose_to_string(uint8_t p); uint8_t router_purpose_from_string(const char *s); -#endif +#endif /* !defined(TOR_ROUTERINFO_H) */ diff --git a/src/feature/nodelist/routerinfo_st.h b/src/feature/nodelist/routerinfo_st.h index 59656818c1..59fd56d0a0 100644 --- a/src/feature/nodelist/routerinfo_st.h +++ b/src/feature/nodelist/routerinfo_st.h @@ -112,4 +112,4 @@ struct routerinfo_t { uint8_t purpose; }; -#endif +#endif /* !defined(ROUTERINFO_ST_H) */ diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c index d1220f553a..c56b714cb0 100644 --- a/src/feature/nodelist/routerlist.c +++ b/src/feature/nodelist/routerlist.c @@ -67,7 +67,7 @@ #include "core/mainloop/mainloop.h" #include "core/or/policies.h" #include "feature/client/bridges.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirauth/authmode.h" #include "feature/dirauth/process_descs.h" #include "feature/dirauth/reachability.h" @@ -954,20 +954,18 @@ routerlist_free_(routerlist_t *rl) smartlist_free(rl->routers); smartlist_free(rl->old_routers); if (rl->desc_store.mmap) { - int res = tor_munmap_file(routerlist->desc_store.mmap); + int res = tor_munmap_file(rl->desc_store.mmap); if (res != 0) { log_warn(LD_FS, "Failed to munmap routerlist->desc_store.mmap"); } } if (rl->extrainfo_store.mmap) { - int res = tor_munmap_file(routerlist->extrainfo_store.mmap); + int res = tor_munmap_file(rl->extrainfo_store.mmap); if (res != 0) { log_warn(LD_FS, "Failed to munmap routerlist->extrainfo_store.mmap"); } } tor_free(rl); - - router_dir_info_changed(); } /** Log information about how much memory is being used for routerlist, @@ -1426,8 +1424,10 @@ routerlist_reparse_old(routerlist_t *rl, signed_descriptor_t *sd) void routerlist_free_all(void) { - routerlist_free(routerlist); - routerlist = NULL; + routerlist_t *rl = routerlist; + routerlist = NULL; // Prevent internals of routerlist_free() from using + // routerlist. + routerlist_free(rl); dirlist_free_all(); if (warned_nicknames) { SMARTLIST_FOREACH(warned_nicknames, char *, cp, tor_free(cp)); @@ -1926,6 +1926,8 @@ routerlist_remove_old_routers(void) void routerlist_descriptors_added(smartlist_t *sl, int from_cache) { + // XXXX use pubsub mechanism here. + tor_assert(sl); control_event_descriptors_changed(sl); SMARTLIST_FOREACH_BEGIN(sl, routerinfo_t *, ri) { @@ -1933,7 +1935,9 @@ routerlist_descriptors_added(smartlist_t *sl, int from_cache) learned_bridge_descriptor(ri, from_cache); if (ri->needs_retest_if_added) { ri->needs_retest_if_added = 0; +#ifdef HAVE_MODULE_DIRAUTH dirserv_single_reachability_test(approx_time(), ri); +#endif } } SMARTLIST_FOREACH_END(ri); } @@ -2856,7 +2860,7 @@ int router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2) { time_t r1pub, r2pub; - long time_difference; + time_t time_difference; tor_assert(r1 && r2); /* r1 should be the one that was published first. */ @@ -2920,7 +2924,9 @@ router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2) * give or take some slop? */ r1pub = r1->cache_info.published_on; r2pub = r2->cache_info.published_on; - time_difference = labs(r2->uptime - (r1->uptime + (r2pub - r1pub))); + time_difference = r2->uptime - (r1->uptime + (r2pub - r1pub)); + if (time_difference < 0) + time_difference = - time_difference; if (time_difference > ROUTER_ALLOW_UPTIME_DRIFT && time_difference > r1->uptime * .05 && time_difference > r2->uptime * .05) @@ -2969,7 +2975,7 @@ routerinfo_incompatible_with_extrainfo(const crypto_pk_t *identity_pkey, digest256_matches = tor_memeq(ei->digest256, sd->extra_info_digest256, DIGEST256_LEN); digest256_matches |= - tor_mem_is_zero(sd->extra_info_digest256, DIGEST256_LEN); + fast_mem_is_zero(sd->extra_info_digest256, DIGEST256_LEN); /* The identity must match exactly to have been generated at the same time * by the same router. */ @@ -3053,7 +3059,7 @@ routerinfo_has_curve25519_onion_key(const routerinfo_t *ri) return 0; } - if (tor_mem_is_zero((const char*)ri->onion_curve25519_pkey->public_key, + if (fast_mem_is_zero((const char*)ri->onion_curve25519_pkey->public_key, CURVE25519_PUBKEY_LEN)) { return 0; } diff --git a/src/feature/nodelist/routerlist_st.h b/src/feature/nodelist/routerlist_st.h index 7446ead3cb..10b919a1bf 100644 --- a/src/feature/nodelist/routerlist_st.h +++ b/src/feature/nodelist/routerlist_st.h @@ -36,5 +36,5 @@ struct routerlist_t { desc_store_t extrainfo_store; }; -#endif +#endif /* !defined(ROUTERLIST_ST_H) */ diff --git a/src/feature/nodelist/routerset.c b/src/feature/nodelist/routerset.c index 55e2756959..e801fd81b1 100644 --- a/src/feature/nodelist/routerset.c +++ b/src/feature/nodelist/routerset.c @@ -378,7 +378,7 @@ routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset, } else { /* We need to iterate over the routerlist to get all the ones of the * right kind. */ - smartlist_t *nodes = nodelist_get_list(); + const smartlist_t *nodes = nodelist_get_list(); SMARTLIST_FOREACH(nodes, const node_t *, node, { if (running_only && !node->is_running) continue; diff --git a/src/feature/nodelist/routerstatus_st.h b/src/feature/nodelist/routerstatus_st.h index 8d91b45e11..46337c9e52 100644 --- a/src/feature/nodelist/routerstatus_st.h +++ b/src/feature/nodelist/routerstatus_st.h @@ -78,5 +78,5 @@ struct routerstatus_t { }; -#endif +#endif /* !defined(ROUTERSTATUS_ST_H) */ diff --git a/src/feature/nodelist/signed_descriptor_st.h b/src/feature/nodelist/signed_descriptor_st.h index bdcebf184a..64c28f7440 100644 --- a/src/feature/nodelist/signed_descriptor_st.h +++ b/src/feature/nodelist/signed_descriptor_st.h @@ -57,5 +57,5 @@ struct signed_descriptor_t { unsigned int send_unencrypted : 1; }; -#endif +#endif /* !defined(SIGNED_DESCRIPTOR_ST_H) */ diff --git a/src/feature/nodelist/torcert.c b/src/feature/nodelist/torcert.c index b0197e9f13..270c14eb1c 100644 --- a/src/feature/nodelist/torcert.c +++ b/src/feature/nodelist/torcert.c @@ -74,7 +74,7 @@ tor_cert_sign_impl(const ed25519_keypair_t *signing_key, tor_assert(real_len == alloc_len); tor_assert(real_len > ED25519_SIG_LEN); uint8_t *sig = encoded + (real_len - ED25519_SIG_LEN); - tor_assert(tor_mem_is_zero((char*)sig, ED25519_SIG_LEN)); + tor_assert(fast_mem_is_zero((char*)sig, ED25519_SIG_LEN)); ed25519_signature_t signature; if (ed25519_sign(&signature, encoded, @@ -290,8 +290,8 @@ tor_cert_describe_signature_status(const tor_cert_t *cert) } /** Return a new copy of cert */ -tor_cert_t * -tor_cert_dup(const tor_cert_t *cert) +MOCK_IMPL(tor_cert_t *, +tor_cert_dup,(const tor_cert_t *cert)) { tor_cert_t *newcert = tor_memdup(cert, sizeof(tor_cert_t)); if (cert->encoded) diff --git a/src/feature/nodelist/torcert.h b/src/feature/nodelist/torcert.h index 492275b514..03d5bdca93 100644 --- a/src/feature/nodelist/torcert.h +++ b/src/feature/nodelist/torcert.h @@ -71,7 +71,7 @@ int tor_cert_checksig(tor_cert_t *cert, const ed25519_public_key_t *pubkey, time_t now); const char *tor_cert_describe_signature_status(const tor_cert_t *cert); -tor_cert_t *tor_cert_dup(const tor_cert_t *cert); +MOCK_DECL(tor_cert_t *,tor_cert_dup,(const tor_cert_t *cert)); int tor_cert_eq(const tor_cert_t *cert1, const tor_cert_t *cert2); int tor_cert_opt_eq(const tor_cert_t *cert1, const tor_cert_t *cert2); diff --git a/src/feature/nodelist/vote_routerstatus_st.h b/src/feature/nodelist/vote_routerstatus_st.h index 366754c166..0d909da260 100644 --- a/src/feature/nodelist/vote_routerstatus_st.h +++ b/src/feature/nodelist/vote_routerstatus_st.h @@ -38,4 +38,4 @@ struct vote_routerstatus_t { uint8_t ed25519_id[ED25519_PUBKEY_LEN]; }; -#endif +#endif /* !defined(VOTE_ROUTERSTATUS_ST_H) */ diff --git a/src/feature/relay/dns.c b/src/feature/relay/dns.c index fa0a1b5910..05b97e0ae2 100644 --- a/src/feature/relay/dns.c +++ b/src/feature/relay/dns.c @@ -59,7 +59,7 @@ #include "core/or/connection_edge.h" #include "core/or/policies.h" #include "core/or/relay.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/relay/dns.h" #include "feature/relay/router.h" #include "feature/relay/routermode.h" @@ -1394,7 +1394,7 @@ configured_nameserver_address(const size_t idx) return NULL; } -#endif +#endif /* defined(HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR) */ /** Configure eventdns nameservers if force is true, or if the configuration * has changed since the last time we called this function, or if we failed on @@ -2187,7 +2187,8 @@ dns_cache_handle_oom(time_t now, size_t min_remove_bytes) current_size -= bytes_removed; total_bytes_removed += bytes_removed; - time_inc += 3600; /* Increase time_inc by 1 hour. */ + /* Increase time_inc by a reasonable fraction. */ + time_inc += (MAX_DNS_TTL_AT_EXIT / 4); } while (total_bytes_removed < min_remove_bytes); return total_bytes_removed; diff --git a/src/feature/relay/ext_orport.c b/src/feature/relay/ext_orport.c index 8589efb48d..c343d19b8d 100644 --- a/src/feature/relay/ext_orport.c +++ b/src/feature/relay/ext_orport.c @@ -20,7 +20,7 @@ #include "core/or/or.h" #include "core/mainloop/connection.h" #include "core/or/connection_or.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "app/config/config.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" @@ -659,4 +659,3 @@ ext_orport_free_all(void) if (ext_or_auth_cookie) /* Free the auth cookie */ tor_free(ext_or_auth_cookie); } - diff --git a/src/feature/relay/onion_queue.c b/src/feature/relay/onion_queue.c index 696905cf5e..c37745cf33 100644 --- a/src/feature/relay/onion_queue.c +++ b/src/feature/relay/onion_queue.c @@ -212,10 +212,12 @@ num_ntors_per_tap(void) #define MIN_NUM_NTORS_PER_TAP 1 #define MAX_NUM_NTORS_PER_TAP 100000 - return networkstatus_get_param(NULL, "NumNTorsPerTAP", - DEFAULT_NUM_NTORS_PER_TAP, - MIN_NUM_NTORS_PER_TAP, - MAX_NUM_NTORS_PER_TAP); + int result = networkstatus_get_param(NULL, "NumNTorsPerTAP", + DEFAULT_NUM_NTORS_PER_TAP, + MIN_NUM_NTORS_PER_TAP, + MAX_NUM_NTORS_PER_TAP); + tor_assert(result > 0); + return result; } /** Choose which onion queue we'll pull from next. If one is empty choose diff --git a/src/feature/relay/onion_queue.h b/src/feature/relay/onion_queue.h index 0df921e057..cf478bc1a0 100644 --- a/src/feature/relay/onion_queue.h +++ b/src/feature/relay/onion_queue.h @@ -20,4 +20,4 @@ int onion_num_pending(uint16_t handshake_type); void onion_pending_remove(or_circuit_t *circ); void clear_pending_onions(void); -#endif +#endif /* !defined(TOR_ONION_QUEUE_H) */ diff --git a/src/feature/relay/relay_periodic.c b/src/feature/relay/relay_periodic.c new file mode 100644 index 0000000000..b48b495895 --- /dev/null +++ b/src/feature/relay/relay_periodic.c @@ -0,0 +1,308 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_periodic.c + * @brief Periodic functions for the relay subsytem + **/ + +#include "orconfig.h" +#include "core/or/or.h" + +#include "core/mainloop/periodic.h" +#include "core/mainloop/cpuworker.h" // XXXX use a pubsub event. +#include "core/mainloop/mainloop.h" +#include "core/mainloop/netstatus.h" +#include "core/or/circuituse.h" // XXXX move have_performed_bandwidth_test + +#include "feature/relay/dns.h" +#include "feature/relay/relay_periodic.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "feature/relay/routermode.h" +#include "feature/relay/selftest.h" +#include "feature/stats/predict_ports.h" + +#include "lib/crypt_ops/crypto_rand.h" + +#include "feature/nodelist/routerinfo_st.h" +#include "feature/control/control_events.h" + +#define DECLARE_EVENT(name, roles, flags) \ + static periodic_event_item_t name ## _event = \ + PERIODIC_EVENT(name, \ + PERIODIC_EVENT_ROLE_##roles, \ + flags) + +#define FL(name) (PERIODIC_EVENT_FLAG_##name) + +/** + * Periodic callback: If we're a server and initializing dns failed, retry. + */ +static int +retry_dns_callback(time_t now, const or_options_t *options) +{ + (void)now; +#define RETRY_DNS_INTERVAL (10*60) + if (server_mode(options) && has_dns_init_failed()) + dns_init(); + return RETRY_DNS_INTERVAL; +} + +DECLARE_EVENT(retry_dns, ROUTER, 0); + +static int dns_honesty_first_time = 1; + +/** + * Periodic event: if we're an exit, see if our DNS server is telling us + * obvious lies. + */ +static int +check_dns_honesty_callback(time_t now, const or_options_t *options) +{ + (void)now; + /* 9. and if we're an exit node, check whether our DNS is telling stories + * to us. */ + if (net_is_disabled() || + ! public_server_mode(options) || + router_my_exit_policy_is_reject_star()) + return PERIODIC_EVENT_NO_UPDATE; + + if (dns_honesty_first_time) { + /* Don't launch right when we start */ + dns_honesty_first_time = 0; + return crypto_rand_int_range(60, 180); + } + + dns_launch_correctness_checks(); + return 12*3600 + crypto_rand_int(12*3600); +} + +DECLARE_EVENT(check_dns_honesty, RELAY, FL(NEED_NET)); + +/* Periodic callback: rotate the onion keys after the period defined by the + * "onion-key-rotation-days" consensus parameter, shut down and restart all + * cpuworkers, and update our descriptor if necessary. + */ +static int +rotate_onion_key_callback(time_t now, const or_options_t *options) +{ + if (server_mode(options)) { + int onion_key_lifetime = get_onion_key_lifetime(); + time_t rotation_time = get_onion_key_set_at()+onion_key_lifetime; + if (rotation_time > now) { + return ONION_KEY_CONSENSUS_CHECK_INTERVAL; + } + + log_info(LD_GENERAL,"Rotating onion key."); + rotate_onion_key(); + cpuworkers_rotate_keyinfo(); + if (router_rebuild_descriptor(1)<0) { + log_info(LD_CONFIG, "Couldn't rebuild router descriptor"); + } + if (advertised_server_mode() && !net_is_disabled()) + router_upload_dir_desc_to_dirservers(0); + return ONION_KEY_CONSENSUS_CHECK_INTERVAL; + } + return PERIODIC_EVENT_NO_UPDATE; +} + +DECLARE_EVENT(rotate_onion_key, ROUTER, 0); + +/** Periodic callback: consider rebuilding or and re-uploading our descriptor + * (if we've passed our internal checks). */ +static int +check_descriptor_callback(time_t now, const or_options_t *options) +{ +/** How often do we check whether part of our router info has changed in a + * way that would require an upload? That includes checking whether our IP + * address has changed. */ +#define CHECK_DESCRIPTOR_INTERVAL (60) + + (void)options; + + /* 2b. Once per minute, regenerate and upload the descriptor if the old + * one is inaccurate. */ + if (!net_is_disabled()) { + check_descriptor_bandwidth_changed(now); + check_descriptor_ipaddress_changed(now); + mark_my_descriptor_dirty_if_too_old(now); + consider_publishable_server(0); + } + + return CHECK_DESCRIPTOR_INTERVAL; +} + +DECLARE_EVENT(check_descriptor, ROUTER, FL(NEED_NET)); + +static int dirport_reachability_count = 0; + +/** + * Periodic callback: check whether we're reachable (as a relay), and + * whether our bandwidth has changed enough that we need to + * publish a new descriptor. + */ +static int +check_for_reachability_bw_callback(time_t now, const or_options_t *options) +{ + /* XXXX This whole thing was stuck in the middle of what is now + * XXXX check_descriptor_callback. I'm not sure it's right. */ + + /* also, check religiously for reachability, if it's within the first + * 20 minutes of our uptime. */ + if (server_mode(options) && + (have_completed_a_circuit() || !any_predicted_circuits(now)) && + !net_is_disabled()) { + if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { + router_do_reachability_checks(1, dirport_reachability_count==0); + if (++dirport_reachability_count > 5) + dirport_reachability_count = 0; + return 1; + } else { + /* If we haven't checked for 12 hours and our bandwidth estimate is + * low, do another bandwidth test. This is especially important for + * bridges, since they might go long periods without much use. */ + const routerinfo_t *me = router_get_my_routerinfo(); + static int first_time = 1; + if (!first_time && me && + me->bandwidthcapacity < me->bandwidthrate && + me->bandwidthcapacity < 51200) { + reset_bandwidth_test(); + } + first_time = 0; +#define BANDWIDTH_RECHECK_INTERVAL (12*60*60) + return BANDWIDTH_RECHECK_INTERVAL; + } + } + return CHECK_DESCRIPTOR_INTERVAL; +} + +DECLARE_EVENT(check_for_reachability_bw, ROUTER, FL(NEED_NET)); + +/** + * Callback: Send warnings if Tor doesn't find its ports reachable. + */ +static int +reachability_warnings_callback(time_t now, const or_options_t *options) +{ + (void) now; + + if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { + return (int)(TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT - get_uptime()); + } + + if (server_mode(options) && + !net_is_disabled() && + have_completed_a_circuit()) { + /* every 20 minutes, check and complain if necessary */ + const routerinfo_t *me = router_get_my_routerinfo(); + if (me && !check_whether_orport_reachable(options)) { + char *address = tor_dup_ip(me->addr); + log_warn(LD_CONFIG,"Your server (%s:%d) has not managed to confirm that " + "its ORPort is reachable. Relays do not publish descriptors " + "until their ORPort and DirPort are reachable. Please check " + "your firewalls, ports, address, /etc/hosts file, etc.", + address, me->or_port); + control_event_server_status(LOG_WARN, + "REACHABILITY_FAILED ORADDRESS=%s:%d", + address, me->or_port); + tor_free(address); + } + + if (me && !check_whether_dirport_reachable(options)) { + char *address = tor_dup_ip(me->addr); + log_warn(LD_CONFIG, + "Your server (%s:%d) has not managed to confirm that its " + "DirPort is reachable. Relays do not publish descriptors " + "until their ORPort and DirPort are reachable. Please check " + "your firewalls, ports, address, /etc/hosts file, etc.", + address, me->dir_port); + control_event_server_status(LOG_WARN, + "REACHABILITY_FAILED DIRADDRESS=%s:%d", + address, me->dir_port); + tor_free(address); + } + } + + return TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT; +} + +DECLARE_EVENT(reachability_warnings, ROUTER, FL(NEED_NET)); + +/* Periodic callback: Every 30 seconds, check whether it's time to make new + * Ed25519 subkeys. + */ +static int +check_ed_keys_callback(time_t now, const or_options_t *options) +{ + if (server_mode(options)) { + if (should_make_new_ed_keys(options, now)) { + int new_signing_key = load_ed_keys(options, now); + if (new_signing_key < 0 || + generate_ed_link_cert(options, now, new_signing_key > 0)) { + log_err(LD_OR, "Unable to update Ed25519 keys! Exiting."); + tor_shutdown_event_loop_and_exit(1); + } + } + return 30; + } + return PERIODIC_EVENT_NO_UPDATE; +} + +DECLARE_EVENT(check_ed_keys, ROUTER, 0); + +/* Period callback: Check if our old onion keys are still valid after the + * period of time defined by the consensus parameter + * "onion-key-grace-period-days", otherwise expire them by setting them to + * NULL. + */ +static int +check_onion_keys_expiry_time_callback(time_t now, const or_options_t *options) +{ + if (server_mode(options)) { + int onion_key_grace_period = get_onion_key_grace_period(); + time_t expiry_time = get_onion_key_set_at()+onion_key_grace_period; + if (expiry_time > now) { + return ONION_KEY_CONSENSUS_CHECK_INTERVAL; + } + + log_info(LD_GENERAL, "Expiring old onion keys."); + expire_old_onion_keys(); + cpuworkers_rotate_keyinfo(); + return ONION_KEY_CONSENSUS_CHECK_INTERVAL; + } + + return PERIODIC_EVENT_NO_UPDATE; +} + +DECLARE_EVENT(check_onion_keys_expiry_time, ROUTER, 0); + +void +relay_register_periodic_events(void) +{ + periodic_events_register(&retry_dns_event); + periodic_events_register(&check_dns_honesty_event); + periodic_events_register(&rotate_onion_key_event); + periodic_events_register(&check_descriptor_event); + periodic_events_register(&check_for_reachability_bw_event); + periodic_events_register(&reachability_warnings_event); + periodic_events_register(&check_ed_keys_event); + periodic_events_register(&check_onion_keys_expiry_time_event); + + dns_honesty_first_time = 1; + dirport_reachability_count = 0; +} + +/** + * Update our schedule so that we'll check whether we need to update our + * descriptor immediately, rather than after up to CHECK_DESCRIPTOR_INTERVAL + * seconds. + */ +void +reschedule_descriptor_update_check(void) +{ + periodic_event_reschedule(&check_descriptor_event); +} diff --git a/src/feature/relay/relay_periodic.h b/src/feature/relay/relay_periodic.h new file mode 100644 index 0000000000..b6ea83c749 --- /dev/null +++ b/src/feature/relay/relay_periodic.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_periodic.h + * @brief Header for feature/relay/relay_periodic.c + **/ + +#ifndef TOR_FEATURE_RELAY_RELAY_PERIODIC_H +#define TOR_FEATURE_RELAY_RELAY_PERIODIC_H + +void relay_register_periodic_events(void); +void reschedule_descriptor_update_check(void); + +#endif /* !defined(TOR_FEATURE_RELAY_RELAY_PERIODIC_H) */ diff --git a/src/feature/relay/relay_sys.c b/src/feature/relay/relay_sys.c new file mode 100644 index 0000000000..106e88b2a5 --- /dev/null +++ b/src/feature/relay/relay_sys.c @@ -0,0 +1,48 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_sys.c + * @brief Subsystem definitions for the relay module. + **/ + +#include "orconfig.h" +#include "core/or/or.h" + +#include "feature/relay/dns.h" +#include "feature/relay/ext_orport.h" +#include "feature/relay/onion_queue.h" +#include "feature/relay/relay_periodic.h" +#include "feature/relay/relay_sys.h" +#include "feature/relay/routerkeys.h" +#include "feature/relay/router.h" + +#include "lib/subsys/subsys.h" + +static int +subsys_relay_initialize(void) +{ + relay_register_periodic_events(); + return 0; +} + +static void +subsys_relay_shutdown(void) +{ + dns_free_all(); + ext_orport_free_all(); + clear_pending_onions(); + routerkeys_free_all(); + router_free_all(); +} + +const struct subsys_fns_t sys_relay = { + .name = "relay", + .supported = true, + .level = 50, + .initialize = subsys_relay_initialize, + .shutdown = subsys_relay_shutdown, +}; diff --git a/src/feature/relay/relay_sys.h b/src/feature/relay/relay_sys.h new file mode 100644 index 0000000000..32e21d90d8 --- /dev/null +++ b/src/feature/relay/relay_sys.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file relay_sys.h + * @brief Header for feature/relay/relay_sys.c + **/ + +#ifndef TOR_FEATURE_RELAY_RELAY_SYS_H +#define TOR_FEATURE_RELAY_RELAY_SYS_H + +extern const struct subsys_fns_t sys_relay; + +#endif /* !defined(TOR_FEATURE_RELAY_RELAY_SYS_H) */ diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index cdd032f78d..25bb1835c2 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -16,7 +16,7 @@ #include "core/or/policies.h" #include "core/or/protover.h" #include "feature/client/transports.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirauth/process_descs.h" #include "feature/dircache/dirserv.h" #include "feature/dirclient/dirclient.h" @@ -152,6 +152,8 @@ routerinfo_err_to_string(int err) return "Cannot generate descriptor"; case TOR_ROUTERINFO_ERROR_DESC_REBUILDING: return "Descriptor still rebuilding - not ready yet"; + case TOR_ROUTERINFO_ERROR_INTERNAL_BUG: + return "Internal bug, see logs for details"; } log_warn(LD_BUG, "unknown routerinfo error %d - shouldn't happen", err); @@ -194,8 +196,8 @@ set_onion_key(crypto_pk_t *k) /** Return the current onion key. Requires that the onion key has been * loaded or generated. */ -crypto_pk_t * -get_onion_key(void) +MOCK_IMPL(crypto_pk_t *, +get_onion_key,(void)) { tor_assert(onionkey); return onionkey; @@ -242,7 +244,7 @@ expire_old_onion_keys(void) lastonionkey = NULL; } - /* We zero out the keypair. See the tor_mem_is_zero() check made in + /* We zero out the keypair. See the fast_mem_is_zero() check made in * construct_ntor_key_map() below. */ memset(&last_curve25519_onion_key, 0, sizeof(last_curve25519_onion_key)); @@ -269,11 +271,12 @@ expire_old_onion_keys(void) /** Return the current secret onion key for the ntor handshake. Must only * be called from the main thread. */ -static const curve25519_keypair_t * -get_current_curve25519_keypair(void) +MOCK_IMPL(STATIC const struct curve25519_keypair_t *, +get_current_curve25519_keypair,(void)) { return &curve25519_onion_key; } + /** Return a map from KEYID (the key itself) to keypairs for use in the ntor * handshake. Must only be called from the main thread. */ di_digest256_map_t * @@ -281,7 +284,7 @@ construct_ntor_key_map(void) { di_digest256_map_t *m = NULL; - if (!tor_mem_is_zero((const char*) + if (!fast_mem_is_zero((const char*) curve25519_onion_key.pubkey.public_key, CURVE25519_PUBKEY_LEN)) { dimap_add_entry(&m, @@ -289,7 +292,7 @@ construct_ntor_key_map(void) tor_memdup(&curve25519_onion_key, sizeof(curve25519_keypair_t))); } - if (!tor_mem_is_zero((const char*) + if (!fast_mem_is_zero((const char*) last_curve25519_onion_key.pubkey.public_key, CURVE25519_PUBKEY_LEN)) { dimap_add_entry(&m, @@ -350,7 +353,7 @@ set_server_identity_key_digest_testing(const uint8_t *digest) { memcpy(server_identitykey_digest, digest, DIGEST_LEN); } -#endif +#endif /* defined(TOR_UNIT_TESTS) */ /** Make sure that we have set up our identity keys to match or not match as * appropriate, and die with an assertion if we have not. */ @@ -374,8 +377,8 @@ assert_identity_keys_ok(void) /** Returns the current server identity key; requires that the key has * been set, and that we are running as a Tor server. */ -crypto_pk_t * -get_server_identity_key(void) +MOCK_IMPL(crypto_pk_t *, +get_server_identity_key,(void)) { tor_assert(server_identitykey); tor_assert(server_mode(get_options())); @@ -1046,7 +1049,7 @@ init_keys(void) return -1; keydir = get_keydir_fname("secret_onion_key_ntor.old"); - if (tor_mem_is_zero((const char *) + if (fast_mem_is_zero((const char *) last_curve25519_onion_key.pubkey.public_key, CURVE25519_PUBKEY_LEN) && file_status(keydir) == FN_FILE) { @@ -1941,26 +1944,33 @@ get_my_declared_family(const or_options_t *options) return result; } -/** Build a fresh routerinfo, signed server descriptor, and extra-info document - * for this OR. Set r to the generated routerinfo, e to the generated - * extra-info document. Return 0 on success, -1 on temporary error. Failure to - * generate an extra-info document is not an error and is indicated by setting - * e to NULL. Caller is responsible for freeing generated documents if 0 is - * returned. +/** Allocate a fresh, unsigned routerinfo for this OR, without any of the + * fields that depend on the corresponding extrainfo. + * + * On success, set ri_out to the new routerinfo, and return 0. + * Caller is responsible for freeing the generated routerinfo. + * + * Returns a negative value and sets ri_out to NULL on temporary error. */ -int -router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e) +MOCK_IMPL(STATIC int, +router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out)) { - routerinfo_t *ri; - extrainfo_t *ei; + routerinfo_t *ri = NULL; uint32_t addr; char platform[256]; int hibernating = we_are_hibernating(); const or_options_t *options = get_options(); + int result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG; + + if (BUG(!ri_out)) { + result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG; + goto err; + } if (router_pick_published_address(options, &addr, 0) < 0) { log_warn(LD_CONFIG, "Don't know my address while generating descriptor"); - return TOR_ROUTERINFO_ERROR_NO_EXT_ADDR; + result = TOR_ROUTERINFO_ERROR_NO_EXT_ADDR; + goto err; } /* Log a message if the address in the descriptor doesn't match the ORPort @@ -2017,8 +2027,8 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e) ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key()); if (BUG(crypto_pk_get_digest(ri->identity_pkey, ri->cache_info.identity_digest) < 0)) { - routerinfo_free(ri); - return TOR_ROUTERINFO_ERROR_DIGEST_FAILED; + result = TOR_ROUTERINFO_ERROR_DIGEST_FAILED; + goto err; } ri->cache_info.signing_key_cert = tor_cert_dup(get_master_signing_key_cert()); @@ -2057,85 +2067,258 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e) ri->declared_family = get_my_declared_family(options); + if (options->BridgeRelay) { + ri->purpose = ROUTER_PURPOSE_BRIDGE; + /* Bridges shouldn't be able to send their descriptors unencrypted, + anyway, since they don't have a DirPort, and always connect to the + bridge authority anonymously. But just in case they somehow think of + sending them on an unencrypted connection, don't allow them to try. */ + ri->cache_info.send_unencrypted = 0; + } else { + ri->purpose = ROUTER_PURPOSE_GENERAL; + ri->cache_info.send_unencrypted = 1; + } + + goto done; + + err: + routerinfo_free(ri); + *ri_out = NULL; + return result; + + done: + *ri_out = ri; + return 0; +} + +/** Allocate and return a fresh, unsigned extrainfo for this OR, based on the + * routerinfo ri. + * + * Uses options->Nickname to set the nickname, and options->BridgeRelay to set + * ei->cache_info.send_unencrypted. + * + * If ri is NULL, logs a BUG() warning and returns NULL. + * Caller is responsible for freeing the generated extrainfo. + */ +static extrainfo_t * +router_build_fresh_unsigned_extrainfo(const routerinfo_t *ri) +{ + extrainfo_t *ei = NULL; + const or_options_t *options = get_options(); + + if (BUG(!ri)) + return NULL; + /* Now generate the extrainfo. */ ei = tor_malloc_zero(sizeof(extrainfo_t)); ei->cache_info.is_extrainfo = 1; - strlcpy(ei->nickname, get_options()->Nickname, sizeof(ei->nickname)); + strlcpy(ei->nickname, options->Nickname, sizeof(ei->nickname)); ei->cache_info.published_on = ri->cache_info.published_on; ei->cache_info.signing_key_cert = tor_cert_dup(get_master_signing_key_cert()); memcpy(ei->cache_info.identity_digest, ri->cache_info.identity_digest, DIGEST_LEN); + + if (options->BridgeRelay) { + /* See note in router_build_fresh_routerinfo(). */ + ei->cache_info.send_unencrypted = 0; + } else { + ei->cache_info.send_unencrypted = 1; + } + + return ei; +} + +/** Dump the extrainfo descriptor body for ei, sign it, and add the body and + * signature to ei->cache_info. Note that the extrainfo body is determined by + * ei, and some additional config and statistics state: see + * extrainfo_dump_to_string() for details. + * + * Return 0 on success, -1 on temporary error. + * If ei is NULL, logs a BUG() warning and returns -1. + * On error, ei->cache_info is not modified. + */ +static int +router_dump_and_sign_extrainfo_descriptor_body(extrainfo_t *ei) +{ + if (BUG(!ei)) + return -1; + if (extrainfo_dump_to_string(&ei->cache_info.signed_descriptor_body, ei, get_server_identity_key(), get_master_signing_keypair()) < 0) { log_warn(LD_BUG, "Couldn't generate extra-info descriptor."); - extrainfo_free(ei); - ei = NULL; - } else { - ei->cache_info.signed_descriptor_len = - strlen(ei->cache_info.signed_descriptor_body); - router_get_extrainfo_hash(ei->cache_info.signed_descriptor_body, - ei->cache_info.signed_descriptor_len, - ei->cache_info.signed_descriptor_digest); - crypto_digest256((char*) ei->digest256, - ei->cache_info.signed_descriptor_body, - ei->cache_info.signed_descriptor_len, - DIGEST_SHA256); + return -1; } - /* Now finish the router descriptor. */ - if (ei) { - memcpy(ri->cache_info.extra_info_digest, - ei->cache_info.signed_descriptor_digest, - DIGEST_LEN); - memcpy(ri->cache_info.extra_info_digest256, - ei->digest256, - DIGEST256_LEN); - } else { - /* ri was allocated with tor_malloc_zero, so there is no need to - * zero ri->cache_info.extra_info_digest here. */ + ei->cache_info.signed_descriptor_len = + strlen(ei->cache_info.signed_descriptor_body); + + router_get_extrainfo_hash(ei->cache_info.signed_descriptor_body, + ei->cache_info.signed_descriptor_len, + ei->cache_info.signed_descriptor_digest); + crypto_digest256((char*) ei->digest256, + ei->cache_info.signed_descriptor_body, + ei->cache_info.signed_descriptor_len, + DIGEST_SHA256); + + return 0; +} + +/** Allocate and return a fresh, signed extrainfo for this OR, based on the + * routerinfo ri. + * + * If ri is NULL, logs a BUG() warning and returns NULL. + * Caller is responsible for freeing the generated extrainfo. + */ +STATIC extrainfo_t * +router_build_fresh_signed_extrainfo(const routerinfo_t *ri) +{ + int result = -1; + extrainfo_t *ei = NULL; + + if (BUG(!ri)) + return NULL; + + ei = router_build_fresh_unsigned_extrainfo(ri); + /* router_build_fresh_unsigned_extrainfo() should not fail. */ + if (BUG(!ei)) + goto err; + + result = router_dump_and_sign_extrainfo_descriptor_body(ei); + if (result < 0) + goto err; + + goto done; + + err: + extrainfo_free(ei); + return NULL; + + done: + return ei; +} + +/** Set the fields in ri that depend on ei. + * + * If ei is NULL, logs a BUG() warning and zeroes the relevant fields. + */ +STATIC void +router_update_routerinfo_from_extrainfo(routerinfo_t *ri, + const extrainfo_t *ei) +{ + if (BUG(!ei)) { + /* Just to be safe, zero ri->cache_info.extra_info_digest here. */ + memset(ri->cache_info.extra_info_digest, 0, DIGEST_LEN); + memset(ri->cache_info.extra_info_digest256, 0, DIGEST256_LEN); + return; } + + /* Now finish the router descriptor. */ + memcpy(ri->cache_info.extra_info_digest, + ei->cache_info.signed_descriptor_digest, + DIGEST_LEN); + memcpy(ri->cache_info.extra_info_digest256, + ei->digest256, + DIGEST256_LEN); +} + +/** Dump the descriptor body for ri, sign it, and add the body and signature to + * ri->cache_info. Note that the descriptor body is determined by ri, and some + * additional config and state: see router_dump_router_to_string() for details. + * + * Return 0 on success, and a negative value on temporary error. + * If ri is NULL, logs a BUG() warning and returns a negative value. + * On error, ri->cache_info is not modified. + */ +STATIC int +router_dump_and_sign_routerinfo_descriptor_body(routerinfo_t *ri) +{ + if (BUG(!ri)) + return TOR_ROUTERINFO_ERROR_INTERNAL_BUG; + if (! (ri->cache_info.signed_descriptor_body = router_dump_router_to_string(ri, get_server_identity_key(), get_onion_key(), get_current_curve25519_keypair(), get_master_signing_keypair())) ) { log_warn(LD_BUG, "Couldn't generate router descriptor."); - routerinfo_free(ri); - extrainfo_free(ei); return TOR_ROUTERINFO_ERROR_CANNOT_GENERATE; } + ri->cache_info.signed_descriptor_len = strlen(ri->cache_info.signed_descriptor_body); - ri->purpose = - options->BridgeRelay ? ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL; - if (options->BridgeRelay) { - /* Bridges shouldn't be able to send their descriptors unencrypted, - anyway, since they don't have a DirPort, and always connect to the - bridge authority anonymously. But just in case they somehow think of - sending them on an unencrypted connection, don't allow them to try. */ - ri->cache_info.send_unencrypted = 0; - if (ei) - ei->cache_info.send_unencrypted = 0; - } else { - ri->cache_info.send_unencrypted = 1; - if (ei) - ei->cache_info.send_unencrypted = 1; - } - router_get_router_hash(ri->cache_info.signed_descriptor_body, strlen(ri->cache_info.signed_descriptor_body), ri->cache_info.signed_descriptor_digest); + return 0; +} + +/** Build a fresh routerinfo, signed server descriptor, and signed extrainfo + * document for this OR. + * + * Set r to the generated routerinfo, e to the generated extrainfo document. + * Failure to generate an extra-info document is not an error and is indicated + * by setting e to NULL. + * Return 0 on success, and a negative value on temporary error. + * Caller is responsible for freeing generated documents on success. + */ +int +router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e) +{ + int result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG; + routerinfo_t *ri = NULL; + extrainfo_t *ei = NULL; + + if (BUG(!r)) + goto err; + + if (BUG(!e)) + goto err; + + result = router_build_fresh_unsigned_routerinfo(&ri); + if (result < 0) { + goto err; + } + /* If ri is NULL, then result should be negative. So this check should be + * unreachable. */ + if (BUG(!ri)) { + result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG; + goto err; + } + + ei = router_build_fresh_signed_extrainfo(ri); + + /* Failing to create an ei is not an error. */ + if (ei) { + router_update_routerinfo_from_extrainfo(ri, ei); + } + + result = router_dump_and_sign_routerinfo_descriptor_body(ri); + if (result < 0) + goto err; + if (ei) { - tor_assert(! - routerinfo_incompatible_with_extrainfo(ri->identity_pkey, ei, - &ri->cache_info, NULL)); + if (BUG(routerinfo_incompatible_with_extrainfo(ri->identity_pkey, ei, + &ri->cache_info, NULL))) { + result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG; + goto err; + } } + goto done; + + err: + routerinfo_free(ri); + extrainfo_free(ei); + *r = NULL; + *e = NULL; + return result; + + done: *r = ri; *e = ei; return 0; @@ -2478,6 +2661,10 @@ get_platform_str(char *platform, size_t len) /** OR only: Given a routerinfo for this router, and an identity key to sign * with, encode the routerinfo as a signed server descriptor and return a new * string encoding the result, or NULL on failure. + * + * In addition to the fields in router, this function calls + * onion_key_lifetime(), get_options(), and we_are_hibernating(), and uses the + * results to populate some fields in the descriptor. */ char * router_dump_router_to_string(routerinfo_t *router, @@ -2541,11 +2728,8 @@ router_dump_router_to_string(routerinfo_t *router, log_err(LD_BUG,"Couldn't base64-encode signing key certificate!"); goto err; } - if (ed25519_public_to_base64(ed_fp_base64, - &router->cache_info.signing_key_cert->signing_key)<0) { - log_err(LD_BUG,"Couldn't base64-encode identity key\n"); - goto err; - } + ed25519_public_to_base64(ed_fp_base64, + &router->cache_info.signing_key_cert->signing_key); tor_asprintf(&ed_cert_line, "identity-ed25519\n" "-----BEGIN ED25519 CERT-----\n" "%s" @@ -2790,8 +2974,7 @@ router_dump_router_to_string(routerinfo_t *router, if (ed25519_sign(&sig, (const uint8_t*)digest, DIGEST256_LEN, signing_keypair) < 0) goto err; - if (ed25519_signature_to_base64(buf, &sig) < 0) - goto err; + ed25519_signature_to_base64(buf, &sig); smartlist_add_asprintf(chunks, "%s\n", buf); } @@ -2930,9 +3113,14 @@ load_stats_file(const char *filename, const char *end_line, time_t now, return r; } -/** Write the contents of extrainfo and aggregated statistics to - * *s_out, signing them with ident_key. Return 0 on - * success, negative on failure. */ +/** Write the contents of extrainfo, to * *s_out, signing them + * with ident_key. + * + * If ExtraInfoStatistics is 1, also write aggregated statistics and related + * configuration data before signing. Most statistics also have an option that + * enables or disables that particular statistic. + * + * Return 0 on success, negative on failure. */ int extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, crypto_pk_t *ident_key, @@ -2942,7 +3130,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, char identity[HEX_DIGEST_LEN+1]; char published[ISO_TIME_LEN+1]; char digest[DIGEST_LEN]; - char *bandwidth_usage; int result; static int write_stats_to_extrainfo = 1; char sig[DIROBJ_MAX_SIG_LEN+1]; @@ -2957,7 +3144,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, base16_encode(identity, sizeof(identity), extrainfo->cache_info.identity_digest, DIGEST_LEN); format_iso_time(published, extrainfo->cache_info.published_on); - bandwidth_usage = rep_hist_get_bandwidth_lines(); if (emit_ed_sigs) { if (!extrainfo->cache_info.signing_key_cert->signing_key_included || !ed25519_pubkey_eq(&extrainfo->cache_info.signing_key_cert->signed_key, @@ -2983,21 +3169,35 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, ed_cert_line = tor_strdup(""); } - tor_asprintf(&pre, "extra-info %s %s\n%spublished %s\n%s", + tor_asprintf(&pre, "extra-info %s %s\n%spublished %s\n", extrainfo->nickname, identity, ed_cert_line, - published, bandwidth_usage); + published); smartlist_add(chunks, pre); - if (geoip_is_loaded(AF_INET)) - smartlist_add_asprintf(chunks, "geoip-db-digest %s\n", - geoip_db_digest(AF_INET)); - if (geoip_is_loaded(AF_INET6)) - smartlist_add_asprintf(chunks, "geoip6-db-digest %s\n", - geoip_db_digest(AF_INET6)); + /* Add information about the pluggable transports we support, even if we + * are not publishing statistics. This information is needed by BridgeDB + * to distribute bridges. */ + if (options->ServerTransportPlugin) { + char *pluggable_transports = pt_get_extra_info_descriptor_string(); + if (pluggable_transports) + smartlist_add(chunks, pluggable_transports); + } if (options->ExtraInfoStatistics && write_stats_to_extrainfo) { log_info(LD_GENERAL, "Adding stats to extra-info descriptor."); + /* Bandwidth usage stats don't have their own option */ + { + contents = rep_hist_get_bandwidth_lines(); + smartlist_add(chunks, contents); + } + /* geoip hashes aren't useful unless we are publishing other stats */ + if (geoip_is_loaded(AF_INET)) + smartlist_add_asprintf(chunks, "geoip-db-digest %s\n", + geoip_db_digest(AF_INET)); + if (geoip_is_loaded(AF_INET6)) + smartlist_add_asprintf(chunks, "geoip6-db-digest %s\n", + geoip_db_digest(AF_INET6)); if (options->DirReqStatistics && load_stats_file("stats"PATH_SEPARATOR"dirreq-stats", "dirreq-stats-end", now, &contents) > 0) { @@ -3033,19 +3233,12 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, if (contents) smartlist_add(chunks, contents); } - } - - /* Add information about the pluggable transports we support. */ - if (options->ServerTransportPlugin) { - char *pluggable_transports = pt_get_extra_info_descriptor_string(); - if (pluggable_transports) - smartlist_add(chunks, pluggable_transports); - } - - if (should_record_bridge_info(options) && write_stats_to_extrainfo) { - const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now); - if (bridge_stats) { - smartlist_add_strdup(chunks, bridge_stats); + /* bridge statistics */ + if (should_record_bridge_info(options)) { + const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now); + if (bridge_stats) { + smartlist_add_strdup(chunks, bridge_stats); + } } } @@ -3060,8 +3253,7 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, if (ed25519_sign(&ed_sig, (const uint8_t*)sha256_digest, DIGEST256_LEN, signing_keypair) < 0) goto err; - if (ed25519_signature_to_base64(buf, &ed_sig) < 0) - goto err; + ed25519_signature_to_base64(buf, &ed_sig); smartlist_add_asprintf(chunks, "%s\n", buf); } @@ -3139,7 +3331,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, tor_free(s_dup); tor_free(ed_cert_line); extrainfo_free(ei_tmp); - tor_free(bandwidth_usage); return result; } diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h index 60bc857ceb..55b9ef9e68 100644 --- a/src/feature/relay/router.h +++ b/src/feature/relay/router.h @@ -23,11 +23,12 @@ struct ed25519_keypair_t; #define TOR_ROUTERINFO_ERROR_DIGEST_FAILED (-4) #define TOR_ROUTERINFO_ERROR_CANNOT_GENERATE (-5) #define TOR_ROUTERINFO_ERROR_DESC_REBUILDING (-6) +#define TOR_ROUTERINFO_ERROR_INTERNAL_BUG (-7) -crypto_pk_t *get_onion_key(void); +MOCK_DECL(crypto_pk_t *,get_onion_key,(void)); time_t get_onion_key_set_at(void); void set_server_identity_key(crypto_pk_t *k); -crypto_pk_t *get_server_identity_key(void); +MOCK_DECL(crypto_pk_t *,get_server_identity_key,(void)); int server_identity_key_is_set(void); void set_client_identity_key(crypto_pk_t *k); crypto_pk_t *get_tlsclient_identity_key(void); @@ -114,7 +115,7 @@ void router_reset_reachability(void); void router_free_all(void); #ifdef ROUTER_PRIVATE -/* Used only by router.c and test.c */ +/* Used only by router.c and the unit tests */ STATIC void get_platform_str(char *platform, size_t len); STATIC int router_write_fingerprint(int hashed); STATIC smartlist_t *get_my_declared_family(const or_options_t *options); @@ -123,8 +124,18 @@ STATIC smartlist_t *get_my_declared_family(const or_options_t *options); extern time_t desc_clean_since; extern const char *desc_dirty_reason; void set_server_identity_key_digest_testing(const uint8_t *digest); -#endif - -#endif +MOCK_DECL(STATIC const struct curve25519_keypair_t *, + get_current_curve25519_keypair,(void)); + +MOCK_DECL(STATIC int, + router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out)); +STATIC extrainfo_t *router_build_fresh_signed_extrainfo( + const routerinfo_t *ri); +STATIC void router_update_routerinfo_from_extrainfo(routerinfo_t *ri, + const extrainfo_t *ei); +STATIC int router_dump_and_sign_routerinfo_descriptor_body(routerinfo_t *ri); +#endif /* defined(TOR_UNIT_TESTS) */ + +#endif /* defined(ROUTER_PRIVATE) */ #endif /* !defined(TOR_ROUTER_H) */ diff --git a/src/feature/relay/routerkeys.c b/src/feature/relay/routerkeys.c index 876f908d41..a9190b2e13 100644 --- a/src/feature/relay/routerkeys.c +++ b/src/feature/relay/routerkeys.c @@ -188,7 +188,7 @@ load_ed_keys(const or_options_t *options, time_t now) /* Check/Create the key directory */ if (create_keys_directory(options) < 0) - return -1; + goto err; char *fname; if (options->master_key_fname) { @@ -226,7 +226,7 @@ load_ed_keys(const or_options_t *options, time_t now) tor_free(fname); } } - if (tor_mem_is_zero((char*)id->seckey.seckey, sizeof(id->seckey))) + if (safe_mem_is_zero((char*)id->seckey.seckey, sizeof(id->seckey))) sign_signing_key_with_id = NULL; else sign_signing_key_with_id = id; @@ -631,14 +631,14 @@ get_master_identity_keypair(void) } #endif /* defined(TOR_UNIT_TESTS) */ -const ed25519_keypair_t * -get_master_signing_keypair(void) +MOCK_IMPL(const ed25519_keypair_t *, +get_master_signing_keypair,(void)) { return master_signing_key; } -const struct tor_cert_st * -get_master_signing_key_cert(void) +MOCK_IMPL(const struct tor_cert_st *, +get_master_signing_key_cert,(void)) { return signing_key_cert; } @@ -706,6 +706,8 @@ make_tap_onion_key_crosscert(const crypto_pk_t *onion_key, *len_out = 0; if (crypto_pk_get_digest(rsa_id_key, (char*)signed_data) < 0) { + log_info(LD_OR, "crypto_pk_get_digest failed in " + "make_tap_onion_key_crosscert!"); return NULL; } memcpy(signed_data + DIGEST_LEN, master_id_key->pubkey, ED25519_PUBKEY_LEN); @@ -713,8 +715,12 @@ make_tap_onion_key_crosscert(const crypto_pk_t *onion_key, int r = crypto_pk_private_sign(onion_key, (char*)signature, sizeof(signature), (const char*)signed_data, sizeof(signed_data)); - if (r < 0) + if (r < 0) { + /* It's probably missing the private key */ + log_info(LD_OR, "crypto_pk_private_sign failed in " + "make_tap_onion_key_crosscert!"); return NULL; + } *len_out = r; diff --git a/src/feature/relay/routerkeys.h b/src/feature/relay/routerkeys.h index 0badd34191..cde07b52c3 100644 --- a/src/feature/relay/routerkeys.h +++ b/src/feature/relay/routerkeys.h @@ -7,8 +7,8 @@ #include "lib/crypt_ops/crypto_ed25519.h" const ed25519_public_key_t *get_master_identity_key(void); -const ed25519_keypair_t *get_master_signing_keypair(void); -const struct tor_cert_st *get_master_signing_key_cert(void); +MOCK_DECL(const ed25519_keypair_t *, get_master_signing_keypair,(void)); +MOCK_DECL(const struct tor_cert_st *, get_master_signing_key_cert,(void)); const ed25519_keypair_t *get_current_auth_keypair(void); const struct tor_cert_st *get_current_link_cert_cert(void); diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c index 064eea6c46..f8b54ff45d 100644 --- a/src/feature/relay/selftest.c +++ b/src/feature/relay/selftest.c @@ -26,7 +26,7 @@ #include "core/or/crypt_path_st.h" #include "core/or/origin_circuit_st.h" #include "core/or/relay.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirclient/dirclient.h" #include "feature/dircommon/directory.h" #include "feature/nodelist/authority_cert_st.h" @@ -35,6 +35,7 @@ #include "feature/nodelist/routerlist.h" // but... #include "feature/nodelist/routerset.h" #include "feature/nodelist/torcert.h" +#include "feature/relay/relay_periodic.h" #include "feature/relay/router.h" #include "feature/relay/selftest.h" diff --git a/src/feature/relay/selftest.h b/src/feature/relay/selftest.h index a80ec8936e..aea77ec791 100644 --- a/src/feature/relay/selftest.h +++ b/src/feature/relay/selftest.h @@ -21,4 +21,4 @@ void router_orport_found_reachable(void); void router_dirport_found_reachable(void); void router_perform_bandwidth_test(int num_circs, time_t now); -#endif +#endif /* !defined(TOR_SELFTEST_H) */ diff --git a/src/feature/rend/rend_authorized_client_st.h b/src/feature/rend/rend_authorized_client_st.h index 7bd4f2fe8c..51a1798fcb 100644 --- a/src/feature/rend/rend_authorized_client_st.h +++ b/src/feature/rend/rend_authorized_client_st.h @@ -14,5 +14,5 @@ struct rend_authorized_client_t { crypto_pk_t *client_key; }; -#endif +#endif /* !defined(REND_AUTHORIZED_CLIENT_ST_H) */ diff --git a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h b/src/feature/rend/rend_encoded_v2_service_descriptor_st.h index 05ff145d53..bd8a60f0d9 100644 --- a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h +++ b/src/feature/rend/rend_encoded_v2_service_descriptor_st.h @@ -13,5 +13,5 @@ struct rend_encoded_v2_service_descriptor_t { char *desc_str; /**< Descriptor string. */ }; -#endif +#endif /* !defined(REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H) */ diff --git a/src/feature/rend/rend_intro_point_st.h b/src/feature/rend/rend_intro_point_st.h index de6987e569..4882b62752 100644 --- a/src/feature/rend/rend_intro_point_st.h +++ b/src/feature/rend/rend_intro_point_st.h @@ -73,4 +73,4 @@ struct rend_intro_point_t { unsigned int circuit_established:1; }; -#endif +#endif /* !defined(REND_INTRO_POINT_ST_H) */ diff --git a/src/feature/rend/rend_service_descriptor_st.h b/src/feature/rend/rend_service_descriptor_st.h index aeb3178064..ff7627ce96 100644 --- a/src/feature/rend/rend_service_descriptor_st.h +++ b/src/feature/rend/rend_service_descriptor_st.h @@ -30,5 +30,5 @@ struct rend_service_descriptor_t { smartlist_t *successful_uploads; }; -#endif +#endif /* !defined(REND_SERVICE_DESCRIPTOR_ST_H) */ diff --git a/src/feature/rend/rendcache.c b/src/feature/rend/rendcache.c index fadfb43883..c3f86d8c82 100644 --- a/src/feature/rend/rendcache.c +++ b/src/feature/rend/rendcache.c @@ -19,6 +19,8 @@ #include "feature/rend/rend_intro_point_st.h" #include "feature/rend/rend_service_descriptor_st.h" +#include "lib/ctime/di_ops.h" + /** Map from service id (as generated by rend_get_service_id) to * rend_cache_entry_t. */ STATIC strmap_t *rend_cache = NULL; @@ -593,10 +595,10 @@ rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc) char desc_id_digest[DIGEST_LEN]; tor_assert(rend_cache_v2_dir); if (base32_decode(desc_id_digest, DIGEST_LEN, - desc_id, REND_DESC_ID_V2_LEN_BASE32) < 0) { + desc_id, REND_DESC_ID_V2_LEN_BASE32) != DIGEST_LEN) { log_fn(LOG_PROTOCOL_WARN, LD_REND, "Rejecting v2 rendezvous descriptor request -- descriptor ID " - "contains illegal characters: %s", + "has wrong length or illegal characters: %s", safe_str(desc_id)); return -1; } @@ -854,7 +856,8 @@ rend_cache_store_v2_desc_as_client(const char *desc, *entry = NULL; } if (base32_decode(want_desc_id, sizeof(want_desc_id), - desc_id_base32, strlen(desc_id_base32)) != 0) { + desc_id_base32, strlen(desc_id_base32)) != + sizeof(want_desc_id)) { log_warn(LD_BUG, "Couldn't decode base32 %s for descriptor id.", escaped_safe_str_client(desc_id_base32)); goto err; @@ -888,8 +891,8 @@ rend_cache_store_v2_desc_as_client(const char *desc, if (intro_content && intro_size > 0) { int n_intro_points; if (rend_data->auth_type != REND_NO_AUTH && - !tor_mem_is_zero(rend_data->descriptor_cookie, - sizeof(rend_data->descriptor_cookie))) { + !safe_mem_is_zero(rend_data->descriptor_cookie, + sizeof(rend_data->descriptor_cookie))) { char *ipos_decrypted = NULL; size_t ipos_decrypted_size; if (rend_decrypt_introduction_points(&ipos_decrypted, @@ -1005,4 +1008,3 @@ rend_cache_store_v2_desc_as_client(const char *desc, tor_free(intro_content); return retval; } - diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c index 4ca783c7c3..5bdd4d453e 100644 --- a/src/feature/rend/rendclient.c +++ b/src/feature/rend/rendclient.c @@ -17,7 +17,7 @@ #include "core/or/connection_edge.h" #include "core/or/relay.h" #include "feature/client/circpathbias.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirclient/dirclient.h" #include "feature/dircommon/directory.h" #include "feature/hs/hs_circuit.h" @@ -403,14 +403,23 @@ rend_client_introduction_acked(origin_circuit_t *circ, } else { log_info(LD_REND,"...Found no rend circ. Dropping on the floor."); } + /* Save the rend data digest to a temporary object so that we don't access + * it after we mark the circuit for close. */ + const uint8_t *rend_digest_tmp = NULL; + size_t digest_len; + uint8_t *cached_rend_digest = NULL; + rend_digest_tmp = rend_data_get_pk_digest(circ->rend_data, &digest_len); + cached_rend_digest = tor_malloc_zero(digest_len); + memcpy(cached_rend_digest, rend_digest_tmp, digest_len); + /* close the circuit: we won't need it anymore. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCE_ACKED); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); /* close any other intros launched in parallel */ - rend_client_close_other_intros(rend_data_get_pk_digest(circ->rend_data, - NULL)); + rend_client_close_other_intros(cached_rend_digest); + tor_free(cached_rend_digest); /* free the temporary digest */ } else { /* It's a NAK; the introduction point didn't relay our request. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCING); @@ -469,16 +478,19 @@ directory_get_from_hs_dir(const char *desc_id, /* Automatically pick an hs dir if none given. */ if (!rs_hsdir) { + bool rate_limited = false; + /* Determine responsible dirs. Even if we can't get all we want, work with * the ones we have. If it's empty, we'll notice in hs_pick_hsdir(). */ smartlist_t *responsible_dirs = smartlist_new(); hid_serv_get_responsible_directories(responsible_dirs, desc_id); - hs_dir = hs_pick_hsdir(responsible_dirs, desc_id_base32); + hs_dir = hs_pick_hsdir(responsible_dirs, desc_id_base32, &rate_limited); if (!hs_dir) { /* No suitable hs dir can be found, stop right now. */ - control_event_hsv2_descriptor_failed(rend_query, NULL, - "QUERY_NO_HSDIR"); + const char *query_response = (rate_limited) ? "QUERY_RATE_LIMITED" : + "QUERY_NO_HSDIR"; + control_event_hsv2_descriptor_failed(rend_query, NULL, query_response); control_event_hs_descriptor_content(rend_data_get_address(rend_query), desc_id_base32, NULL, NULL); return 0; diff --git a/src/feature/rend/rendcommon.c b/src/feature/rend/rendcommon.c index de48af795f..777de2984c 100644 --- a/src/feature/rend/rendcommon.c +++ b/src/feature/rend/rendcommon.c @@ -15,7 +15,7 @@ #include "core/or/circuitlist.h" #include "core/or/circuituse.h" #include "app/config/config.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" #include "feature/hs/hs_client.h" @@ -171,9 +171,10 @@ rend_compute_v2_desc_id(char *desc_id_out, const char *service_id, } /* Convert service ID to binary. */ if (base32_decode(service_id_binary, REND_SERVICE_ID_LEN, - service_id, REND_SERVICE_ID_LEN_BASE32) < 0) { + service_id, REND_SERVICE_ID_LEN_BASE32) != + REND_SERVICE_ID_LEN) { log_warn(LD_REND, "Could not compute v2 descriptor ID: " - "Illegal characters in service ID: %s", + "Illegal characters or wrong length for service ID: %s", safe_str_client(service_id)); return -1; } diff --git a/src/feature/rend/rendparse.c b/src/feature/rend/rendparse.c index abd0feb448..a98cb3ad88 100644 --- a/src/feature/rend/rendparse.c +++ b/src/feature/rend/rendparse.c @@ -143,8 +143,9 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, goto err; } if (base32_decode(desc_id_out, DIGEST_LEN, - tok->args[0], REND_DESC_ID_V2_LEN_BASE32) < 0) { - log_warn(LD_REND, "Descriptor ID contains illegal characters: %s", + tok->args[0], REND_DESC_ID_V2_LEN_BASE32) != DIGEST_LEN) { + log_warn(LD_REND, + "Descriptor ID has wrong length or illegal characters: %s", tok->args[0]); goto err; } @@ -174,8 +175,10 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]); goto err; } - if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) < 0) { - log_warn(LD_REND, "Secret ID part contains illegal characters: %s", + if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) != + DIGEST_LEN) { + log_warn(LD_REND, + "Secret ID part has wrong length or illegal characters: %s", tok->args[0]); goto err; } @@ -429,8 +432,10 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed, /* Parse identifier. */ tok = find_by_keyword(tokens, R_IPO_IDENTIFIER); if (base32_decode(info->identity_digest, DIGEST_LEN, - tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) { - log_warn(LD_REND, "Identity digest contains illegal characters: %s", + tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) != + DIGEST_LEN) { + log_warn(LD_REND, + "Identity digest has wrong length or illegal characters: %s", tok->args[0]); rend_intro_point_free(intro); goto err; diff --git a/src/feature/rend/rendparse.h b/src/feature/rend/rendparse.h index 0cef931e90..b1ccce9b6c 100644 --- a/src/feature/rend/rendparse.h +++ b/src/feature/rend/rendparse.h @@ -29,4 +29,4 @@ int rend_parse_introduction_points(rend_service_descriptor_t *parsed, size_t intro_points_encoded_size); int rend_parse_client_keys(strmap_t *parsed_clients, const char *str); -#endif +#endif /* !defined(TOR_REND_PARSE_H) */ diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c index 5ee084b0b7..119a6f9c89 100644 --- a/src/feature/rend/rendservice.c +++ b/src/feature/rend/rendservice.c @@ -18,8 +18,9 @@ #include "core/or/circuituse.h" #include "core/or/policies.h" #include "core/or/relay.h" +#include "core/or/crypt_path.h" #include "feature/client/circpathbias.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dirclient/dirclient.h" #include "feature/dircommon/directory.h" #include "feature/hs/hs_common.h" @@ -2122,8 +2123,12 @@ rend_service_receive_introduction(origin_circuit_t *circuit, int flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL; if (circ_needs_uptime) flags |= CIRCLAUNCH_NEED_UPTIME; /* A Single Onion Service only uses a direct connection if its - * firewall rules permit direct connections to the address. */ - if (rend_service_use_direct_connection(options, rp)) { + * firewall rules permit direct connections to the address. + * + * We only use a one-hop path on the first attempt. If the first attempt + * fails, we use a 3-hop path for reachability / reliability. + * See the comment in rend_service_relauch_rendezvous() for details. */ + if (rend_service_use_direct_connection(options, rp) && i == 0) { flags = flags | CIRCLAUNCH_ONEHOP_TUNNEL; } launched = circuit_launch_by_extend_info( @@ -2163,7 +2168,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit, cpath->rend_dh_handshake_state = dh; dh = NULL; - if (circuit_init_cpath_crypto(cpath, + if (cpath_init_circuit_crypto(cpath, keys+DIGEST_LEN, sizeof(keys)-DIGEST_LEN, 1, 0)<0) goto err; @@ -3012,6 +3017,10 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) { origin_circuit_t *newcirc; cpath_build_state_t *newstate, *oldstate; + const char *rend_pk_digest; + rend_service_t *service = NULL; + + int flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL; tor_assert(oldcirc->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); oldstate = oldcirc->build_state; @@ -3026,13 +3035,31 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) log_info(LD_REND,"Reattempting rendezvous circuit to '%s'", safe_str(extend_info_describe(oldstate->chosen_exit))); + /* Look up the service. */ + rend_pk_digest = (char *) rend_data_get_pk_digest(oldcirc->rend_data, NULL); + service = rend_service_get_by_pk_digest(rend_pk_digest); + + if (!service) { + char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; + base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1, + rend_pk_digest, REND_SERVICE_ID_LEN); + + log_warn(LD_BUG, "Internal error: Trying to relaunch a rendezvous circ " + "for an unrecognized service %s.", + safe_str_client(serviceid)); + return; + } + + if (hs_service_requires_uptime_circ(service->ports)) { + flags |= CIRCLAUNCH_NEED_UPTIME; + } + /* You'd think Single Onion Services would want to retry the rendezvous * using a direct connection. But if it's blocked by a firewall, or the * service is IPv6-only, or the rend point avoiding becoming a one-hop * proxy, we need a 3-hop connection. */ newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, - oldstate->chosen_exit, - CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL); + oldstate->chosen_exit, flags); if (!newcirc) { log_warn(LD_REND,"Couldn't relaunch rendezvous circuit to '%s'.", @@ -3063,8 +3090,15 @@ rend_service_launch_establish_intro(rend_service_t *service, extend_info_t *launch_ei = intro->extend_info; extend_info_t *direct_ei = NULL; - /* Are we in single onion mode? */ - if (rend_service_allow_non_anonymous_connection(options)) { + /* Are we in single onion mode? + * + * We only use a one-hop path on the first attempt. If the first attempt + * fails, we use a 3-hop path for reachability / reliability. + * (Unlike v3, retries is incremented by the caller after it calls this + * function.) + */ + if (rend_service_allow_non_anonymous_connection(options) && + intro->circuit_retries == 0) { /* Do we have a descriptor for the node? * We've either just chosen it from the consensus, or we've just reviewed * our intro points to see which ones are still valid, and deleted the ones @@ -3525,7 +3559,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) hop->package_window = circuit_initial_package_window(); hop->deliver_window = CIRCWINDOW_START; - onion_append_to_cpath(&circuit->cpath, hop); + cpath_extend_linked_list(&circuit->cpath, hop); circuit->build_state->pending_final_cpath = NULL; /* prevent double-free */ /* Change the circuit purpose. */ @@ -4205,6 +4239,7 @@ rend_consider_services_intro_points(time_t now) * directly ourselves. */ intro->extend_info = extend_info_from_node(node, 0); if (BUG(intro->extend_info == NULL)) { + tor_free(intro); break; } intro->intro_key = crypto_pk_new(); diff --git a/src/feature/stats/geoip_stats.c b/src/feature/stats/geoip_stats.c index 5119da19a0..6fb21f4f79 100644 --- a/src/feature/stats/geoip_stats.c +++ b/src/feature/stats/geoip_stats.c @@ -32,7 +32,7 @@ #include "ht.h" #include "lib/buf/buffers.h" #include "app/config/config.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/client/dnsserv.h" #include "core/or/dos.h" #include "lib/geoip/geoip.h" diff --git a/src/feature/stats/predict_ports.h b/src/feature/stats/predict_ports.h index 272344da2f..45b206c23a 100644 --- a/src/feature/stats/predict_ports.h +++ b/src/feature/stats/predict_ports.h @@ -27,4 +27,4 @@ int rep_hist_circbuilding_dormant(time_t now); int predicted_ports_prediction_time_remaining(time_t now); void predicted_ports_free_all(void); -#endif +#endif /* !defined(TOR_PREDICT_PORTS_H) */ diff --git a/src/feature/stats/rephist.h b/src/feature/stats/rephist.h index 3accc8c610..0d72946382 100644 --- a/src/feature/stats/rephist.h +++ b/src/feature/stats/rephist.h @@ -103,7 +103,7 @@ typedef struct bw_array_t bw_array_t; STATIC uint64_t find_largest_max(bw_array_t *b); STATIC void commit_max(bw_array_t *b); STATIC void advance_obs(bw_array_t *b); -#endif +#endif /* defined(REPHIST_PRIVATE) */ /** * Represents the type of a cell for padding accounting diff --git a/src/include.am b/src/include.am index 9070a69a03..77c126ba45 100644 --- a/src/include.am +++ b/src/include.am @@ -8,6 +8,7 @@ include src/lib/compress/include.am include src/lib/container/include.am include src/lib/crypt_ops/include.am include src/lib/defs/include.am +include src/lib/dispatch/include.am include src/lib/encoding/include.am include src/lib/evloop/include.am include src/lib/fdio/include.am @@ -24,6 +25,7 @@ include src/lib/malloc/include.am include src/lib/net/include.am include src/lib/osinfo/include.am include src/lib/process/include.am +include src/lib/pubsub/include.am include src/lib/sandbox/include.am include src/lib/string/include.am include src/lib/subsys/include.am diff --git a/src/lib/arch/bytes.h b/src/lib/arch/bytes.h index fa82241b28..b8b6288139 100644 --- a/src/lib/arch/bytes.h +++ b/src/lib/arch/bytes.h @@ -129,7 +129,7 @@ tor_ntohll(uint64_t a) { return a; } -#else +#else /* !(defined(WORDS_BIGENDIAN)) */ static inline uint16_t tor_htons(uint16_t a) { @@ -177,6 +177,6 @@ tor_ntohll(uint64_t a) { return tor_htonll(a); } -#endif +#endif /* defined(WORDS_BIGENDIAN) */ -#endif +#endif /* !defined(TOR_BYTES_H) */ diff --git a/src/lib/arch/include.am b/src/lib/arch/include.am index f92ee9222f..c5926c6330 100644 --- a/src/lib/arch/include.am +++ b/src/lib/arch/include.am @@ -1,3 +1,4 @@ +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/arch/bytes.h diff --git a/src/lib/buf/include.am b/src/lib/buf/include.am index 3338c3dbdb..27430d1d38 100644 --- a/src/lib/buf/include.am +++ b/src/lib/buf/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-buf-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_buf_a_SOURCES = \ src/lib/buf/buffers.c @@ -13,5 +14,6 @@ src_lib_libtor_buf_testing_a_SOURCES = \ src_lib_libtor_buf_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_buf_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/buf/buffers.h diff --git a/src/lib/cc/compat_compiler.h b/src/lib/cc/compat_compiler.h index 3a0f307186..a8d1593214 100644 --- a/src/lib/cc/compat_compiler.h +++ b/src/lib/cc/compat_compiler.h @@ -217,4 +217,16 @@ /** Macro: Yields the number of elements in array x. */ #define ARRAY_LENGTH(x) ((sizeof(x)) / sizeof(x[0])) -#endif /* !defined(TOR_COMPAT_H) */ +/** + * "Eat" a semicolon that somebody puts at the end of a top-level macro. + * + * Frequently, we want to declare a macro that people will use at file scope, + * and we want to allow people to put a semicolon after the macro. + * + * This declaration of a struct can be repeated any number of times, and takes + * a trailing semicolon afterwards. + **/ +#define EAT_SEMICOLON \ + struct dummy_semicolon_eater__ + +#endif /* !defined(TOR_COMPAT_COMPILER_H) */ diff --git a/src/lib/cc/ctassert.h b/src/lib/cc/ctassert.h index e42976360f..bedf0b83a6 100644 --- a/src/lib/cc/ctassert.h +++ b/src/lib/cc/ctassert.h @@ -22,7 +22,7 @@ /* If C11 is available, just use _Static_assert. */ #define CTASSERT(x) _Static_assert((x), #x) -#else +#else /* !(__STDC_VERSION__ >= 201112L) */ /* * If C11 is not available, expand __COUNTER__, or __INCLUDE_LEVEL__ @@ -42,12 +42,12 @@ #else /* hope it's unique enough */ #define CTASSERT(x) CTASSERT_EXPN((x), l, __LINE__) -#endif +#endif /* defined(__COUNTER__) || ... */ #define CTASSERT_EXPN(x, a, b) CTASSERT_DECL(x, a, b) #define CTASSERT_DECL(x, a, b) \ typedef char tor_ctassert_##a##_##b[(x) ? 1 : -1] ATTR_UNUSED -#endif +#endif /* __STDC_VERSION__ >= 201112L */ #endif /* !defined(TOR_CTASSERT_H) */ diff --git a/src/lib/cc/include.am b/src/lib/cc/include.am index 52cf8a9f72..1aa722dd82 100644 --- a/src/lib/cc/include.am +++ b/src/lib/cc/include.am @@ -1,4 +1,5 @@ +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/cc/compat_compiler.h \ src/lib/cc/ctassert.h \ diff --git a/src/lib/cc/torint.h b/src/lib/cc/torint.h index c9b2d329f2..523f378ed7 100644 --- a/src/lib/cc/torint.h +++ b/src/lib/cc/torint.h @@ -96,9 +96,9 @@ typedef int32_t ssize_t; # else # define TOR_PRIuSZ PRIu32 # endif -#else +#else /* !(defined(_WIN32)) */ # define TOR_PRIuSZ "zu" -#endif +#endif /* defined(_WIN32) */ #ifdef _WIN32 # ifdef _WIN64 @@ -106,9 +106,9 @@ typedef int32_t ssize_t; # else # define TOR_PRIdSZ PRId32 # endif -#else +#else /* !(defined(_WIN32)) */ # define TOR_PRIdSZ "zd" -#endif +#endif /* defined(_WIN32) */ #ifndef SSIZE_MAX #if (SIZEOF_SIZE_T == 4) @@ -125,4 +125,13 @@ typedef int32_t ssize_t; /** Any size_t larger than this amount is likely to be an underflow. */ #define SIZE_T_CEILING ((size_t)(SSIZE_MAX-16)) +#if SIZEOF_INT > SIZEOF_VOID_P +#error "sizeof(int) > sizeof(void *) - Tor cannot be built on this platform!" +#endif + +#if SIZEOF_UNSIGNED_INT > SIZEOF_VOID_P +#error "sizeof(unsigned int) > sizeof(void *) - Tor cannot be built on this \ +platform!" +#endif + #endif /* !defined(TOR_TORINT_H) */ diff --git a/src/lib/compress/compress_zstd.c b/src/lib/compress/compress_zstd.c index 45d0d4d602..a99ea67e0b 100644 --- a/src/lib/compress/compress_zstd.c +++ b/src/lib/compress/compress_zstd.c @@ -25,7 +25,7 @@ * all invocations of zstd's static-only functions in a check to make sure * that the compile-time version matches the run-time version. */ #define ZSTD_STATIC_LINKING_ONLY -#endif +#endif /* defined(ENABLE_ZSTD_ADVANCED_APIS) */ #ifdef HAVE_ZSTD #ifdef HAVE_CFLAG_WUNUSED_CONST_VARIABLE @@ -35,7 +35,7 @@ DISABLE_GCC_WARNING(unused-const-variable) #ifdef HAVE_CFLAG_WUNUSED_CONST_VARIABLE ENABLE_GCC_WARNING(unused-const-variable) #endif -#endif +#endif /* defined(HAVE_ZSTD) */ /** Total number of bytes allocated for Zstandard state. */ static atomic_counter_t total_zstd_allocation; @@ -77,7 +77,7 @@ tor_zstd_format_version(char *buf, size_t buflen, unsigned version_number) version_number / 100 % 100, version_number % 100); } -#endif +#endif /* defined(HAVE_ZSTD) */ #define VERSION_STR_MAX_LEN 16 /* more than enough space for 99.99.99 */ @@ -125,9 +125,9 @@ tor_zstd_can_use_static_apis(void) } #endif return (ZSTD_VERSION_NUMBER == ZSTD_versionNumber()); -#else +#else /* !(defined(ZSTD_STATIC_LINKING_ONLY) && defined(HAVE_ZSTD)) */ return 0; -#endif +#endif /* defined(ZSTD_STATIC_LINKING_ONLY) && defined(HAVE_ZSTD) */ } /** Internal Zstandard state for incremental compression/decompression. @@ -237,7 +237,7 @@ tor_zstd_state_size_precalc(int compress, int preset) #endif } } -#endif +#endif /* defined(ZSTD_STATIC_LINKING_ONLY) */ return tor_zstd_state_size_precalc_fake(compress, preset); } #endif /* defined(HAVE_ZSTD) */ @@ -527,7 +527,7 @@ tor_zstd_warn_if_version_mismatched(void) "For safety, we'll avoid using advanced zstd functionality.", header_version, runtime_version); } -#endif +#endif /* defined(HAVE_ZSTD) && defined(ENABLE_ZSTD_ADVANCED_APIS) */ } #ifdef TOR_UNIT_TESTS @@ -538,4 +538,4 @@ tor_zstd_set_static_apis_disabled_for_testing(int disabled) { static_apis_disable_for_testing = disabled; } -#endif +#endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/lib/compress/include.am b/src/lib/compress/include.am index b952779578..60dd447d4e 100644 --- a/src/lib/compress/include.am +++ b/src/lib/compress/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-compress-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_compress_a_SOURCES = \ src/lib/compress/compress.c \ src/lib/compress/compress_buf.c \ @@ -18,6 +19,7 @@ src_lib_libtor_compress_testing_a_SOURCES = \ src_lib_libtor_compress_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_compress_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/compress/compress.h \ src/lib/compress/compress_lzma.h \ diff --git a/src/lib/container/bitarray.h b/src/lib/container/bitarray.h index 910d5fea65..45992796af 100644 --- a/src/lib/container/bitarray.h +++ b/src/lib/container/bitarray.h @@ -83,4 +83,4 @@ bitarray_is_set(bitarray_t *b, int bit) return b[bit >> BITARRAY_SHIFT] & (1u << (bit & BITARRAY_MASK)); } -#endif /* !defined(TOR_CONTAINER_H) */ +#endif /* !defined(TOR_BITARRAY_H) */ diff --git a/src/lib/container/include.am b/src/lib/container/include.am index 032e4033da..00d7b8e587 100644 --- a/src/lib/container/include.am +++ b/src/lib/container/include.am @@ -5,9 +5,11 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-container-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_container_a_SOURCES = \ src/lib/container/bloomfilt.c \ src/lib/container/map.c \ + src/lib/container/namemap.c \ src/lib/container/order.c \ src/lib/container/smartlist.c @@ -16,10 +18,13 @@ src_lib_libtor_container_testing_a_SOURCES = \ src_lib_libtor_container_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_container_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/container/bitarray.h \ src/lib/container/bloomfilt.h \ src/lib/container/handles.h \ src/lib/container/map.h \ + src/lib/container/namemap.h \ + src/lib/container/namemap_st.h \ src/lib/container/order.h \ src/lib/container/smartlist.h diff --git a/src/lib/container/map.h b/src/lib/container/map.h index d61b1ec18f..9da1d3072c 100644 --- a/src/lib/container/map.h +++ b/src/lib/container/map.h @@ -258,4 +258,4 @@ void* strmap_remove_lc(strmap_t *map, const char *key); return digestmap_iter_done((digestmap_iter_t*)iter); \ } -#endif /* !defined(TOR_CONTAINER_H) */ +#endif /* !defined(TOR_MAP_H) */ diff --git a/src/lib/container/namemap.c b/src/lib/container/namemap.c new file mode 100644 index 0000000000..a90057b32c --- /dev/null +++ b/src/lib/container/namemap.c @@ -0,0 +1,184 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/container/smartlist.h" +#include "lib/container/namemap.h" +#include "lib/container/namemap_st.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/malloc.h" +#include "lib/string/printf.h" + +#include "ext/siphash.h" + +#include + +/** Helper for namemap hashtable implementation: compare two entries. */ +static inline int +mapped_name_eq(const mapped_name_t *a, const mapped_name_t *b) +{ + return !strcmp(a->name, b->name); +} + +/** Helper for namemap hashtable implementation: hash an entry. */ +static inline unsigned +mapped_name_hash(const mapped_name_t *a) +{ + return (unsigned) siphash24g(a->name, strlen(a->name)); +} + +HT_PROTOTYPE(namemap_ht, mapped_name_t, node, mapped_name_hash, + mapped_name_eq) +HT_GENERATE2(namemap_ht, mapped_name_t, node, mapped_name_hash, + mapped_name_eq, 0.6, tor_reallocarray_, tor_free_) + +/** Set up an uninitialized map. */ +void +namemap_init(namemap_t *map) +{ + memset(map, 0, sizeof(*map)); + HT_INIT(namemap_ht, &map->ht); + map->names = smartlist_new(); +} + +/** Return the name that map associates with a given id, or + * NULL if there is no such name. */ +const char * +namemap_get_name(const namemap_t *map, unsigned id) +{ + if (map->names && id < (unsigned)smartlist_len(map->names)) { + mapped_name_t *name = smartlist_get(map->names, (int)id); + return name->name; + } else { + return NULL; + } +} + +/** + * Return the name that map associates with a given id, or a + * pointer to a statically allocated string describing the value of id + * if no such name exists. + **/ +const char * +namemap_fmt_name(const namemap_t *map, unsigned id) +{ + static char buf[32]; + + const char *name = namemap_get_name(map, id); + if (name) + return name; + + tor_snprintf(buf, sizeof(buf), "{%u}", id); + + return buf; +} + +/** + * Helper: As namemap_get_id(), but requires that name is + * namelen charaters long, and that namelen is no more than + * MAX_NAMEMAP_NAME_LEN. + */ +static unsigned +namemap_get_id_unchecked(const namemap_t *map, + const char *name, + size_t namelen) +{ + union { + mapped_name_t n; + char storage[MAX_NAMEMAP_NAME_LEN + sizeof(mapped_name_t) + 1]; + } u; + memcpy(u.n.name, name, namelen); + u.n.name[namelen] = 0; + const mapped_name_t *found = HT_FIND(namemap_ht, &map->ht, &u.n); + if (found) { + tor_assert(map->names); + tor_assert(smartlist_get(map->names, found->intval) == found); + return found->intval; + } + + return NAMEMAP_ERR; +} + +/** + * Return the identifier currently associated by map with the name + * name, or NAMEMAP_ERR if no such identifier exists. + **/ +unsigned +namemap_get_id(const namemap_t *map, + const char *name) +{ + size_t namelen = strlen(name); + if (namelen > MAX_NAMEMAP_NAME_LEN) { + return NAMEMAP_ERR; + } + + return namemap_get_id_unchecked(map, name, namelen); +} + +/** + * Return the identifier associated by map with the name + * name, allocating a new identifier in map if none exists. + * + * Return NAMEMAP_ERR if name is too long, or if there are no more + * identifiers we can allocate. + **/ +unsigned +namemap_get_or_create_id(namemap_t *map, + const char *name) +{ + size_t namelen = strlen(name); + if (namelen > MAX_NAMEMAP_NAME_LEN) { + return NAMEMAP_ERR; + } + + if (PREDICT_UNLIKELY(map->names == NULL)) + map->names = smartlist_new(); + + unsigned found = namemap_get_id_unchecked(map, name, namelen); + if (found != NAMEMAP_ERR) + return found; + + unsigned new_id = (unsigned)smartlist_len(map->names); + if (new_id == NAMEMAP_ERR) + return NAMEMAP_ERR; /* Can't allocate any more. */ + + mapped_name_t *insert = tor_malloc_zero( + offsetof(mapped_name_t, name) + namelen + 1); + memcpy(insert->name, name, namelen+1); + insert->intval = new_id; + + HT_INSERT(namemap_ht, &map->ht, insert); + smartlist_add(map->names, insert); + + return new_id; +} + +/** Return the number of entries in 'names' */ +size_t +namemap_get_size(const namemap_t *map) +{ + if (PREDICT_UNLIKELY(map->names == NULL)) + return 0; + + return smartlist_len(map->names); +} + +/** + * Release all storage held in map. + */ +void +namemap_clear(namemap_t *map) +{ + if (!map) + return; + + HT_CLEAR(namemap_ht, &map->ht); + if (map->names) { + SMARTLIST_FOREACH(map->names, mapped_name_t *, n, + tor_free(n)); + smartlist_free(map->names); + } + memset(map, 0, sizeof(*map)); +} diff --git a/src/lib/container/namemap.h b/src/lib/container/namemap.h new file mode 100644 index 0000000000..b96bc13f3a --- /dev/null +++ b/src/lib/container/namemap.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_NAMEMAP_H +#define TOR_NAMEMAP_H + +/** + * \file namemap.h + * + * \brief Header for namemap.c + **/ + +#include "lib/cc/compat_compiler.h" +#include "ext/ht.h" + +#include + +typedef struct namemap_t namemap_t; + +/** Returned in place of an identifier when an error occurs. */ +#define NAMEMAP_ERR UINT_MAX + +void namemap_init(namemap_t *map); +const char *namemap_get_name(const namemap_t *map, unsigned id); +const char *namemap_fmt_name(const namemap_t *map, unsigned id); +unsigned namemap_get_id(const namemap_t *map, + const char *name); +unsigned namemap_get_or_create_id(namemap_t *map, + const char *name); +size_t namemap_get_size(const namemap_t *map); +void namemap_clear(namemap_t *map); + +#endif /* !defined(TOR_NAMEMAP_H) */ diff --git a/src/lib/container/namemap_st.h b/src/lib/container/namemap_st.h new file mode 100644 index 0000000000..5008fd5855 --- /dev/null +++ b/src/lib/container/namemap_st.h @@ -0,0 +1,34 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef NAMEMAP_ST_H +#define NAMEMAP_ST_H + +#include "lib/cc/compat_compiler.h" +#include "ext/ht.h" + +struct smartlist_t; + +/** Longest allowed name that's allowed in a namemap_t. */ +#define MAX_NAMEMAP_NAME_LEN 128 + +/** An entry inside a namemap_t. Maps a string to a numeric identifier. */ +typedef struct mapped_name_t { + HT_ENTRY(mapped_name_t) node; + unsigned intval; + char name[FLEXIBLE_ARRAY_MEMBER]; +} mapped_name_t; + +/** A structure that allocates small numeric identifiers for names and maps + * back and forth between them. */ +struct namemap_t { + HT_HEAD(namemap_ht, mapped_name_t) ht; + struct smartlist_t *names; +}; + +/** Macro to initialize a namemap. */ +#define NAMEMAP_INIT() { HT_INITIALIZER(), NULL } + +#endif /* !defined(NAMEMAP_ST_H) */ diff --git a/src/lib/container/order.h b/src/lib/container/order.h index a176d6d8a6..3f2fd054a0 100644 --- a/src/lib/container/order.h +++ b/src/lib/container/order.h @@ -57,4 +57,4 @@ third_quartile_uint32(uint32_t *array, int n_elements) return find_nth_uint32(array, n_elements, (n_elements*3)/4); } -#endif /* !defined(TOR_CONTAINER_H) */ +#endif /* !defined(TOR_ORDER_H) */ diff --git a/src/lib/container/smartlist.h b/src/lib/container/smartlist.h index 77682db03e..81b0151433 100644 --- a/src/lib/container/smartlist.h +++ b/src/lib/container/smartlist.h @@ -165,4 +165,4 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join, } \ STMT_END -#endif /* !defined(TOR_CONTAINER_H) */ +#endif /* !defined(TOR_SMARTLIST_H) */ diff --git a/src/lib/crypt_ops/crypto_cipher.h b/src/lib/crypt_ops/crypto_cipher.h index cc4fbf7a41..88d63c1df2 100644 --- a/src/lib/crypt_ops/crypto_cipher.h +++ b/src/lib/crypt_ops/crypto_cipher.h @@ -54,4 +54,4 @@ int crypto_cipher_decrypt_with_iv(const char *key, char *to, size_t tolen, const char *from, size_t fromlen); -#endif /* !defined(TOR_CRYPTO_H) */ +#endif /* !defined(TOR_CRYPTO_CIPHER_H) */ diff --git a/src/lib/crypt_ops/crypto_curve25519.h b/src/lib/crypt_ops/crypto_curve25519.h index 061a7a3505..cd23169cd5 100644 --- a/src/lib/crypt_ops/crypto_curve25519.h +++ b/src/lib/crypt_ops/crypto_curve25519.h @@ -76,8 +76,8 @@ STATIC int curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret); int curve25519_public_from_base64(curve25519_public_key_t *pkey, const char *input); -int curve25519_public_to_base64(char *output, - const curve25519_public_key_t *pkey); +void curve25519_public_to_base64(char *output, + const curve25519_public_key_t *pkey); void curve25519_set_impl_params(int use_ed); void curve25519_init(void); diff --git a/src/lib/crypt_ops/crypto_dh_openssl.c b/src/lib/crypt_ops/crypto_dh_openssl.c index 8c6388fd5d..75cee1b596 100644 --- a/src/lib/crypt_ops/crypto_dh_openssl.c +++ b/src/lib/crypt_ops/crypto_dh_openssl.c @@ -34,7 +34,7 @@ static int tor_check_dh_key(int severity, const BIGNUM *bn); struct crypto_dh_t { DH *dh; /**< The openssl DH object */ }; -#endif +#endif /* !defined(ENABLE_NSS) */ static DH *new_openssl_dh_from_params(BIGNUM *p, BIGNUM *g); @@ -100,7 +100,7 @@ crypto_validate_dh_params(const BIGNUM *p, const BIGNUM *g) DH_free(dh); return ret; } -#endif +#endif /* 0 */ /** * Helper: convert hex to a bignum, and return it. Assert that the @@ -202,7 +202,7 @@ crypto_dh_new(int dh_type) tor_free(res); // sets res to NULL. return res; } -#endif +#endif /* !defined(ENABLE_NSS) */ /** Create and return a new openssl DH from a given prime and generator. */ static DH * @@ -461,7 +461,7 @@ crypto_dh_free_(crypto_dh_t *dh) DH_free(dh->dh); tor_free(dh); } -#endif +#endif /* !defined(ENABLE_NSS) */ void crypto_dh_free_all_openssl(void) diff --git a/src/lib/crypt_ops/crypto_digest.c b/src/lib/crypt_ops/crypto_digest.c index 26f06c6c79..64a7d2d52c 100644 --- a/src/lib/crypt_ops/crypto_digest.c +++ b/src/lib/crypt_ops/crypto_digest.c @@ -23,171 +23,6 @@ #include "lib/arch/bytes.h" -#ifdef ENABLE_NSS -DISABLE_GCC_WARNING(strict-prototypes) -#include -ENABLE_GCC_WARNING(strict-prototypes) -#else - -#include "lib/crypt_ops/crypto_openssl_mgt.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include -#include - -ENABLE_GCC_WARNING(redundant-decls) -#endif - -#ifdef ENABLE_NSS -/** - * Convert a digest_algorithm_t (used by tor) to a HashType (used by NSS). - * On failure, return SEC_OID_UNKNOWN. */ -static SECOidTag -digest_alg_to_nss_oid(digest_algorithm_t alg) -{ - switch (alg) { - case DIGEST_SHA1: return SEC_OID_SHA1; - case DIGEST_SHA256: return SEC_OID_SHA256; - case DIGEST_SHA512: return SEC_OID_SHA512; - case DIGEST_SHA3_256: /* Fall through */ - case DIGEST_SHA3_512: /* Fall through */ - default: - return SEC_OID_UNKNOWN; - } -} - -/* Helper: get an unkeyed digest via pk11wrap */ -static int -digest_nss_internal(SECOidTag alg, - char *digest, unsigned len_out, - const char *msg, size_t msg_len) -{ - if (alg == SEC_OID_UNKNOWN) - return -1; - tor_assert(msg_len <= UINT_MAX); - - int rv = -1; - SECStatus s; - PK11Context *ctx = PK11_CreateDigestContext(alg); - if (!ctx) - return -1; - - s = PK11_DigestBegin(ctx); - if (s != SECSuccess) - goto done; - - s = PK11_DigestOp(ctx, (const unsigned char *)msg, (unsigned int)msg_len); - if (s != SECSuccess) - goto done; - - unsigned int len = 0; - s = PK11_DigestFinal(ctx, (unsigned char *)digest, &len, len_out); - if (s != SECSuccess) - goto done; - - rv = 0; - done: - PK11_DestroyContext(ctx, PR_TRUE); - return rv; -} - -/** True iff alg is implemented in our crypto library, and we want to use that - * implementation */ -static bool -library_supports_digest(digest_algorithm_t alg) -{ - switch (alg) { - case DIGEST_SHA1: /* Fall through */ - case DIGEST_SHA256: /* Fall through */ - case DIGEST_SHA512: /* Fall through */ - return true; - case DIGEST_SHA3_256: /* Fall through */ - case DIGEST_SHA3_512: /* Fall through */ - default: - return false; - } -} -#endif - -/* Crypto digest functions */ - -/** Compute the SHA1 digest of the len bytes on data stored in - * m. Write the DIGEST_LEN byte result into digest. - * Return 0 on success, -1 on failure. - */ -MOCK_IMPL(int, -crypto_digest,(char *digest, const char *m, size_t len)) -{ - tor_assert(m); - tor_assert(digest); -#ifdef ENABLE_NSS - return digest_nss_internal(SEC_OID_SHA1, digest, DIGEST_LEN, m, len); -#else - if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL) { - return -1; - } -#endif - return 0; -} - -/** Compute a 256-bit digest of len bytes in data stored in m, - * using the algorithm algorithm. Write the DIGEST_LEN256-byte result - * into digest. Return 0 on success, -1 on failure. */ -int -crypto_digest256(char *digest, const char *m, size_t len, - digest_algorithm_t algorithm) -{ - tor_assert(m); - tor_assert(digest); - tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); - - int ret = 0; - if (algorithm == DIGEST_SHA256) { -#ifdef ENABLE_NSS - return digest_nss_internal(SEC_OID_SHA256, digest, DIGEST256_LEN, m, len); -#else - ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL); -#endif - } else { - ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len) - > -1); - } - - if (!ret) - return -1; - return 0; -} - -/** Compute a 512-bit digest of len bytes in data stored in m, - * using the algorithm algorithm. Write the DIGEST_LEN512-byte result - * into digest. Return 0 on success, -1 on failure. */ -int -crypto_digest512(char *digest, const char *m, size_t len, - digest_algorithm_t algorithm) -{ - tor_assert(m); - tor_assert(digest); - tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); - - int ret = 0; - if (algorithm == DIGEST_SHA512) { -#ifdef ENABLE_NSS - return digest_nss_internal(SEC_OID_SHA512, digest, DIGEST512_LEN, m, len); -#else - ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest) - != NULL); -#endif - } else { - ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len) - > -1); - } - - if (!ret) - return -1; - return 0; -} - /** Set the common_digests_t in ds_out to contain every digest on the * len bytes in m that we know how to compute. Return 0 on * success, -1 on failure. */ @@ -267,485 +102,6 @@ crypto_digest_algorithm_get_length(digest_algorithm_t alg) } } -/** Intermediate information about the digest of a stream of data. */ -struct crypto_digest_t { - digest_algorithm_t algorithm; /**< Which algorithm is in use? */ - /** State for the digest we're using. Only one member of the - * union is usable, depending on the value of algorithm. Note also - * that space for other members might not even be allocated! - */ - union { -#ifdef ENABLE_NSS - PK11Context *ctx; -#else - SHA_CTX sha1; /**< state for SHA1 */ - SHA256_CTX sha2; /**< state for SHA256 */ - SHA512_CTX sha512; /**< state for SHA512 */ -#endif - keccak_state sha3; /**< state for SHA3-[256,512] */ - } d; -}; - -#ifdef TOR_UNIT_TESTS - -digest_algorithm_t -crypto_digest_get_algorithm(crypto_digest_t *digest) -{ - tor_assert(digest); - - return digest->algorithm; -} - -#endif /* defined(TOR_UNIT_TESTS) */ - -/** - * Return the number of bytes we need to malloc in order to get a - * crypto_digest_t for alg, or the number of bytes we need to wipe - * when we free one. - */ -static size_t -crypto_digest_alloc_bytes(digest_algorithm_t alg) -{ - /* Helper: returns the number of bytes in the 'f' field of 'st' */ -#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f )) - /* Gives the length of crypto_digest_t through the end of the field 'd' */ -#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \ - STRUCT_FIELD_SIZE(crypto_digest_t, f)) - switch (alg) { -#ifdef ENABLE_NSS - case DIGEST_SHA1: /* Fall through */ - case DIGEST_SHA256: /* Fall through */ - case DIGEST_SHA512: - return END_OF_FIELD(d.ctx); -#else - case DIGEST_SHA1: - return END_OF_FIELD(d.sha1); - case DIGEST_SHA256: - return END_OF_FIELD(d.sha2); - case DIGEST_SHA512: - return END_OF_FIELD(d.sha512); -#endif - case DIGEST_SHA3_256: - case DIGEST_SHA3_512: - return END_OF_FIELD(d.sha3); - default: - tor_assert(0); // LCOV_EXCL_LINE - return 0; // LCOV_EXCL_LINE - } -#undef END_OF_FIELD -#undef STRUCT_FIELD_SIZE -} - -/** - * Internal function: create and return a new digest object for 'algorithm'. - * Does not typecheck the algorithm. - */ -static crypto_digest_t * -crypto_digest_new_internal(digest_algorithm_t algorithm) -{ - crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm)); - r->algorithm = algorithm; - - switch (algorithm) - { -#ifdef ENABLE_NSS - case DIGEST_SHA1: /* fall through */ - case DIGEST_SHA256: /* fall through */ - case DIGEST_SHA512: - r->d.ctx = PK11_CreateDigestContext(digest_alg_to_nss_oid(algorithm)); - if (BUG(!r->d.ctx)) { - tor_free(r); - return NULL; - } - if (BUG(SECSuccess != PK11_DigestBegin(r->d.ctx))) { - crypto_digest_free(r); - return NULL; - } - break; -#else - case DIGEST_SHA1: - SHA1_Init(&r->d.sha1); - break; - case DIGEST_SHA256: - SHA256_Init(&r->d.sha2); - break; - case DIGEST_SHA512: - SHA512_Init(&r->d.sha512); - break; -#endif - case DIGEST_SHA3_256: - keccak_digest_init(&r->d.sha3, 256); - break; - case DIGEST_SHA3_512: - keccak_digest_init(&r->d.sha3, 512); - break; - default: - tor_assert_unreached(); - } - - return r; -} - -/** Allocate and return a new digest object to compute SHA1 digests. - */ -crypto_digest_t * -crypto_digest_new(void) -{ - return crypto_digest_new_internal(DIGEST_SHA1); -} - -/** Allocate and return a new digest object to compute 256-bit digests - * using algorithm. - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest256_new` - * C_RUST_COUPLED: `crypto::digest::Sha256::default` - */ -crypto_digest_t * -crypto_digest256_new(digest_algorithm_t algorithm) -{ - tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); - return crypto_digest_new_internal(algorithm); -} - -/** Allocate and return a new digest object to compute 512-bit digests - * using algorithm. */ -crypto_digest_t * -crypto_digest512_new(digest_algorithm_t algorithm) -{ - tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); - return crypto_digest_new_internal(algorithm); -} - -/** Deallocate a digest object. - */ -void -crypto_digest_free_(crypto_digest_t *digest) -{ - if (!digest) - return; -#ifdef ENABLE_NSS - if (library_supports_digest(digest->algorithm)) { - PK11_DestroyContext(digest->d.ctx, PR_TRUE); - } -#endif - size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); - memwipe(digest, 0, bytes); - tor_free(digest); -} - -/** Add len bytes from data to the digest object. - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_add_bytess` - * C_RUST_COUPLED: `crypto::digest::Sha256::process` - */ -void -crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, - size_t len) -{ - tor_assert(digest); - tor_assert(data); - /* Using the SHA*_*() calls directly means we don't support doing - * SHA in hardware. But so far the delay of getting the question - * to the hardware, and hearing the answer, is likely higher than - * just doing it ourselves. Hashes are fast. - */ - switch (digest->algorithm) { -#ifdef ENABLE_NSS - case DIGEST_SHA1: /* fall through */ - case DIGEST_SHA256: /* fall through */ - case DIGEST_SHA512: - tor_assert(len <= UINT_MAX); - SECStatus s = PK11_DigestOp(digest->d.ctx, - (const unsigned char *)data, - (unsigned int)len); - tor_assert(s == SECSuccess); - break; -#else - case DIGEST_SHA1: - SHA1_Update(&digest->d.sha1, (void*)data, len); - break; - case DIGEST_SHA256: - SHA256_Update(&digest->d.sha2, (void*)data, len); - break; - case DIGEST_SHA512: - SHA512_Update(&digest->d.sha512, (void*)data, len); - break; -#endif - case DIGEST_SHA3_256: /* FALLSTHROUGH */ - case DIGEST_SHA3_512: - keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len); - break; - default: - /* LCOV_EXCL_START */ - tor_fragile_assert(); - break; - /* LCOV_EXCL_STOP */ - } -} - -/** Compute the hash of the data that has been passed to the digest - * object; write the first out_len bytes of the result to out. - * out_len must be \<= DIGEST512_LEN. - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_get_digest` - * C_RUST_COUPLED: `impl digest::FixedOutput for Sha256` - */ -void -crypto_digest_get_digest(crypto_digest_t *digest, - char *out, size_t out_len) -{ - unsigned char r[DIGEST512_LEN]; - tor_assert(digest); - tor_assert(out); - tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm)); - - /* The SHA-3 code handles copying into a temporary ctx, and also can handle - * short output buffers by truncating appropriately. */ - if (digest->algorithm == DIGEST_SHA3_256 || - digest->algorithm == DIGEST_SHA3_512) { - keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len); - return; - } - -#ifdef ENABLE_NSS - /* Copy into a temporary buffer since DigestFinal (alters) the context */ - unsigned char buf[1024]; - unsigned int saved_len = 0; - unsigned rlen; - unsigned char *saved = PK11_SaveContextAlloc(digest->d.ctx, - buf, sizeof(buf), - &saved_len); - tor_assert(saved); - SECStatus s = PK11_DigestFinal(digest->d.ctx, r, &rlen, sizeof(r)); - tor_assert(s == SECSuccess); - tor_assert(rlen >= out_len); - s = PK11_RestoreContext(digest->d.ctx, saved, saved_len); - tor_assert(s == SECSuccess); - if (saved != buf) { - PORT_ZFree(saved, saved_len); - } -#else - const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); - crypto_digest_t tmpenv; - /* memcpy into a temporary ctx, since SHA*_Final clears the context */ - memcpy(&tmpenv, digest, alloc_bytes); - switch (digest->algorithm) { - case DIGEST_SHA1: - SHA1_Final(r, &tmpenv.d.sha1); - break; - case DIGEST_SHA256: - SHA256_Final(r, &tmpenv.d.sha2); - break; - case DIGEST_SHA512: - SHA512_Final(r, &tmpenv.d.sha512); - break; -//LCOV_EXCL_START - case DIGEST_SHA3_256: /* FALLSTHROUGH */ - case DIGEST_SHA3_512: - default: - log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm); - /* This is fatal, because it should never happen. */ - tor_assert_unreached(); - break; -//LCOV_EXCL_STOP - } -#endif - memcpy(out, r, out_len); - memwipe(r, 0, sizeof(r)); -} - -/** Allocate and return a new digest object with the same state as - * digest - * - * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_dup` - * C_RUST_COUPLED: `impl Clone for crypto::digest::Sha256` - */ -crypto_digest_t * -crypto_digest_dup(const crypto_digest_t *digest) -{ - tor_assert(digest); - const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); - crypto_digest_t *result = tor_memdup(digest, alloc_bytes); -#ifdef ENABLE_NSS - if (library_supports_digest(digest->algorithm)) { - result->d.ctx = PK11_CloneContext(digest->d.ctx); - } -#endif - return result; -} - -/** Temporarily save the state of digest in checkpoint. - * Asserts that digest is a SHA1 digest object. - */ -void -crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint, - const crypto_digest_t *digest) -{ - const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); - tor_assert(bytes <= sizeof(checkpoint->mem)); -#ifdef ENABLE_NSS - if (library_supports_digest(digest->algorithm)) { - unsigned char *allocated; - allocated = PK11_SaveContextAlloc(digest->d.ctx, - (unsigned char *)checkpoint->mem, - sizeof(checkpoint->mem), - &checkpoint->bytes_used); - /* No allocation is allowed here. */ - tor_assert(allocated == checkpoint->mem); - return; - } -#endif - memcpy(checkpoint->mem, digest, bytes); -} - -/** Restore the state of digest from checkpoint. - * Asserts that digest is a SHA1 digest object. Requires that the - * state was previously stored with crypto_digest_checkpoint() */ -void -crypto_digest_restore(crypto_digest_t *digest, - const crypto_digest_checkpoint_t *checkpoint) -{ - const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); -#ifdef ENABLE_NSS - if (library_supports_digest(digest->algorithm)) { - SECStatus s = PK11_RestoreContext(digest->d.ctx, - (unsigned char *)checkpoint->mem, - checkpoint->bytes_used); - tor_assert(s == SECSuccess); - return; - } -#endif - memcpy(digest, checkpoint->mem, bytes); -} - -/** Replace the state of the digest object into with the state - * of the digest object from. Requires that 'into' and 'from' - * have the same digest type. - */ -void -crypto_digest_assign(crypto_digest_t *into, - const crypto_digest_t *from) -{ - tor_assert(into); - tor_assert(from); - tor_assert(into->algorithm == from->algorithm); - const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm); -#ifdef ENABLE_NSS - if (library_supports_digest(from->algorithm)) { - PK11_DestroyContext(into->d.ctx, PR_TRUE); - into->d.ctx = PK11_CloneContext(from->d.ctx); - return; - } -#endif - memcpy(into,from,alloc_bytes); -} - -/** Given a list of strings in lst, set the len_out-byte digest - * at digest_out to the hash of the concatenation of those strings, - * plus the optional string append, computed with the algorithm - * alg. - * out_len must be \<= DIGEST512_LEN. */ -void -crypto_digest_smartlist(char *digest_out, size_t len_out, - const smartlist_t *lst, - const char *append, - digest_algorithm_t alg) -{ - crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg); -} - -/** Given a list of strings in lst, set the len_out-byte digest - * at digest_out to the hash of the concatenation of: the - * optional string prepend, those strings, - * and the optional string append, computed with the algorithm - * alg. - * len_out must be \<= DIGEST512_LEN. */ -void -crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, - const char *prepend, - const smartlist_t *lst, - const char *append, - digest_algorithm_t alg) -{ - crypto_digest_t *d = crypto_digest_new_internal(alg); - if (prepend) - crypto_digest_add_bytes(d, prepend, strlen(prepend)); - SMARTLIST_FOREACH(lst, const char *, cp, - crypto_digest_add_bytes(d, cp, strlen(cp))); - if (append) - crypto_digest_add_bytes(d, append, strlen(append)); - crypto_digest_get_digest(d, digest_out, len_out); - crypto_digest_free(d); -} - -/** Compute the HMAC-SHA-256 of the msg_len bytes in msg, using - * the key of length key_len. Store the DIGEST256_LEN-byte - * result in hmac_out. Asserts on failure. - */ -void -crypto_hmac_sha256(char *hmac_out, - const char *key, size_t key_len, - const char *msg, size_t msg_len) -{ - /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */ - tor_assert(key_len < INT_MAX); - tor_assert(msg_len < INT_MAX); - tor_assert(hmac_out); -#ifdef ENABLE_NSS - PK11SlotInfo *slot = NULL; - PK11SymKey *symKey = NULL; - PK11Context *hmac = NULL; - - int ok = 0; - SECStatus s; - SECItem keyItem, paramItem; - keyItem.data = (unsigned char *)key; - keyItem.len = (unsigned)key_len; - paramItem.type = siBuffer; - paramItem.data = NULL; - paramItem.len = 0; - - slot = PK11_GetBestSlot(CKM_SHA256_HMAC, NULL); - if (!slot) - goto done; - symKey = PK11_ImportSymKey(slot, CKM_SHA256_HMAC, - PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL); - if (!symKey) - goto done; - - hmac = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, symKey, - ¶mItem); - if (!hmac) - goto done; - s = PK11_DigestBegin(hmac); - if (s != SECSuccess) - goto done; - s = PK11_DigestOp(hmac, (const unsigned char *)msg, (unsigned int)msg_len); - if (s != SECSuccess) - goto done; - unsigned int len=0; - s = PK11_DigestFinal(hmac, (unsigned char *)hmac_out, &len, DIGEST256_LEN); - if (s != SECSuccess || len != DIGEST256_LEN) - goto done; - ok = 1; - - done: - if (hmac) - PK11_DestroyContext(hmac, PR_TRUE); - if (symKey) - PK11_FreeSymKey(symKey); - if (slot) - PK11_FreeSlot(slot); - - tor_assert(ok); -#else - unsigned char *rv = NULL; - rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len, - (unsigned char*)hmac_out, NULL); - tor_assert(rv); -#endif -} - /** Compute a MAC using SHA3-256 of msg_len bytes in msg using a * key of length key_len and a salt of length * salt_len. Store the result of len_out bytes in in @@ -779,7 +135,23 @@ crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out, /** Internal state for a eXtendable-Output Function (XOF). */ struct crypto_xof_t { +#ifdef OPENSSL_HAS_SHAKE3_EVP + /* XXXX We can't enable this yet, because OpenSSL's + * DigestFinalXOF function can't be called repeatedly on the same + * XOF. + * + * We could in theory use the undocumented SHA3_absorb and SHA3_squeeze + * functions, but let's not mess with undocumented OpenSSL internals any + * more than we have to. + * + * We could also revise our XOF code so that it only allows a single + * squeeze operation; we don't require streaming squeeze operations + * outside the tests yet. + */ + EVP_MD_CTX *ctx; +#else /* !(defined(OPENSSL_HAS_SHAKE3_EVP)) */ keccak_state s; +#endif /* defined(OPENSSL_HAS_SHAKE3_EVP) */ }; /** Allocate a new XOF object backed by SHAKE-256. The security level @@ -792,7 +164,14 @@ crypto_xof_new(void) { crypto_xof_t *xof; xof = tor_malloc(sizeof(crypto_xof_t)); +#ifdef OPENSSL_HAS_SHAKE256 + xof->ctx = EVP_MD_CTX_new(); + tor_assert(xof->ctx); + int r = EVP_DigestInit(xof->ctx, EVP_shake256()); + tor_assert(r == 1); +#else /* !(defined(OPENSSL_HAS_SHAKE256)) */ keccak_xof_init(&xof->s, 256); +#endif /* defined(OPENSSL_HAS_SHAKE256) */ return xof; } @@ -803,8 +182,13 @@ crypto_xof_new(void) void crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len) { +#ifdef OPENSSL_HAS_SHAKE256 + int r = EVP_DigestUpdate(xof->ctx, data, len); + tor_assert(r == 1); +#else int i = keccak_xof_absorb(&xof->s, data, len); tor_assert(i == 0); +#endif /* defined(OPENSSL_HAS_SHAKE256) */ } /** Squeeze bytes out of a XOF object. Calling this routine will render @@ -813,8 +197,13 @@ crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len) void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len) { +#ifdef OPENSSL_HAS_SHAKE256 + int r = EVP_DigestFinalXOF(xof->ctx, out, len); + tor_assert(r == 1); +#else int i = keccak_xof_squeeze(&xof->s, out, len); tor_assert(i == 0); +#endif /* defined(OPENSSL_HAS_SHAKE256) */ } /** Cleanse and deallocate a XOF object. */ @@ -823,6 +212,34 @@ crypto_xof_free_(crypto_xof_t *xof) { if (!xof) return; +#ifdef OPENSSL_HAS_SHAKE256 + if (xof->ctx) + EVP_MD_CTX_free(xof->ctx); +#endif memwipe(xof, 0, sizeof(crypto_xof_t)); tor_free(xof); } + +/** Compute the XOF (SHAKE256) of a input_len bytes at input, + * putting output_len bytes at output. */ +void +crypto_xof(uint8_t *output, size_t output_len, + const uint8_t *input, size_t input_len) +{ +#ifdef OPENSSL_HAS_SHA3 + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + tor_assert(ctx); + int r = EVP_DigestInit(ctx, EVP_shake256()); + tor_assert(r == 1); + r = EVP_DigestUpdate(ctx, input, input_len); + tor_assert(r == 1); + r = EVP_DigestFinalXOF(ctx, output, output_len); + tor_assert(r == 1); + EVP_MD_CTX_free(ctx); +#else /* !(defined(OPENSSL_HAS_SHA3)) */ + crypto_xof_t *xof = crypto_xof_new(); + crypto_xof_add_bytes(xof, input, input_len); + crypto_xof_squeeze_bytes(xof, output, output_len); + crypto_xof_free(xof); +#endif /* defined(OPENSSL_HAS_SHA3) */ +} diff --git a/src/lib/crypt_ops/crypto_digest.h b/src/lib/crypt_ops/crypto_digest.h index 47e60ce617..5869db7800 100644 --- a/src/lib/crypt_ops/crypto_digest.h +++ b/src/lib/crypt_ops/crypto_digest.h @@ -124,6 +124,8 @@ void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len); void crypto_xof_free_(crypto_xof_t *xof); #define crypto_xof_free(xof) \ FREE_AND_NULL(crypto_xof_t, crypto_xof_free_, (xof)) +void crypto_xof(uint8_t *output, size_t output_len, + const uint8_t *input, size_t input_len); #ifdef TOR_UNIT_TESTS digest_algorithm_t crypto_digest_get_algorithm(crypto_digest_t *digest); diff --git a/src/lib/crypt_ops/crypto_digest_nss.c b/src/lib/crypt_ops/crypto_digest_nss.c new file mode 100644 index 0000000000..b73f0736fd --- /dev/null +++ b/src/lib/crypt_ops/crypto_digest_nss.c @@ -0,0 +1,560 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_digest_nss.c + * \brief Block of functions related with digest and xof utilities and + * operations (NSS specific implementations). + **/ + +#include "lib/container/smartlist.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/log/log.h" +#include "lib/log/util_bug.h" + +#include "keccak-tiny/keccak-tiny.h" + +#include +#include + +#include "lib/arch/bytes.h" + +DISABLE_GCC_WARNING(strict-prototypes) +#include +ENABLE_GCC_WARNING(strict-prototypes) + +/** + * Convert a digest_algorithm_t (used by tor) to a HashType (used by NSS). + * On failure, return SEC_OID_UNKNOWN. */ +static SECOidTag +digest_alg_to_nss_oid(digest_algorithm_t alg) +{ + switch (alg) { + case DIGEST_SHA1: return SEC_OID_SHA1; + case DIGEST_SHA256: return SEC_OID_SHA256; + case DIGEST_SHA512: return SEC_OID_SHA512; + case DIGEST_SHA3_256: /* Fall through */ + case DIGEST_SHA3_512: /* Fall through */ + default: + return SEC_OID_UNKNOWN; + } +} + +/* Helper: get an unkeyed digest via pk11wrap */ +static int +digest_nss_internal(SECOidTag alg, + char *digest, unsigned len_out, + const char *msg, size_t msg_len) +{ + if (alg == SEC_OID_UNKNOWN) + return -1; + tor_assert(msg_len <= UINT_MAX); + + int rv = -1; + SECStatus s; + PK11Context *ctx = PK11_CreateDigestContext(alg); + if (!ctx) + return -1; + + s = PK11_DigestBegin(ctx); + if (s != SECSuccess) + goto done; + + s = PK11_DigestOp(ctx, (const unsigned char *)msg, (unsigned int)msg_len); + if (s != SECSuccess) + goto done; + + unsigned int len = 0; + s = PK11_DigestFinal(ctx, (unsigned char *)digest, &len, len_out); + if (s != SECSuccess) + goto done; + + rv = 0; + done: + PK11_DestroyContext(ctx, PR_TRUE); + return rv; +} + +/** True iff alg is implemented in our crypto library, and we want to use that + * implementation */ +static bool +library_supports_digest(digest_algorithm_t alg) +{ + switch (alg) { + case DIGEST_SHA1: /* Fall through */ + case DIGEST_SHA256: /* Fall through */ + case DIGEST_SHA512: /* Fall through */ + return true; + case DIGEST_SHA3_256: /* Fall through */ + case DIGEST_SHA3_512: /* Fall through */ + default: + return false; + } +} + +/* Crypto digest functions */ + +/** Compute the SHA1 digest of the len bytes on data stored in + * m. Write the DIGEST_LEN byte result into digest. + * Return 0 on success, -1 on failure. + */ +MOCK_IMPL(int, +crypto_digest,(char *digest, const char *m, size_t len)) +{ + tor_assert(m); + tor_assert(digest); + return digest_nss_internal(SEC_OID_SHA1, digest, DIGEST_LEN, m, len); +} + +/** Compute a 256-bit digest of len bytes in data stored in m, + * using the algorithm algorithm. Write the DIGEST_LEN256-byte result + * into digest. Return 0 on success, -1 on failure. */ +int +crypto_digest256(char *digest, const char *m, size_t len, + digest_algorithm_t algorithm) +{ + tor_assert(m); + tor_assert(digest); + tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); + + int ret = 0; + if (algorithm == DIGEST_SHA256) { + return digest_nss_internal(SEC_OID_SHA256, digest, DIGEST256_LEN, m, len); + } else { + ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len) + > -1); + } + + if (!ret) + return -1; + return 0; +} + +/** Compute a 512-bit digest of len bytes in data stored in m, + * using the algorithm algorithm. Write the DIGEST_LEN512-byte result + * into digest. Return 0 on success, -1 on failure. */ +int +crypto_digest512(char *digest, const char *m, size_t len, + digest_algorithm_t algorithm) +{ + tor_assert(m); + tor_assert(digest); + tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); + + int ret = 0; + if (algorithm == DIGEST_SHA512) { + return digest_nss_internal(SEC_OID_SHA512, digest, DIGEST512_LEN, m, len); + } else { + ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len) + > -1); + } + + if (!ret) + return -1; + return 0; +} + +/** Intermediate information about the digest of a stream of data. */ +struct crypto_digest_t { + digest_algorithm_t algorithm; /**< Which algorithm is in use? */ + /** State for the digest we're using. Only one member of the + * union is usable, depending on the value of algorithm. Note also + * that space for other members might not even be allocated! + */ + union { + PK11Context *ctx; + keccak_state sha3; /**< state for SHA3-[256,512] */ + } d; +}; + +#ifdef TOR_UNIT_TESTS + +digest_algorithm_t +crypto_digest_get_algorithm(crypto_digest_t *digest) +{ + tor_assert(digest); + + return digest->algorithm; +} + +#endif /* defined(TOR_UNIT_TESTS) */ + +/** + * Return the number of bytes we need to malloc in order to get a + * crypto_digest_t for alg, or the number of bytes we need to wipe + * when we free one. + */ +static size_t +crypto_digest_alloc_bytes(digest_algorithm_t alg) +{ + /* Helper: returns the number of bytes in the 'f' field of 'st' */ +#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f )) + /* Gives the length of crypto_digest_t through the end of the field 'd' */ +#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \ + STRUCT_FIELD_SIZE(crypto_digest_t, f)) + switch (alg) { + case DIGEST_SHA1: /* Fall through */ + case DIGEST_SHA256: /* Fall through */ + case DIGEST_SHA512: + return END_OF_FIELD(d.ctx); + case DIGEST_SHA3_256: + case DIGEST_SHA3_512: + return END_OF_FIELD(d.sha3); + default: + tor_assert(0); // LCOV_EXCL_LINE + return 0; // LCOV_EXCL_LINE + } +#undef END_OF_FIELD +#undef STRUCT_FIELD_SIZE +} + +/** + * Internal function: create and return a new digest object for 'algorithm'. + * Does not typecheck the algorithm. + */ +static crypto_digest_t * +crypto_digest_new_internal(digest_algorithm_t algorithm) +{ + crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm)); + r->algorithm = algorithm; + + switch (algorithm) + { + case DIGEST_SHA1: /* fall through */ + case DIGEST_SHA256: /* fall through */ + case DIGEST_SHA512: + r->d.ctx = PK11_CreateDigestContext(digest_alg_to_nss_oid(algorithm)); + if (BUG(!r->d.ctx)) { + tor_free(r); + return NULL; + } + if (BUG(SECSuccess != PK11_DigestBegin(r->d.ctx))) { + crypto_digest_free(r); + return NULL; + } + break; + case DIGEST_SHA3_256: + keccak_digest_init(&r->d.sha3, 256); + break; + case DIGEST_SHA3_512: + keccak_digest_init(&r->d.sha3, 512); + break; + default: + tor_assert_unreached(); + } + + return r; +} + +/** Allocate and return a new digest object to compute SHA1 digests. + */ +crypto_digest_t * +crypto_digest_new(void) +{ + return crypto_digest_new_internal(DIGEST_SHA1); +} + +/** Allocate and return a new digest object to compute 256-bit digests + * using algorithm. + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest256_new` + * C_RUST_COUPLED: `crypto::digest::Sha256::default` + */ +crypto_digest_t * +crypto_digest256_new(digest_algorithm_t algorithm) +{ + tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); + return crypto_digest_new_internal(algorithm); +} + +/** Allocate and return a new digest object to compute 512-bit digests + * using algorithm. */ +crypto_digest_t * +crypto_digest512_new(digest_algorithm_t algorithm) +{ + tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); + return crypto_digest_new_internal(algorithm); +} + +/** Deallocate a digest object. + */ +void +crypto_digest_free_(crypto_digest_t *digest) +{ + if (!digest) + return; + if (library_supports_digest(digest->algorithm)) { + PK11_DestroyContext(digest->d.ctx, PR_TRUE); + } + size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); + memwipe(digest, 0, bytes); + tor_free(digest); +} + +/** Add len bytes from data to the digest object. + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_add_bytess` + * C_RUST_COUPLED: `crypto::digest::Sha256::process` + */ +void +crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, + size_t len) +{ + tor_assert(digest); + tor_assert(data); + /* Using the SHA*_*() calls directly means we don't support doing + * SHA in hardware. But so far the delay of getting the question + * to the hardware, and hearing the answer, is likely higher than + * just doing it ourselves. Hashes are fast. + */ + switch (digest->algorithm) { + case DIGEST_SHA1: /* fall through */ + case DIGEST_SHA256: /* fall through */ + case DIGEST_SHA512: + tor_assert(len <= UINT_MAX); + SECStatus s = PK11_DigestOp(digest->d.ctx, + (const unsigned char *)data, + (unsigned int)len); + tor_assert(s == SECSuccess); + break; + case DIGEST_SHA3_256: /* FALLSTHROUGH */ + case DIGEST_SHA3_512: + keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len); + break; + default: + /* LCOV_EXCL_START */ + tor_fragile_assert(); + break; + /* LCOV_EXCL_STOP */ + } +} + +/** Compute the hash of the data that has been passed to the digest + * object; write the first out_len bytes of the result to out. + * out_len must be \<= DIGEST512_LEN. + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_get_digest` + * C_RUST_COUPLED: `impl digest::FixedOutput for Sha256` + */ +void +crypto_digest_get_digest(crypto_digest_t *digest, + char *out, size_t out_len) +{ + unsigned char r[DIGEST512_LEN]; + tor_assert(digest); + tor_assert(out); + tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm)); + + /* The SHA-3 code handles copying into a temporary ctx, and also can handle + * short output buffers by truncating appropriately. */ + if (digest->algorithm == DIGEST_SHA3_256 || + digest->algorithm == DIGEST_SHA3_512) { + keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len); + return; + } + + /* Copy into a temporary buffer since DigestFinal (alters) the context */ + unsigned char buf[1024]; + unsigned int saved_len = 0; + unsigned rlen; + unsigned char *saved = PK11_SaveContextAlloc(digest->d.ctx, + buf, sizeof(buf), + &saved_len); + tor_assert(saved); + SECStatus s = PK11_DigestFinal(digest->d.ctx, r, &rlen, sizeof(r)); + tor_assert(s == SECSuccess); + tor_assert(rlen >= out_len); + s = PK11_RestoreContext(digest->d.ctx, saved, saved_len); + tor_assert(s == SECSuccess); + + if (saved != buf) { + PORT_ZFree(saved, saved_len); + } + memcpy(out, r, out_len); + memwipe(r, 0, sizeof(r)); +} + +/** Allocate and return a new digest object with the same state as + * digest + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_dup` + * C_RUST_COUPLED: `impl Clone for crypto::digest::Sha256` + */ +crypto_digest_t * +crypto_digest_dup(const crypto_digest_t *digest) +{ + tor_assert(digest); + const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); + crypto_digest_t *result = tor_memdup(digest, alloc_bytes); + + if (library_supports_digest(digest->algorithm)) { + result->d.ctx = PK11_CloneContext(digest->d.ctx); + } + + return result; +} + +/** Temporarily save the state of digest in checkpoint. + * Asserts that digest is a SHA1 digest object. + */ +void +crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint, + const crypto_digest_t *digest) +{ + const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); + tor_assert(bytes <= sizeof(checkpoint->mem)); + if (library_supports_digest(digest->algorithm)) { + unsigned char *allocated; + allocated = PK11_SaveContextAlloc(digest->d.ctx, + (unsigned char *)checkpoint->mem, + sizeof(checkpoint->mem), + &checkpoint->bytes_used); + /* No allocation is allowed here. */ + tor_assert(allocated == checkpoint->mem); + return; + } + memcpy(checkpoint->mem, digest, bytes); +} + +/** Restore the state of digest from checkpoint. + * Asserts that digest is a SHA1 digest object. Requires that the + * state was previously stored with crypto_digest_checkpoint() */ +void +crypto_digest_restore(crypto_digest_t *digest, + const crypto_digest_checkpoint_t *checkpoint) +{ + const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); + if (library_supports_digest(digest->algorithm)) { + SECStatus s = PK11_RestoreContext(digest->d.ctx, + (unsigned char *)checkpoint->mem, + checkpoint->bytes_used); + tor_assert(s == SECSuccess); + return; + } + memcpy(digest, checkpoint->mem, bytes); +} + +/** Replace the state of the digest object into with the state + * of the digest object from. Requires that 'into' and 'from' + * have the same digest type. + */ +void +crypto_digest_assign(crypto_digest_t *into, + const crypto_digest_t *from) +{ + tor_assert(into); + tor_assert(from); + tor_assert(into->algorithm == from->algorithm); + const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm); + if (library_supports_digest(from->algorithm)) { + PK11_DestroyContext(into->d.ctx, PR_TRUE); + into->d.ctx = PK11_CloneContext(from->d.ctx); + return; + } + memcpy(into,from,alloc_bytes); +} + +/** Given a list of strings in lst, set the len_out-byte digest + * at digest_out to the hash of the concatenation of those strings, + * plus the optional string append, computed with the algorithm + * alg. + * out_len must be \<= DIGEST512_LEN. */ +void +crypto_digest_smartlist(char *digest_out, size_t len_out, + const smartlist_t *lst, + const char *append, + digest_algorithm_t alg) +{ + crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg); +} + +/** Given a list of strings in lst, set the len_out-byte digest + * at digest_out to the hash of the concatenation of: the + * optional string prepend, those strings, + * and the optional string append, computed with the algorithm + * alg. + * len_out must be \<= DIGEST512_LEN. */ +void +crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, + const char *prepend, + const smartlist_t *lst, + const char *append, + digest_algorithm_t alg) +{ + crypto_digest_t *d = crypto_digest_new_internal(alg); + if (prepend) + crypto_digest_add_bytes(d, prepend, strlen(prepend)); + SMARTLIST_FOREACH(lst, const char *, cp, + crypto_digest_add_bytes(d, cp, strlen(cp))); + if (append) + crypto_digest_add_bytes(d, append, strlen(append)); + crypto_digest_get_digest(d, digest_out, len_out); + crypto_digest_free(d); +} + +/** Compute the HMAC-SHA-256 of the msg_len bytes in msg, using + * the key of length key_len. Store the DIGEST256_LEN-byte + * result in hmac_out. Asserts on failure. + */ +void +crypto_hmac_sha256(char *hmac_out, + const char *key, size_t key_len, + const char *msg, size_t msg_len) +{ + /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */ + tor_assert(key_len < INT_MAX); + tor_assert(msg_len < INT_MAX); + tor_assert(hmac_out); + + PK11SlotInfo *slot = NULL; + PK11SymKey *symKey = NULL; + PK11Context *hmac = NULL; + + int ok = 0; + SECStatus s; + SECItem keyItem, paramItem; + keyItem.data = (unsigned char *)key; + keyItem.len = (unsigned)key_len; + paramItem.type = siBuffer; + paramItem.data = NULL; + paramItem.len = 0; + + slot = PK11_GetBestSlot(CKM_SHA256_HMAC, NULL); + if (!slot) + goto done; + symKey = PK11_ImportSymKey(slot, CKM_SHA256_HMAC, + PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL); + if (!symKey) + goto done; + + hmac = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, symKey, + ¶mItem); + if (!hmac) + goto done; + s = PK11_DigestBegin(hmac); + if (s != SECSuccess) + goto done; + s = PK11_DigestOp(hmac, (const unsigned char *)msg, (unsigned int)msg_len); + if (s != SECSuccess) + goto done; + unsigned int len=0; + s = PK11_DigestFinal(hmac, (unsigned char *)hmac_out, &len, DIGEST256_LEN); + if (s != SECSuccess || len != DIGEST256_LEN) + goto done; + ok = 1; + + done: + if (hmac) + PK11_DestroyContext(hmac, PR_TRUE); + if (symKey) + PK11_FreeSymKey(symKey); + if (slot) + PK11_FreeSlot(slot); + + tor_assert(ok); +} + diff --git a/src/lib/crypt_ops/crypto_digest_openssl.c b/src/lib/crypt_ops/crypto_digest_openssl.c new file mode 100644 index 0000000000..c631b0eac0 --- /dev/null +++ b/src/lib/crypt_ops/crypto_digest_openssl.c @@ -0,0 +1,522 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_digest_openssl.c + * \brief Block of functions related with digest and xof utilities and + * operations (OpenSSL specific implementations). + **/ + +#include "lib/container/smartlist.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/log/log.h" +#include "lib/log/util_bug.h" + +#include "keccak-tiny/keccak-tiny.h" + +#include +#include + +#include "lib/arch/bytes.h" + +#include "lib/crypt_ops/crypto_openssl_mgt.h" + +DISABLE_GCC_WARNING(redundant-decls) + +#include +#include + +ENABLE_GCC_WARNING(redundant-decls) + +/* Crypto digest functions */ + +/** Compute the SHA1 digest of the len bytes on data stored in + * m. Write the DIGEST_LEN byte result into digest. + * Return 0 on success, -1 on failure. + */ +MOCK_IMPL(int, +crypto_digest,(char *digest, const char *m, size_t len)) +{ + tor_assert(m); + tor_assert(digest); + if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL) { + return -1; + } + return 0; +} + +/** Compute a 256-bit digest of len bytes in data stored in m, + * using the algorithm algorithm. Write the DIGEST_LEN256-byte result + * into digest. Return 0 on success, -1 on failure. */ +int +crypto_digest256(char *digest, const char *m, size_t len, + digest_algorithm_t algorithm) +{ + tor_assert(m); + tor_assert(digest); + tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); + + int ret = 0; + if (algorithm == DIGEST_SHA256) { + ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL); + } else { +#ifdef OPENSSL_HAS_SHA3 + unsigned int dlen = DIGEST256_LEN; + ret = EVP_Digest(m, len, (uint8_t*)digest, &dlen, EVP_sha3_256(), NULL); +#else + ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len) + > -1); +#endif /* defined(OPENSSL_HAS_SHA3) */ + } + + if (!ret) + return -1; + return 0; +} + +/** Compute a 512-bit digest of len bytes in data stored in m, + * using the algorithm algorithm. Write the DIGEST_LEN512-byte result + * into digest. Return 0 on success, -1 on failure. */ +int +crypto_digest512(char *digest, const char *m, size_t len, + digest_algorithm_t algorithm) +{ + tor_assert(m); + tor_assert(digest); + tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); + + int ret = 0; + if (algorithm == DIGEST_SHA512) { + ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest) + != NULL); + } else { +#ifdef OPENSSL_HAS_SHA3 + unsigned int dlen = DIGEST512_LEN; + ret = EVP_Digest(m, len, (uint8_t*)digest, &dlen, EVP_sha3_512(), NULL); +#else + ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len) + > -1); +#endif /* defined(OPENSSL_HAS_SHA3) */ + } + + if (!ret) + return -1; + return 0; +} + +/** Intermediate information about the digest of a stream of data. */ +struct crypto_digest_t { + digest_algorithm_t algorithm; /**< Which algorithm is in use? */ + /** State for the digest we're using. Only one member of the + * union is usable, depending on the value of algorithm. Note also + * that space for other members might not even be allocated! + */ + union { + SHA_CTX sha1; /**< state for SHA1 */ + SHA256_CTX sha2; /**< state for SHA256 */ + SHA512_CTX sha512; /**< state for SHA512 */ +#ifdef OPENSSL_HAS_SHA3 + EVP_MD_CTX *md; +#else + keccak_state sha3; /**< state for SHA3-[256,512] */ +#endif + } d; +}; + +#ifdef TOR_UNIT_TESTS + +digest_algorithm_t +crypto_digest_get_algorithm(crypto_digest_t *digest) +{ + tor_assert(digest); + + return digest->algorithm; +} + +#endif /* defined(TOR_UNIT_TESTS) */ + +/** + * Return the number of bytes we need to malloc in order to get a + * crypto_digest_t for alg, or the number of bytes we need to wipe + * when we free one. + */ +static size_t +crypto_digest_alloc_bytes(digest_algorithm_t alg) +{ + /* Helper: returns the number of bytes in the 'f' field of 'st' */ +#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f )) + /* Gives the length of crypto_digest_t through the end of the field 'd' */ +#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \ + STRUCT_FIELD_SIZE(crypto_digest_t, f)) + switch (alg) { + case DIGEST_SHA1: + return END_OF_FIELD(d.sha1); + case DIGEST_SHA256: + return END_OF_FIELD(d.sha2); + case DIGEST_SHA512: + return END_OF_FIELD(d.sha512); +#ifdef OPENSSL_HAS_SHA3 + case DIGEST_SHA3_256: /* Fall through */ + case DIGEST_SHA3_512: + return END_OF_FIELD(d.md); +#else + case DIGEST_SHA3_256: /* Fall through */ + case DIGEST_SHA3_512: + return END_OF_FIELD(d.sha3); +#endif /* defined(OPENSSL_HAS_SHA3) */ + default: + tor_assert(0); // LCOV_EXCL_LINE + return 0; // LCOV_EXCL_LINE + } +#undef END_OF_FIELD +#undef STRUCT_FIELD_SIZE +} + +/** + * Internal function: create and return a new digest object for 'algorithm'. + * Does not typecheck the algorithm. + */ +static crypto_digest_t * +crypto_digest_new_internal(digest_algorithm_t algorithm) +{ + crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm)); + r->algorithm = algorithm; + + switch (algorithm) + { + case DIGEST_SHA1: + SHA1_Init(&r->d.sha1); + break; + case DIGEST_SHA256: + SHA256_Init(&r->d.sha2); + break; + case DIGEST_SHA512: + SHA512_Init(&r->d.sha512); + break; +#ifdef OPENSSL_HAS_SHA3 + case DIGEST_SHA3_256: + r->d.md = EVP_MD_CTX_new(); + if (!EVP_DigestInit(r->d.md, EVP_sha3_256())) { + crypto_digest_free(r); + return NULL; + } + break; + case DIGEST_SHA3_512: + r->d.md = EVP_MD_CTX_new(); + if (!EVP_DigestInit(r->d.md, EVP_sha3_512())) { + crypto_digest_free(r); + return NULL; + } + break; +#else /* !(defined(OPENSSL_HAS_SHA3)) */ + case DIGEST_SHA3_256: + keccak_digest_init(&r->d.sha3, 256); + break; + case DIGEST_SHA3_512: + keccak_digest_init(&r->d.sha3, 512); + break; +#endif /* defined(OPENSSL_HAS_SHA3) */ + default: + tor_assert_unreached(); + } + + return r; +} + +/** Allocate and return a new digest object to compute SHA1 digests. + */ +crypto_digest_t * +crypto_digest_new(void) +{ + return crypto_digest_new_internal(DIGEST_SHA1); +} + +/** Allocate and return a new digest object to compute 256-bit digests + * using algorithm. + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest256_new` + * C_RUST_COUPLED: `crypto::digest::Sha256::default` + */ +crypto_digest_t * +crypto_digest256_new(digest_algorithm_t algorithm) +{ + tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); + return crypto_digest_new_internal(algorithm); +} + +/** Allocate and return a new digest object to compute 512-bit digests + * using algorithm. */ +crypto_digest_t * +crypto_digest512_new(digest_algorithm_t algorithm) +{ + tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); + return crypto_digest_new_internal(algorithm); +} + +/** Deallocate a digest object. + */ +void +crypto_digest_free_(crypto_digest_t *digest) +{ + if (!digest) + return; +#ifdef OPENSSL_HAS_SHA3 + if (digest->algorithm == DIGEST_SHA3_256 || + digest->algorithm == DIGEST_SHA3_512) { + if (digest->d.md) { + EVP_MD_CTX_free(digest->d.md); + } + } +#endif /* defined(OPENSSL_HAS_SHA3) */ + size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); + memwipe(digest, 0, bytes); + tor_free(digest); +} + +/** Add len bytes from data to the digest object. + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_add_bytess` + * C_RUST_COUPLED: `crypto::digest::Sha256::process` + */ +void +crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, + size_t len) +{ + tor_assert(digest); + tor_assert(data); + /* Using the SHA*_*() calls directly means we don't support doing + * SHA in hardware. But so far the delay of getting the question + * to the hardware, and hearing the answer, is likely higher than + * just doing it ourselves. Hashes are fast. + */ + switch (digest->algorithm) { + case DIGEST_SHA1: + SHA1_Update(&digest->d.sha1, (void*)data, len); + break; + case DIGEST_SHA256: + SHA256_Update(&digest->d.sha2, (void*)data, len); + break; + case DIGEST_SHA512: + SHA512_Update(&digest->d.sha512, (void*)data, len); + break; +#ifdef OPENSSL_HAS_SHA3 + case DIGEST_SHA3_256: /* FALLSTHROUGH */ + case DIGEST_SHA3_512: { + int r = EVP_DigestUpdate(digest->d.md, data, len); + tor_assert(r); + } + break; +#else /* !(defined(OPENSSL_HAS_SHA3)) */ + case DIGEST_SHA3_256: /* FALLSTHROUGH */ + case DIGEST_SHA3_512: + keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len); + break; +#endif /* defined(OPENSSL_HAS_SHA3) */ + default: + /* LCOV_EXCL_START */ + tor_fragile_assert(); + break; + /* LCOV_EXCL_STOP */ + } +} + +/** Compute the hash of the data that has been passed to the digest + * object; write the first out_len bytes of the result to out. + * out_len must be \<= DIGEST512_LEN. + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_get_digest` + * C_RUST_COUPLED: `impl digest::FixedOutput for Sha256` + */ +void +crypto_digest_get_digest(crypto_digest_t *digest, + char *out, size_t out_len) +{ + unsigned char r[DIGEST512_LEN]; + tor_assert(digest); + tor_assert(out); + tor_assert(out_len <= crypto_digest_algorithm_get_length(digest->algorithm)); + + /* The SHA-3 code handles copying into a temporary ctx, and also can handle + * short output buffers by truncating appropriately. */ + if (digest->algorithm == DIGEST_SHA3_256 || + digest->algorithm == DIGEST_SHA3_512) { +#ifdef OPENSSL_HAS_SHA3 + unsigned dlen = (unsigned) + crypto_digest_algorithm_get_length(digest->algorithm); + EVP_MD_CTX *tmp = EVP_MD_CTX_new(); + EVP_MD_CTX_copy(tmp, digest->d.md); + memset(r, 0xff, sizeof(r)); + int res = EVP_DigestFinal(tmp, r, &dlen); + EVP_MD_CTX_free(tmp); + tor_assert(res == 1); + goto done; +#else /* !(defined(OPENSSL_HAS_SHA3)) */ + /* Tiny-Keccak handles copying into a temporary ctx, and also can handle + * short output buffers by truncating appropriately. */ + keccak_digest_sum(&digest->d.sha3, (uint8_t *)out, out_len); + return; +#endif /* defined(OPENSSL_HAS_SHA3) */ + } + + const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); + crypto_digest_t tmpenv; + /* memcpy into a temporary ctx, since SHA*_Final clears the context */ + memcpy(&tmpenv, digest, alloc_bytes); + switch (digest->algorithm) { + case DIGEST_SHA1: + SHA1_Final(r, &tmpenv.d.sha1); + break; + case DIGEST_SHA256: + SHA256_Final(r, &tmpenv.d.sha2); + break; + case DIGEST_SHA512: + SHA512_Final(r, &tmpenv.d.sha512); + break; +//LCOV_EXCL_START + case DIGEST_SHA3_256: /* FALLSTHROUGH */ + case DIGEST_SHA3_512: + default: + log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm); + /* This is fatal, because it should never happen. */ + tor_assert_unreached(); + break; +//LCOV_EXCL_STOP + } +#ifdef OPENSSL_HAS_SHA3 + done: +#endif + memcpy(out, r, out_len); + memwipe(r, 0, sizeof(r)); +} + +/** Allocate and return a new digest object with the same state as + * digest + * + * C_RUST_COUPLED: `external::crypto_digest::crypto_digest_dup` + * C_RUST_COUPLED: `impl Clone for crypto::digest::Sha256` + */ +crypto_digest_t * +crypto_digest_dup(const crypto_digest_t *digest) +{ + tor_assert(digest); + const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm); + crypto_digest_t *result = tor_memdup(digest, alloc_bytes); + +#ifdef OPENSSL_HAS_SHA3 + if (digest->algorithm == DIGEST_SHA3_256 || + digest->algorithm == DIGEST_SHA3_512) { + result->d.md = EVP_MD_CTX_new(); + EVP_MD_CTX_copy(result->d.md, digest->d.md); + } +#endif /* defined(OPENSSL_HAS_SHA3) */ + return result; +} + +/** Temporarily save the state of digest in checkpoint. + * Asserts that digest is a SHA1 digest object. + */ +void +crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint, + const crypto_digest_t *digest) +{ + const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); + tor_assert(bytes <= sizeof(checkpoint->mem)); + memcpy(checkpoint->mem, digest, bytes); +} + +/** Restore the state of digest from checkpoint. + * Asserts that digest is a SHA1 digest object. Requires that the + * state was previously stored with crypto_digest_checkpoint() */ +void +crypto_digest_restore(crypto_digest_t *digest, + const crypto_digest_checkpoint_t *checkpoint) +{ + const size_t bytes = crypto_digest_alloc_bytes(digest->algorithm); + memcpy(digest, checkpoint->mem, bytes); +} + +/** Replace the state of the digest object into with the state + * of the digest object from. Requires that 'into' and 'from' + * have the same digest type. + */ +void +crypto_digest_assign(crypto_digest_t *into, + const crypto_digest_t *from) +{ + tor_assert(into); + tor_assert(from); + tor_assert(into->algorithm == from->algorithm); + const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm); + +#ifdef OPENSSL_HAS_SHA3 + if (from->algorithm == DIGEST_SHA3_256 || + from->algorithm == DIGEST_SHA3_512) { + EVP_MD_CTX_copy(into->d.md, from->d.md); + return; + } +#endif /* defined(OPENSSL_HAS_SHA3) */ + + memcpy(into,from,alloc_bytes); +} + +/** Given a list of strings in lst, set the len_out-byte digest + * at digest_out to the hash of the concatenation of those strings, + * plus the optional string append, computed with the algorithm + * alg. + * out_len must be \<= DIGEST512_LEN. */ +void +crypto_digest_smartlist(char *digest_out, size_t len_out, + const smartlist_t *lst, + const char *append, + digest_algorithm_t alg) +{ + crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg); +} + +/** Given a list of strings in lst, set the len_out-byte digest + * at digest_out to the hash of the concatenation of: the + * optional string prepend, those strings, + * and the optional string append, computed with the algorithm + * alg. + * len_out must be \<= DIGEST512_LEN. */ +void +crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, + const char *prepend, + const smartlist_t *lst, + const char *append, + digest_algorithm_t alg) +{ + crypto_digest_t *d = crypto_digest_new_internal(alg); + if (prepend) + crypto_digest_add_bytes(d, prepend, strlen(prepend)); + SMARTLIST_FOREACH(lst, const char *, cp, + crypto_digest_add_bytes(d, cp, strlen(cp))); + if (append) + crypto_digest_add_bytes(d, append, strlen(append)); + crypto_digest_get_digest(d, digest_out, len_out); + crypto_digest_free(d); +} + +/** Compute the HMAC-SHA-256 of the msg_len bytes in msg, using + * the key of length key_len. Store the DIGEST256_LEN-byte + * result in hmac_out. Asserts on failure. + */ +void +crypto_hmac_sha256(char *hmac_out, + const char *key, size_t key_len, + const char *msg, size_t msg_len) +{ + /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */ + tor_assert(key_len < INT_MAX); + tor_assert(msg_len < INT_MAX); + tor_assert(hmac_out); + unsigned char *rv = NULL; + rv = HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len, + (unsigned char*)hmac_out, NULL); + tor_assert(rv); +} + diff --git a/src/lib/crypt_ops/crypto_ed25519.c b/src/lib/crypt_ops/crypto_ed25519.c index 400f963898..0581529125 100644 --- a/src/lib/crypt_ops/crypto_ed25519.c +++ b/src/lib/crypt_ops/crypto_ed25519.c @@ -226,7 +226,7 @@ ed25519_keypair_generate(ed25519_keypair_t *keypair_out, int extra_strong) int ed25519_public_key_is_zero(const ed25519_public_key_t *pubkey) { - return tor_mem_is_zero((char*)pubkey->pubkey, ED25519_PUBKEY_LEN); + return safe_mem_is_zero((char*)pubkey->pubkey, ED25519_PUBKEY_LEN); } /* Return a heap-allocated array that contains msg prefixed by the diff --git a/src/lib/crypt_ops/crypto_format.c b/src/lib/crypt_ops/crypto_format.c index 84f73e5272..118cd79045 100644 --- a/src/lib/crypt_ops/crypto_format.c +++ b/src/lib/crypt_ops/crypto_format.c @@ -104,7 +104,7 @@ crypto_read_tagged_contents_from_file(const char *fname, prefix[32] = 0; /* Check type, extract tag. */ if (strcmpstart(prefix, "== ") || strcmpend(prefix, " ==") || - ! tor_mem_is_zero(prefix+strlen(prefix), 32-strlen(prefix))) { + ! fast_mem_is_zero(prefix+strlen(prefix), 32-strlen(prefix))) { saved_errno = EINVAL; goto end; } @@ -131,20 +131,27 @@ crypto_read_tagged_contents_from_file(const char *fname, return r; } -/** Encode pkey as a base64-encoded string, without trailing "=" +/** Encode pkey as a base64-encoded string, including trailing "=" * characters, in the buffer output, which must have at least - * CURVE25519_BASE64_PADDED_LEN+1 bytes available. Return 0 on success, -1 on - * failure. */ -int + * CURVE25519_BASE64_PADDED_LEN+1 bytes available. + * Can not fail. + * + * Careful! CURVE25519_BASE64_PADDED_LEN is one byte longer than + * ED25519_BASE64_LEN. + */ +void curve25519_public_to_base64(char *output, const curve25519_public_key_t *pkey) { char buf[128]; - base64_encode(buf, sizeof(buf), - (const char*)pkey->public_key, CURVE25519_PUBKEY_LEN, 0); - buf[CURVE25519_BASE64_PADDED_LEN] = '\0'; + int n = base64_encode(buf, sizeof(buf), + (const char*)pkey->public_key, + CURVE25519_PUBKEY_LEN, 0); + /* These asserts should always succeed, unless there is a bug in + * base64_encode(). */ + tor_assert(n == CURVE25519_BASE64_PADDED_LEN); + tor_assert(buf[CURVE25519_BASE64_PADDED_LEN] == '\0'); memcpy(output, buf, CURVE25519_BASE64_PADDED_LEN+1); - return 0; } /** Try to decode a base64-encoded curve25519 public key from input @@ -181,8 +188,7 @@ ed25519_fmt(const ed25519_public_key_t *pkey) if (ed25519_public_key_is_zero(pkey)) { strlcpy(formatted, "", sizeof(formatted)); } else { - int r = ed25519_public_to_base64(formatted, pkey); - tor_assert(!r); + ed25519_public_to_base64(formatted, pkey); } } else { strlcpy(formatted, "", sizeof(formatted)); @@ -202,28 +208,35 @@ ed25519_public_from_base64(ed25519_public_key_t *pkey, /** Encode the public key pkey into the buffer at output, * which must have space for ED25519_BASE64_LEN bytes of encoded key, - * plus one byte for a terminating NUL. Return 0 on success, -1 on failure. + * plus one byte for a terminating NUL. + * Can not fail. + * + * Careful! ED25519_BASE64_LEN is one byte shorter than + * CURVE25519_BASE64_PADDED_LEN. */ -int +void ed25519_public_to_base64(char *output, const ed25519_public_key_t *pkey) { - return digest256_to_base64(output, (const char *)pkey->pubkey); + digest256_to_base64(output, (const char *)pkey->pubkey); } /** Encode the signature sig into the buffer at output, * which must have space for ED25519_SIG_BASE64_LEN bytes of encoded signature, - * plus one byte for a terminating NUL. Return 0 on success, -1 on failure. + * plus one byte for a terminating NUL. + * Can not fail. */ -int +void ed25519_signature_to_base64(char *output, const ed25519_signature_t *sig) { char buf[256]; int n = base64_encode_nopad(buf, sizeof(buf), sig->sig, ED25519_SIG_LEN); + /* These asserts should always succeed, unless there is a bug in + * base64_encode_nopad(). */ tor_assert(n == ED25519_SIG_BASE64_LEN); + tor_assert(buf[ED25519_SIG_BASE64_LEN] == '\0'); memcpy(output, buf, ED25519_SIG_BASE64_LEN+1); - return 0; } /** Try to decode the string input into an ed25519 signature. On @@ -233,16 +246,11 @@ int ed25519_signature_from_base64(ed25519_signature_t *sig, const char *input) { - if (strlen(input) != ED25519_SIG_BASE64_LEN) return -1; - char buf[ED25519_SIG_BASE64_LEN+3]; - memcpy(buf, input, ED25519_SIG_BASE64_LEN); - buf[ED25519_SIG_BASE64_LEN+0] = '='; - buf[ED25519_SIG_BASE64_LEN+1] = '='; - buf[ED25519_SIG_BASE64_LEN+2] = 0; char decoded[128]; - int n = base64_decode(decoded, sizeof(decoded), buf, strlen(buf)); + int n = base64_decode(decoded, sizeof(decoded), input, + ED25519_SIG_BASE64_LEN); if (n < 0 || n != ED25519_SIG_LEN) return -1; memcpy(sig->sig, decoded, ED25519_SIG_LEN); @@ -250,24 +258,26 @@ ed25519_signature_from_base64(ed25519_signature_t *sig, return 0; } -/** Base64 encode DIGEST_LINE bytes from digest, remove the trailing = +/** Base64 encode DIGEST_LEN bytes from digest, remove the trailing = * characters, and store the nul-terminated result in the first - * BASE64_DIGEST_LEN+1 bytes of d64. */ -/* XXXX unify with crypto_format.c code */ -int + * BASE64_DIGEST_LEN+1 bytes of d64. + * Can not fail. */ +void digest_to_base64(char *d64, const char *digest) { char buf[256]; - base64_encode(buf, sizeof(buf), digest, DIGEST_LEN, 0); - buf[BASE64_DIGEST_LEN] = '\0'; + int n = base64_encode_nopad(buf, sizeof(buf), + (const uint8_t *)digest, DIGEST_LEN); + /* These asserts should always succeed, unless there is a bug in + * base64_encode_nopad(). */ + tor_assert(n == BASE64_DIGEST_LEN); + tor_assert(buf[BASE64_DIGEST_LEN] == '\0'); memcpy(d64, buf, BASE64_DIGEST_LEN+1); - return 0; } /** Given a base64 encoded, nul-terminated digest in d64 (without * trailing newline or = characters), decode it and store the result in the * first DIGEST_LEN bytes at digest. */ -/* XXXX unify with crypto_format.c code */ int digest_from_base64(char *digest, const char *d64) { @@ -279,22 +289,24 @@ digest_from_base64(char *digest, const char *d64) /** Base64 encode DIGEST256_LINE bytes from digest, remove the * trailing = characters, and store the nul-terminated result in the first - * BASE64_DIGEST256_LEN+1 bytes of d64. */ - /* XXXX unify with crypto_format.c code */ -int + * BASE64_DIGEST256_LEN+1 bytes of d64. + * Can not fail. */ +void digest256_to_base64(char *d64, const char *digest) { char buf[256]; - base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN, 0); - buf[BASE64_DIGEST256_LEN] = '\0'; + int n = base64_encode_nopad(buf, sizeof(buf), + (const uint8_t *)digest, DIGEST256_LEN); + /* These asserts should always succeed, unless there is a bug in + * base64_encode_nopad(). */ + tor_assert(n == BASE64_DIGEST256_LEN); + tor_assert(buf[BASE64_DIGEST256_LEN] == '\0'); memcpy(d64, buf, BASE64_DIGEST256_LEN+1); - return 0; } /** Given a base64 encoded, nul-terminated digest in d64 (without * trailing newline or = characters), decode it and store the result in the * first DIGEST256_LEN bytes at digest. */ -/* XXXX unify with crypto_format.c code */ int digest256_from_base64(char *digest, const char *d64) { diff --git a/src/lib/crypt_ops/crypto_format.h b/src/lib/crypt_ops/crypto_format.h index fe852e6a61..b4b3aa189c 100644 --- a/src/lib/crypt_ops/crypto_format.h +++ b/src/lib/crypt_ops/crypto_format.h @@ -33,18 +33,18 @@ ssize_t crypto_read_tagged_contents_from_file(const char *fname, int ed25519_public_from_base64(struct ed25519_public_key_t *pkey, const char *input); -int ed25519_public_to_base64(char *output, - const struct ed25519_public_key_t *pkey); +void ed25519_public_to_base64(char *output, + const struct ed25519_public_key_t *pkey); const char *ed25519_fmt(const struct ed25519_public_key_t *pkey); int ed25519_signature_from_base64(struct ed25519_signature_t *sig, const char *input); -int ed25519_signature_to_base64(char *output, - const struct ed25519_signature_t *sig); +void ed25519_signature_to_base64(char *output, + const struct ed25519_signature_t *sig); -int digest_to_base64(char *d64, const char *digest); +void digest_to_base64(char *d64, const char *digest); int digest_from_base64(char *digest, const char *d64); -int digest256_to_base64(char *d64, const char *digest); +void digest256_to_base64(char *d64, const char *digest); int digest256_from_base64(char *digest, const char *d64); #endif /* !defined(TOR_CRYPTO_FORMAT_H) */ diff --git a/src/lib/crypt_ops/crypto_hkdf.c b/src/lib/crypt_ops/crypto_hkdf.c index fd2e701651..e0f3d65ad1 100644 --- a/src/lib/crypt_ops/crypto_hkdf.c +++ b/src/lib/crypt_ops/crypto_hkdf.c @@ -25,7 +25,7 @@ #include #define HAVE_OPENSSL_HKDF 1 #endif -#endif +#endif /* defined(ENABLE_OPENSSL) */ #include @@ -109,7 +109,7 @@ crypto_expand_key_material_rfc5869_sha256_openssl( return 0; } -#else +#else /* !(defined(HAVE_OPENSSL_HKDF)) */ /** * Perform RFC5869 HKDF computation using our own legacy implementation. @@ -166,7 +166,7 @@ crypto_expand_key_material_rfc5869_sha256_legacy( memwipe(mac, 0, sizeof(mac)); return 0; } -#endif +#endif /* defined(HAVE_OPENSSL_HKDF) */ /** Expand some secret key material according to RFC5869, using SHA256 as the * underlying hash. The key_in_len bytes at key_in are the @@ -191,11 +191,11 @@ crypto_expand_key_material_rfc5869_sha256( salt_in_len, info_in, info_in_len, key_out, key_out_len); -#else +#else /* !(defined(HAVE_OPENSSL_HKDF)) */ return crypto_expand_key_material_rfc5869_sha256_legacy(key_in, key_in_len, salt_in, salt_in_len, info_in, info_in_len, key_out, key_out_len); -#endif +#endif /* defined(HAVE_OPENSSL_HKDF) */ } diff --git a/src/lib/crypt_ops/crypto_init.c b/src/lib/crypt_ops/crypto_init.c index 4040085c76..a16bf4e11a 100644 --- a/src/lib/crypt_ops/crypto_init.c +++ b/src/lib/crypt_ops/crypto_init.c @@ -12,6 +12,8 @@ #include "orconfig.h" +#define CRYPTO_PRIVATE + #include "lib/crypt_ops/crypto_init.h" #include "lib/crypt_ops/crypto_curve25519.h" @@ -69,6 +71,8 @@ crypto_early_init(void) if (crypto_init_siphash_key() < 0) return -1; + crypto_rand_fast_init(); + curve25519_init(); ed25519_init(); } @@ -95,7 +99,7 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir) (void)useAccel; (void)accelName; (void)accelDir; -#endif +#endif /* defined(ENABLE_OPENSSL) */ #ifdef ENABLE_NSS if (crypto_nss_late_init() < 0) return -1; @@ -111,6 +115,7 @@ crypto_thread_cleanup(void) #ifdef ENABLE_OPENSSL crypto_openssl_thread_cleanup(); #endif + destroy_thread_fast_rng(); } /** @@ -129,6 +134,8 @@ crypto_global_cleanup(void) crypto_nss_global_cleanup(); #endif + crypto_rand_fast_shutdown(); + crypto_early_initialized_ = 0; crypto_global_initialized_ = 0; have_seeded_siphash = 0; @@ -145,6 +152,12 @@ crypto_prefork(void) #ifdef ENABLE_NSS crypto_nss_prefork(); #endif + /* It is not safe to share a fast_rng object across a fork boundary unless + * we actually have zero-on-fork support in map_anon.c. If we have + * drop-on-fork support, we will crash; if we have neither, we will yield + * a copy of the parent process's rng, which is scary and insecure. + */ + destroy_thread_fast_rng(); } /** Run operations that the crypto library requires to be happy again diff --git a/src/lib/crypt_ops/crypto_init.h b/src/lib/crypt_ops/crypto_init.h index 540d08eb56..8de3eb03ed 100644 --- a/src/lib/crypt_ops/crypto_init.h +++ b/src/lib/crypt_ops/crypto_init.h @@ -33,4 +33,4 @@ const char *crypto_get_header_version_string(void); int tor_is_using_nss(void); -#endif /* !defined(TOR_CRYPTO_H) */ +#endif /* !defined(TOR_CRYPTO_INIT_H) */ diff --git a/src/lib/crypt_ops/crypto_nss_mgt.h b/src/lib/crypt_ops/crypto_nss_mgt.h index 72fd2a1229..4cfa9b42a4 100644 --- a/src/lib/crypt_ops/crypto_nss_mgt.h +++ b/src/lib/crypt_ops/crypto_nss_mgt.h @@ -29,6 +29,6 @@ void crypto_nss_global_cleanup(void); void crypto_nss_prefork(void); void crypto_nss_postfork(void); -#endif +#endif /* defined(ENABLE_NSS) */ -#endif /* !defined(TOR_CRYPTO_NSS_H) */ +#endif /* !defined(TOR_CRYPTO_NSS_MGT_H) */ diff --git a/src/lib/crypt_ops/crypto_ope.c b/src/lib/crypt_ops/crypto_ope.c index 2186d2a939..4bd4b35706 100644 --- a/src/lib/crypt_ops/crypto_ope.c +++ b/src/lib/crypt_ops/crypto_ope.c @@ -57,9 +57,9 @@ ope_val_from_le(ope_val_t x) ((x) >> 8) | (((x)&0xff) << 8); } -#else +#else /* !(defined(WORDS_BIGENDIAN)) */ #define ope_val_from_le(x) (x) -#endif +#endif /* defined(WORDS_BIGENDIAN) */ /** * Return a new AES256-CTR stream cipher object for ope, ready to yield diff --git a/src/lib/crypt_ops/crypto_ope.h b/src/lib/crypt_ops/crypto_ope.h index 610d956335..9778dfe0f0 100644 --- a/src/lib/crypt_ops/crypto_ope.h +++ b/src/lib/crypt_ops/crypto_ope.h @@ -41,6 +41,6 @@ struct aes_cnt_cipher; STATIC struct aes_cnt_cipher *ope_get_cipher(const crypto_ope_t *ope, uint32_t initial_idx); STATIC uint64_t sum_values_from_cipher(struct aes_cnt_cipher *c, size_t n); -#endif +#endif /* defined(CRYPTO_OPE_PRIVATE) */ -#endif +#endif /* !defined(CRYPTO_OPE_H) */ diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.c b/src/lib/crypt_ops/crypto_openssl_mgt.c index 60e4ea795e..9ec59e7c81 100644 --- a/src/lib/crypt_ops/crypto_openssl_mgt.c +++ b/src/lib/crypt_ops/crypto_openssl_mgt.c @@ -200,10 +200,10 @@ crypto_openssl_early_init(void) OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); -#else +#else /* !(defined(OPENSSL_1_1_API)) */ ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); -#endif +#endif /* defined(OPENSSL_1_1_API) */ setup_openssl_threading(); @@ -213,6 +213,14 @@ crypto_openssl_early_init(void) !strcmp(version_str, OPENSSL_VERSION_TEXT)) { log_info(LD_CRYPTO, "OpenSSL version matches version from headers " "(%lx: %s).", version_num, version_str); + } else if ((version_num & 0xffff0000) == + (OPENSSL_VERSION_NUMBER & 0xffff0000)) { + log_notice(LD_CRYPTO, + "We compiled with OpenSSL %lx: %s and we " + "are running with OpenSSL %lx: %s. " + "These two versions should be binary compatible.", + (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT, + version_num, version_str); } else { log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the " "version we're running with. If you get weird crashes, that " diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.h b/src/lib/crypt_ops/crypto_openssl_mgt.h index a3dd03aa04..111a2d12ed 100644 --- a/src/lib/crypt_ops/crypto_openssl_mgt.h +++ b/src/lib/crypt_ops/crypto_openssl_mgt.h @@ -84,6 +84,6 @@ int crypto_openssl_late_init(int useAccel, const char *accelName, void crypto_openssl_thread_cleanup(void); void crypto_openssl_global_cleanup(void); -#endif /* ENABLE_OPENSSL */ +#endif /* defined(ENABLE_OPENSSL) */ #endif /* !defined(TOR_CRYPTO_OPENSSL_H) */ diff --git a/src/lib/crypt_ops/crypto_rand.c b/src/lib/crypt_ops/crypto_rand.c index 0b1cb96c1b..a80a98f267 100644 --- a/src/lib/crypt_ops/crypto_rand.c +++ b/src/lib/crypt_ops/crypto_rand.c @@ -36,6 +36,7 @@ #include "lib/defs/digest_sizes.h" #include "lib/crypt_ops/crypto_digest.h" +#include "lib/ctime/di_ops.h" #ifdef ENABLE_NSS #include "lib/crypt_ops/crypto_nss_mgt.h" @@ -46,7 +47,7 @@ DISABLE_GCC_WARNING(redundant-decls) #include #include ENABLE_GCC_WARNING(redundant-decls) -#endif +#endif /* defined(ENABLE_OPENSSL) */ #ifdef ENABLE_NSS #include @@ -314,7 +315,7 @@ crypto_strongest_rand_raw(uint8_t *out, size_t out_len) } } - if ((out_len < sanity_min_size) || !tor_mem_is_zero((char*)out, out_len)) + if ((out_len < sanity_min_size) || !safe_mem_is_zero((char*)out, out_len)) return 0; } @@ -418,7 +419,7 @@ crypto_seed_openssl_rng(void) else return -1; } -#endif +#endif /* defined(ENABLE_OPENSSL) */ #ifdef ENABLE_NSS /** @@ -441,7 +442,7 @@ crypto_seed_nss_rng(void) return load_entropy_ok ? 0 : -1; } -#endif +#endif /* defined(ENABLE_NSS) */ /** * Seed the RNG for any and all crypto libraries that we're using with bytes @@ -519,13 +520,13 @@ crypto_rand_unmocked(char *to, size_t n) #undef BUFLEN } -#else +#else /* !(defined(ENABLE_NSS)) */ int r = RAND_bytes((unsigned char*)to, (int)n); /* We consider a PRNG failure non-survivable. Let's assert so that we get a * stack trace about where it happened. */ tor_assert(r >= 0); -#endif +#endif /* defined(ENABLE_NSS) */ } /** @@ -626,6 +627,6 @@ crypto_force_rand_ssleay(void) RAND_set_rand_method(default_method); return 1; } -#endif +#endif /* defined(ENABLE_OPENSSL) */ return 0; } diff --git a/src/lib/crypt_ops/crypto_rand.h b/src/lib/crypt_ops/crypto_rand.h index 8a81a4acdc..a019287aa9 100644 --- a/src/lib/crypt_ops/crypto_rand.h +++ b/src/lib/crypt_ops/crypto_rand.h @@ -66,12 +66,37 @@ void crypto_fast_rng_free_(crypto_fast_rng_t *); unsigned crypto_fast_rng_get_uint(crypto_fast_rng_t *rng, unsigned limit); uint64_t crypto_fast_rng_get_uint64(crypto_fast_rng_t *rng, uint64_t limit); +uint32_t crypto_fast_rng_get_u32(crypto_fast_rng_t *rng); +uint64_t crypto_fast_rng_uint64_range(crypto_fast_rng_t *rng, + uint64_t min, uint64_t max); double crypto_fast_rng_get_double(crypto_fast_rng_t *rng); +/** + * Using the fast_rng rng, yield true with probability + * 1/n. Otherwise yield false. + * + * n must not be zero. + **/ +#define crypto_fast_rng_one_in_n(rng, n) \ + (0 == (crypto_fast_rng_get_uint((rng), (n)))) + +crypto_fast_rng_t *get_thread_fast_rng(void); + +#ifdef CRYPTO_PRIVATE +/* These are only used from crypto_init.c */ +void destroy_thread_fast_rng(void); +void crypto_rand_fast_init(void); +void crypto_rand_fast_shutdown(void); +#endif /* defined(CRYPTO_PRIVATE) */ + #if defined(TOR_UNIT_TESTS) /* Used for white-box testing */ size_t crypto_fast_rng_get_bytes_used_per_stream(void); -#endif +/* For deterministic prng implementations */ +void crypto_fast_rng_disable_reseed(crypto_fast_rng_t *rng); +/* To override the prng for testing. */ +crypto_fast_rng_t *crypto_replace_thread_fast_rng(crypto_fast_rng_t *rng); +#endif /* defined(TOR_UNIT_TESTS) */ #ifdef CRYPTO_RAND_PRIVATE diff --git a/src/lib/crypt_ops/crypto_rand_fast.c b/src/lib/crypt_ops/crypto_rand_fast.c index 34e763bf51..e6ceb42ccb 100644 --- a/src/lib/crypt_ops/crypto_rand_fast.c +++ b/src/lib/crypt_ops/crypto_rand_fast.c @@ -33,6 +33,7 @@ */ #define CRYPTO_RAND_FAST_PRIVATE +#define CRYPTO_PRIVATE #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_cipher.h" @@ -41,11 +42,29 @@ #include "lib/intmath/cmp.h" #include "lib/cc/ctassert.h" #include "lib/malloc/map_anon.h" +#include "lib/thread/threads.h" #include "lib/log/util_bug.h" +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + #include +#ifdef NOINHERIT_CAN_FAIL +#define CHECK_PID +#endif + +#ifdef CHECK_PID +#define PID_FIELD_LEN sizeof(pid_t) +#else +#define PID_FIELD_LEN 0 +#endif + /* Alias for CRYPTO_FAST_RNG_SEED_LEN to make our code shorter. */ #define SEED_LEN (CRYPTO_FAST_RNG_SEED_LEN) @@ -57,7 +76,7 @@ /* The number of random bytes that we can yield to the user after each * time we fill a crypto_fast_rng_t's buffer. */ -#define BUFLEN (MAPLEN - 2*sizeof(uint16_t) - SEED_LEN) +#define BUFLEN (MAPLEN - 2*sizeof(uint16_t) - SEED_LEN - PID_FIELD_LEN) /* The number of buffer refills after which we should fetch more * entropy from crypto_strongest_rand(). @@ -76,10 +95,20 @@ CTASSERT(KEY_BITS == 128 || KEY_BITS == 192 || KEY_BITS == 256); struct crypto_fast_rng_t { /** How many more fills does this buffer have before we should mix - * in the output of crypto_rand()? */ - uint16_t n_till_reseed; + * in the output of crypto_strongest_rand()? + * + * This value may be negative if unit tests are enabled. If so, it + * indicates that we should never mix in extra data from + * crypto_strongest_rand(). + */ + int16_t n_till_reseed; /** How many bytes are remaining in cbuf.bytes? */ uint16_t bytes_left; +#ifdef CHECK_PID + /** Which process owns this fast_rng? If this value is zero, we do not + * need to test the owner. */ + pid_t owner; +#endif struct cbuf { /** The seed (key and IV) that we will use the next time that we refill * cbuf. */ @@ -122,24 +151,57 @@ crypto_fast_rng_new(void) * long. * * Note that this object is NOT thread-safe. If you need a thread-safe - * prng, use crypto_rand(), or wrap this in a mutex. + * prng, you should probably look at get_thread_fast_rng(). Alternatively, + * use crypto_rand(), wrap this in a mutex. **/ crypto_fast_rng_t * crypto_fast_rng_new_from_seed(const uint8_t *seed) { + unsigned inherit = INHERIT_RES_KEEP; /* We try to allocate this object as securely as we can, to avoid * having it get dumped, swapped, or shared after fork. */ crypto_fast_rng_t *result = tor_mmap_anonymous(sizeof(*result), - ANONMAP_PRIVATE | ANONMAP_NOINHERIT); - + ANONMAP_PRIVATE | ANONMAP_NOINHERIT, + &inherit); memcpy(result->buf.seed, seed, SEED_LEN); /* Causes an immediate refill once the user asks for data. */ result->bytes_left = 0; result->n_till_reseed = RESEED_AFTER; +#ifdef CHECK_PID + if (inherit == INHERIT_RES_KEEP) { + /* This value will neither be dropped nor zeroed after fork, so we need to + * check our pid to make sure we are not sharing it across a fork. This + * can be expensive if the pid value isn't cached, sadly. + */ + result->owner = getpid(); + } +#elif defined(_WIN32) + /* Windows can't fork(), so there's no need to noinherit. */ +#else + /* We decided above that noinherit would always do _something_. Assert here + * that we were correct. */ + tor_assertf(inherit != INHERIT_RES_KEEP, + "We failed to create a non-inheritable memory region, even " + "though we believed such a failure to be impossible! This is " + "probably a bug in Tor support for your platform; please report " + "it."); +#endif /* defined(CHECK_PID) || ... */ return result; } +#ifdef TOR_UNIT_TESTS +/** + * Unit tests only: prevent a crypto_fast_rng_t from ever mixing in more + * entropy. + */ +void +crypto_fast_rng_disable_reseed(crypto_fast_rng_t *rng) +{ + rng->n_till_reseed = -1; +} +#endif /* defined(TOR_UNIT_TESTS) */ + /** * Helper: create a crypto_cipher_t object from SEED_LEN bytes of * input. The first KEY_LEN bytes are used as the stream cipher's key, @@ -151,6 +213,26 @@ cipher_from_seed(const uint8_t *seed) return crypto_cipher_new_with_iv_and_bits(seed, seed+KEY_LEN, KEY_BITS); } +/** + * Helper: mix additional entropy into rng by using our XOF to mix the + * old value for the seed with some additional bytes from + * crypto_strongest_rand(). + **/ +static void +crypto_fast_rng_add_entopy(crypto_fast_rng_t *rng) +{ + crypto_xof_t *xof = crypto_xof_new(); + crypto_xof_add_bytes(xof, rng->buf.seed, SEED_LEN); + { + uint8_t seedbuf[SEED_LEN]; + crypto_strongest_rand(seedbuf, SEED_LEN); + crypto_xof_add_bytes(xof, seedbuf, SEED_LEN); + memwipe(seedbuf, 0, SEED_LEN); + } + crypto_xof_squeeze_bytes(xof, rng->buf.seed, SEED_LEN); + crypto_xof_free(xof); +} + /** * Helper: refill the seed bytes and output buffer of rng, using * the input seed bytes as input (key and IV) for the stream cipher. @@ -161,22 +243,19 @@ cipher_from_seed(const uint8_t *seed) static void crypto_fast_rng_refill(crypto_fast_rng_t *rng) { - if (rng->n_till_reseed-- == 0) { - /* It's time to reseed the RNG. We'll do this by using our XOF to mix the - * old value for the seed with some additional bytes from - * crypto_strongest_rand(). */ - crypto_xof_t *xof = crypto_xof_new(); - crypto_xof_add_bytes(xof, rng->buf.seed, SEED_LEN); - { - uint8_t seedbuf[SEED_LEN]; - crypto_strongest_rand(seedbuf, SEED_LEN); - crypto_xof_add_bytes(xof, seedbuf, SEED_LEN); - memwipe(seedbuf, 0, SEED_LEN); - } - crypto_xof_squeeze_bytes(xof, rng->buf.seed, SEED_LEN); - crypto_xof_free(xof); - + rng->n_till_reseed--; + if (rng->n_till_reseed == 0) { + /* It's time to reseed the RNG. */ + crypto_fast_rng_add_entopy(rng); rng->n_till_reseed = RESEED_AFTER; + } else if (rng->n_till_reseed < 0) { +#ifdef TOR_UNIT_TESTS + /* Reseeding is disabled for testing; never do it on this prng. */ + rng->n_till_reseed = -1; +#else + /* If testing is disabled, this shouldn't be able to become negative. */ + tor_assert_unreached(); +#endif /* defined(TOR_UNIT_TESTS) */ } /* Now fill rng->buf with output from our stream cipher, initialized from * that seed value. */ @@ -208,6 +287,27 @@ static void crypto_fast_rng_getbytes_impl(crypto_fast_rng_t *rng, uint8_t *out, const size_t n) { +#ifdef CHECK_PID + if (rng->owner) { + /* Note that we only need to do this check when we have owner set: that + * is, when our attempt to block inheriting failed, and the result was + * INHERIT_RES_KEEP. + * + * If the result was INHERIT_RES_DROP, then any attempt to access the rng + * memory after forking will crash. + * + * If the result was INHERIT_RES_ZERO, then forking will set the bytes_left + * and n_till_reseed fields to zero. This function will call + * crypto_fast_rng_refill(), which will in turn reseed the PRNG. + * + * So we only need to do this test in the case when mmap_anonymous() + * returned INHERIT_KEEP. We avoid doing it needlessly, since getpid() is + * often a system call, and that can be slow. + */ + tor_assert(rng->owner == getpid()); + } +#endif /* defined(CHECK_PID) */ + size_t bytes_to_yield = n; while (bytes_to_yield) { @@ -260,4 +360,80 @@ crypto_fast_rng_get_bytes_used_per_stream(void) { return BUFLEN; } -#endif +#endif /* defined(TOR_UNIT_TESTS) */ + +/** + * Thread-local instance for our fast RNG. + **/ +static tor_threadlocal_t thread_rng; + +/** + * Return a per-thread fast RNG, initializing it if necessary. + * + * You do not need to free this yourself. + * + * It is NOT safe to share this value across threads. + **/ +crypto_fast_rng_t * +get_thread_fast_rng(void) +{ + crypto_fast_rng_t *rng = tor_threadlocal_get(&thread_rng); + + if (PREDICT_UNLIKELY(rng == NULL)) { + rng = crypto_fast_rng_new(); + tor_threadlocal_set(&thread_rng, rng); + } + + return rng; +} + +/** + * Used when a thread is exiting: free the per-thread fast RNG if needed. + * Invoked from the crypto subsystem's thread-cleanup code. + **/ +void +destroy_thread_fast_rng(void) +{ + crypto_fast_rng_t *rng = tor_threadlocal_get(&thread_rng); + if (!rng) + return; + crypto_fast_rng_free(rng); + tor_threadlocal_set(&thread_rng, NULL); +} + +#ifdef TOR_UNIT_TESTS +/** + * Replace the current thread's rng with rng. For use by the + * unit tests only. Returns the previous thread rng. + **/ +crypto_fast_rng_t * +crypto_replace_thread_fast_rng(crypto_fast_rng_t *rng) +{ + crypto_fast_rng_t *old_rng = tor_threadlocal_get(&thread_rng); + tor_threadlocal_set(&thread_rng, rng); + return old_rng; +} +#endif /* defined(TOR_UNIT_TESTS) */ + +/** + * Initialize the global thread-local key that will be used to keep track + * of per-thread fast RNG instances. Called from the crypto subsystem's + * initialization code. + **/ +void +crypto_rand_fast_init(void) +{ + tor_threadlocal_init(&thread_rng); +} + +/** + * Initialize the global thread-local key that will be used to keep track + * of per-thread fast RNG instances. Called from the crypto subsystem's + * shutdown code. + **/ +void +crypto_rand_fast_shutdown(void) +{ + destroy_thread_fast_rng(); + tor_threadlocal_destroy(&thread_rng); +} diff --git a/src/lib/crypt_ops/crypto_rand_numeric.c b/src/lib/crypt_ops/crypto_rand_numeric.c index d02c5cdcfa..ffbfa2d56c 100644 --- a/src/lib/crypt_ops/crypto_rand_numeric.c +++ b/src/lib/crypt_ops/crypto_rand_numeric.c @@ -155,7 +155,34 @@ crypto_fast_rng_get_uint64(crypto_fast_rng_t *rng, uint64_t limit) } /** - * As crypto_rand_, but extract the result from a crypto_fast_rng_t. + * As crypto_rand_u32, but extract the result from a crypto_fast_rng_t. + */ +uint32_t +crypto_fast_rng_get_u32(crypto_fast_rng_t *rng) +{ + uint32_t val; + crypto_fast_rng_getbytes(rng, (void*)&val, sizeof(val)); + return val; +} + +/** + * As crypto_rand_uint64_range(), but extract the result from a + * crypto_fast_rng_t. + */ +uint64_t +crypto_fast_rng_uint64_range(crypto_fast_rng_t *rng, + uint64_t min, uint64_t max) +{ + /* Handle corrupted input */ + if (BUG(min >= max)) { + return min; + } + + return min + crypto_fast_rng_get_uint64(rng, max - min); +} + +/** + * As crypto_rand_get_double() but extract the result from a crypto_fast_rng_t. */ double crypto_fast_rng_get_double(crypto_fast_rng_t *rng) @@ -164,3 +191,4 @@ crypto_fast_rng_get_double(crypto_fast_rng_t *rng) crypto_fast_rng_getbytes(rng, (void*)&u, sizeof(u)); return ((double)u) / UINT_MAX_AS_DOUBLE; } + diff --git a/src/lib/crypt_ops/crypto_rsa.c b/src/lib/crypt_ops/crypto_rsa.c index c9189b0dfc..c39d2e18d1 100644 --- a/src/lib/crypt_ops/crypto_rsa.c +++ b/src/lib/crypt_ops/crypto_rsa.c @@ -59,7 +59,7 @@ crypto_get_rsa_padding(int padding) default: tor_assert(0); return -1; // LCOV_EXCL_LINE } } -#endif +#endif /* defined(ENABLE_OPENSSL) */ /** Compare the public-key components of a and b. Return non-zero iff * a==b. A NULL key is considered to be distinct from all non-NULL diff --git a/src/lib/crypt_ops/crypto_rsa.h b/src/lib/crypt_ops/crypto_rsa.h index c1ea767f85..e9bfec2f85 100644 --- a/src/lib/crypt_ops/crypto_rsa.h +++ b/src/lib/crypt_ops/crypto_rsa.h @@ -119,7 +119,7 @@ struct rsa_st *crypto_pk_get_openssl_rsa_(crypto_pk_t *env); crypto_pk_t *crypto_new_pk_from_openssl_rsa_(struct rsa_st *rsa); MOCK_DECL(struct evp_pkey_st *, crypto_pk_get_openssl_evp_pkey_,( crypto_pk_t *env,int private)); -#endif +#endif /* defined(ENABLE_OPENSSL) */ #ifdef ENABLE_NSS struct SECKEYPublicKeyStr; @@ -129,7 +129,7 @@ const struct SECKEYPublicKeyStr *crypto_pk_get_nss_pubkey( const crypto_pk_t *key); const struct SECKEYPrivateKeyStr *crypto_pk_get_nss_privkey( const crypto_pk_t *key); -#endif +#endif /* defined(ENABLE_NSS) */ void crypto_pk_assign_public(crypto_pk_t *dest, const crypto_pk_t *src); void crypto_pk_assign_private(crypto_pk_t *dest, const crypto_pk_t *src); @@ -140,6 +140,6 @@ struct SECItemStr; STATIC int secitem_uint_cmp(const struct SECItemStr *a, const struct SECItemStr *b); #endif -#endif +#endif /* defined(TOR_UNIT_TESTS) */ -#endif +#endif /* !defined(TOR_CRYPTO_RSA_H) */ diff --git a/src/lib/crypt_ops/crypto_rsa_nss.c b/src/lib/crypt_ops/crypto_rsa_nss.c index ad2ad38b66..612b7a0e64 100644 --- a/src/lib/crypt_ops/crypto_rsa_nss.c +++ b/src/lib/crypt_ops/crypto_rsa_nss.c @@ -156,7 +156,7 @@ crypto_pk_get_openssl_evp_pkey_,(crypto_pk_t *pk, int private)) tor_free(buf); return result; } -#endif +#endif /* defined(ENABLE_OPENSSL) */ /** Allocate and return storage for a public key. The key itself will not yet * be set. diff --git a/src/lib/crypt_ops/crypto_s2k.c b/src/lib/crypt_ops/crypto_s2k.c index 42276597d4..5cf98e3e64 100644 --- a/src/lib/crypt_ops/crypto_s2k.c +++ b/src/lib/crypt_ops/crypto_s2k.c @@ -285,7 +285,7 @@ secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len, if (rv < 0) return S2K_FAILED; return (int)key_out_len; -#else +#else /* !(defined(ENABLE_OPENSSL)) */ SECItem passItem = { .type = siBuffer, .data = (unsigned char *) secret, .len = (int)secret_len }; @@ -325,7 +325,7 @@ secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len, if (alg) SECOID_DestroyAlgorithmID(alg, PR_TRUE); return rv; -#endif +#endif /* defined(ENABLE_OPENSSL) */ } case S2K_TYPE_SCRYPT: { diff --git a/src/lib/crypt_ops/crypto_util.c b/src/lib/crypt_ops/crypto_util.c index 67a1a9eb92..5e3f4a87a1 100644 --- a/src/lib/crypt_ops/crypto_util.c +++ b/src/lib/crypt_ops/crypto_util.c @@ -30,7 +30,7 @@ DISABLE_GCC_WARNING(redundant-decls) #include #include ENABLE_GCC_WARNING(redundant-decls) -#endif +#endif /* defined(ENABLE_OPENSSL) */ #include "lib/log/log.h" #include "lib/log/util_bug.h" diff --git a/src/lib/crypt_ops/digestset.h b/src/lib/crypt_ops/digestset.h index 91d53a0542..7d6d687342 100644 --- a/src/lib/crypt_ops/digestset.h +++ b/src/lib/crypt_ops/digestset.h @@ -26,4 +26,4 @@ void digestset_add(digestset_t *set, const char *addr); int digestset_probably_contains(const digestset_t *set, const char *addr); -#endif +#endif /* !defined(TOR_DIGESTSET_H) */ diff --git a/src/lib/crypt_ops/include.am b/src/lib/crypt_ops/include.am index 4730440143..1f58a33d38 100644 --- a/src/lib/crypt_ops/include.am +++ b/src/lib/crypt_ops/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-crypt-ops-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_crypt_ops_a_SOURCES = \ src/lib/crypt_ops/crypto_cipher.c \ src/lib/crypt_ops/crypto_curve25519.c \ @@ -27,12 +28,14 @@ src_lib_libtor_crypt_ops_a_SOURCES = \ if USE_NSS src_lib_libtor_crypt_ops_a_SOURCES += \ src/lib/crypt_ops/aes_nss.c \ + src/lib/crypt_ops/crypto_digest_nss.c \ src/lib/crypt_ops/crypto_dh_nss.c \ src/lib/crypt_ops/crypto_nss_mgt.c \ src/lib/crypt_ops/crypto_rsa_nss.c else src_lib_libtor_crypt_ops_a_SOURCES += \ src/lib/crypt_ops/aes_openssl.c \ + src/lib/crypt_ops/crypto_digest_openssl.c \ src/lib/crypt_ops/crypto_rsa_openssl.c endif @@ -50,6 +53,7 @@ src_lib_libtor_crypt_ops_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_crypt_ops_testing_a_CFLAGS = \ $(AM_CFLAGS) $(TOR_CFLAGS_CRYPTLIB) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/crypt_ops/aes.h \ src/lib/crypt_ops/compat_openssl.h \ diff --git a/src/lib/ctime/include.am b/src/lib/ctime/include.am index b46c43ba0c..83942ca4e0 100644 --- a/src/lib/ctime/include.am +++ b/src/lib/ctime/include.am @@ -11,6 +11,7 @@ else mulodi4_source= endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_ctime_a_SOURCES = \ $(mulodi4_source) \ src/ext/csiphash.c \ @@ -21,5 +22,6 @@ src_lib_libtor_ctime_testing_a_SOURCES = \ src_lib_libtor_ctime_a_CFLAGS = @CFLAGS_CONSTTIME@ src_lib_libtor_ctime_testing_a_CFLAGS = @CFLAGS_CONSTTIME@ $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/ctime/di_ops.h diff --git a/src/lib/defs/dh_sizes.h b/src/lib/defs/dh_sizes.h index a2ffbc51c2..b0d1eba0c5 100644 --- a/src/lib/defs/dh_sizes.h +++ b/src/lib/defs/dh_sizes.h @@ -19,4 +19,4 @@ /** Length of our legacy DH keys. */ #define DH1024_KEY_LEN (1024/8) -#endif +#endif /* !defined(TOR_DH_SIZES_H) */ diff --git a/src/lib/defs/digest_sizes.h b/src/lib/defs/digest_sizes.h index 525e5209d6..a0dd97a74d 100644 --- a/src/lib/defs/digest_sizes.h +++ b/src/lib/defs/digest_sizes.h @@ -24,4 +24,4 @@ /** Length of the output of our 64-bit optimized message digests (SHA512). */ #define DIGEST512_LEN 64 -#endif +#endif /* !defined(TOR_DIGEST_SIZES_H) */ diff --git a/src/lib/defs/include.am b/src/lib/defs/include.am index 6a7f9114ea..84ee403771 100644 --- a/src/lib/defs/include.am +++ b/src/lib/defs/include.am @@ -1,6 +1,8 @@ +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/defs/dh_sizes.h \ src/lib/defs/digest_sizes.h \ + src/lib/defs/logging_types.h \ src/lib/defs/time.h \ src/lib/defs/x25519_sizes.h diff --git a/src/lib/defs/logging_types.h b/src/lib/defs/logging_types.h new file mode 100644 index 0000000000..57db818007 --- /dev/null +++ b/src/lib/defs/logging_types.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file logging_types.h + * + * \brief Global definition for types used by logging systems. + **/ + +#ifndef TOR_LOGGING_TYPES_H +#define TOR_LOGGING_TYPES_H + +/* We define this here so that it can be used both by backtrace.h and + * log.h. + */ + +/** Mask of zero or more log domains, OR'd together. */ +typedef uint64_t log_domain_mask_t; + +#endif diff --git a/src/lib/defs/time.h b/src/lib/defs/time.h index c25f5022c5..459afbf42d 100644 --- a/src/lib/defs/time.h +++ b/src/lib/defs/time.h @@ -20,4 +20,4 @@ /* How many nanoseconds per millisecond */ #define TOR_NSEC_PER_MSEC (1000*1000) -#endif +#endif /* !defined(TOR_TIME_DEFS_H) */ diff --git a/src/lib/defs/x25519_sizes.h b/src/lib/defs/x25519_sizes.h index 8933a8866b..6431f0a2dd 100644 --- a/src/lib/defs/x25519_sizes.h +++ b/src/lib/defs/x25519_sizes.h @@ -33,4 +33,4 @@ #define ED25519_BASE64_LEN 43 #define ED25519_SIG_BASE64_LEN 86 -#endif +#endif /* !defined(TOR_X25519_SIZES_H) */ diff --git a/src/lib/dispatch/.may_include b/src/lib/dispatch/.may_include new file mode 100644 index 0000000000..7f2df5859f --- /dev/null +++ b/src/lib/dispatch/.may_include @@ -0,0 +1,10 @@ +orconfig.h + +ext/tor_queue.h + +lib/cc/*.h +lib/container/*.h +lib/dispatch/*.h +lib/intmath/*.h +lib/log/*.h +lib/malloc/*.h diff --git a/src/lib/dispatch/dispatch.h b/src/lib/dispatch/dispatch.h new file mode 100644 index 0000000000..a9e655409a --- /dev/null +++ b/src/lib/dispatch/dispatch.h @@ -0,0 +1,114 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_DISPATCH_H +#define TOR_DISPATCH_H + +#include "lib/dispatch/msgtypes.h" + +/** + * \file dispatch.h + * \brief Low-level APIs for message-passing system. + * + * This module implements message dispatch based on a set of short integer + * identifiers. For a higher-level interface, see pubsub.h. + * + * Each message is represented as a generic msg_t object, and is discriminated + * by its message_id_t. Messages are delivered by a dispatch_t object, which + * delivers each message to its recipients by a configured "channel". + * + * A "channel" is a means of delivering messages. Every message_id_t must + * be associated with exactly one channel, identified by channel_id_t. + * When a channel receives messages, a callback is invoked to either process + * the messages immediately, or to cause them to be processed later. + * + * Every message_id_t has zero or more associated receiver functions set up in + * the dispatch_t object. Once the dispatch_t object is created, receivers + * can be enabled or disabled [TODO], but not added or removed. + * + * Every message_id_t has an associated datatype, identified by a + * msg_type_id_t. These datatypes can be associated with functions to + * (for example) free them, or format them for debugging. + * + * To setup a dispatch_t object, first create a dispatch_cfg_t object, and + * configure messages with their types, channels, and receivers. Then, use + * dispatch_new() with that dispatch_cfg_t to create the dispatch_t object. + * + * (We use a two-phase contruction procedure here to enable better static + * reasoning about publish/subscribe relationships.) + * + * Once you have a dispatch_t, you can queue messages on it with + * dispatch_send*(), and cause those messages to be delivered with + * dispatch_flush(). + **/ + +/** + * A "dispatcher" is the highest-level object; it handles making sure that + * messages are received and delivered properly. Only the mainloop + * should handle this type directly. + */ +typedef struct dispatch_t dispatch_t; + +struct dispatch_cfg_t; + +dispatch_t *dispatch_new(const struct dispatch_cfg_t *cfg); + +/** + * Free a dispatcher. Tor does this at exit. + */ +#define dispatch_free(d) \ + FREE_AND_NULL(dispatch_t, dispatch_free_, (d)) + +void dispatch_free_(dispatch_t *); + +int dispatch_send(dispatch_t *d, + subsys_id_t sender, + channel_id_t channel, + message_id_t msg, + msg_type_id_t type, + msg_aux_data_t auxdata); + +int dispatch_send_msg(dispatch_t *d, msg_t *m); + +int dispatch_send_msg_unchecked(dispatch_t *d, msg_t *m); + +/* Flush up to max_msgs currently pending messages from the + * dispatcher. Messages that are not pending when this function are + * called, are not flushed by this call. Return 0 on success, -1 on + * unrecoverable error. + */ +int dispatch_flush(dispatch_t *, channel_id_t chan, int max_msgs); + +/** + * Function callback type used to alert some other module when a channel's + * queue changes from empty to nonempty. + * + * Ex 1: To cause messages to be processed immediately on-stack, this callback + * should invoke dispatch_flush() directly. + * + * Ex 2: To cause messages to be processed very soon, from the event queue, + * this callback should schedule an event callback to run dispatch_flush(). + * + * Ex 3: To cause messages to be processed periodically, this function should + * do nothing, and a periodic event should invoke dispatch_flush(). + **/ +typedef void (*dispatch_alertfn_t)(struct dispatch_t *, + channel_id_t, void *); + +int dispatch_set_alert_fn(dispatch_t *d, channel_id_t chan, + dispatch_alertfn_t fn, void *userdata); + +#define dispatch_free_msg(d,msg) \ + STMT_BEGIN { \ + msg_t **msg_tmp_ptr__ = &(msg); \ + dispatch_free_msg_((d), *msg_tmp_ptr__); \ + *msg_tmp_ptr__= NULL; \ + } STMT_END +void dispatch_free_msg_(const dispatch_t *d, msg_t *msg); + +char *dispatch_fmt_msg_data(const dispatch_t *d, const msg_t *msg); + +#endif /* !defined(TOR_DISPATCH_H) */ diff --git a/src/lib/dispatch/dispatch_cfg.c b/src/lib/dispatch/dispatch_cfg.c new file mode 100644 index 0000000000..b3a72ec22f --- /dev/null +++ b/src/lib/dispatch/dispatch_cfg.c @@ -0,0 +1,141 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file dispatch_cfg.c + * \brief Create and configure a dispatch_cfg_t. + * + * A dispatch_cfg_t object is used to configure a set of messages and + * associated information before creating a dispatch_t. + */ + +#define DISPATCH_PRIVATE + +#include "orconfig.h" +#include "lib/dispatch/dispatch_cfg.h" +#include "lib/dispatch/dispatch_cfg_st.h" +#include "lib/dispatch/dispatch.h" +#include "lib/dispatch/dispatch_st.h" + +#include "lib/container/smartlist.h" +#include "lib/malloc/malloc.h" + +/** + * Create and return a new dispatch_cfg_t. + **/ +dispatch_cfg_t * +dcfg_new(void) +{ + dispatch_cfg_t *cfg = tor_malloc(sizeof(dispatch_cfg_t)); + cfg->type_by_msg = smartlist_new(); + cfg->chan_by_msg = smartlist_new(); + cfg->fns_by_type = smartlist_new(); + cfg->recv_by_msg = smartlist_new(); + return cfg; +} + +/** + * Associate a message with a datatype. Return 0 on success, -1 if a + * different type was previously associated with the message ID. + **/ +int +dcfg_msg_set_type(dispatch_cfg_t *cfg, message_id_t msg, + msg_type_id_t type) +{ + smartlist_grow(cfg->type_by_msg, msg+1); + msg_type_id_t *oldval = smartlist_get(cfg->type_by_msg, msg); + if (oldval != NULL && *oldval != type) { + return -1; + } + if (!oldval) + smartlist_set(cfg->type_by_msg, msg, tor_memdup(&type, sizeof(type))); + return 0; +} + +/** + * Associate a message with a channel. Return 0 on success, -1 if a + * different channel was previously associated with the message ID. + **/ +int +dcfg_msg_set_chan(dispatch_cfg_t *cfg, message_id_t msg, + channel_id_t chan) +{ + smartlist_grow(cfg->chan_by_msg, msg+1); + channel_id_t *oldval = smartlist_get(cfg->chan_by_msg, msg); + if (oldval != NULL && *oldval != chan) { + return -1; + } + if (!oldval) + smartlist_set(cfg->chan_by_msg, msg, tor_memdup(&chan, sizeof(chan))); + return 0; +} + +/** + * Associate a set of functions with a datatype. Return 0 on success, -1 if + * different functions were previously associated with the type. + **/ +int +dcfg_type_set_fns(dispatch_cfg_t *cfg, msg_type_id_t type, + const dispatch_typefns_t *fns) +{ + smartlist_grow(cfg->fns_by_type, type+1); + dispatch_typefns_t *oldfns = smartlist_get(cfg->fns_by_type, type); + if (oldfns && (oldfns->free_fn != fns->free_fn || + oldfns->fmt_fn != fns->fmt_fn)) + return -1; + if (!oldfns) + smartlist_set(cfg->fns_by_type, type, tor_memdup(fns, sizeof(*fns))); + return 0; +} + +/** + * Associate a receiver with a message ID. Multiple receivers may be + * associated with a single messasge ID. + * + * Return 0 on success, on failure. + **/ +int +dcfg_add_recv(dispatch_cfg_t *cfg, message_id_t msg, + subsys_id_t sys, recv_fn_t fn) +{ + smartlist_grow(cfg->recv_by_msg, msg+1); + smartlist_t *receivers = smartlist_get(cfg->recv_by_msg, msg); + if (!receivers) { + receivers = smartlist_new(); + smartlist_set(cfg->recv_by_msg, msg, receivers); + } + + dispatch_rcv_t *rcv = tor_malloc(sizeof(dispatch_rcv_t)); + rcv->sys = sys; + rcv->enabled = true; + rcv->fn = fn; + smartlist_add(receivers, (void*)rcv); + return 0; +} + +/** Helper: release all storage held by cfg. */ +void +dcfg_free_(dispatch_cfg_t *cfg) +{ + if (!cfg) + return; + + SMARTLIST_FOREACH(cfg->type_by_msg, msg_type_id_t *, id, tor_free(id)); + SMARTLIST_FOREACH(cfg->chan_by_msg, channel_id_t *, id, tor_free(id)); + SMARTLIST_FOREACH(cfg->fns_by_type, dispatch_typefns_t *, f, tor_free(f)); + smartlist_free(cfg->type_by_msg); + smartlist_free(cfg->chan_by_msg); + smartlist_free(cfg->fns_by_type); + SMARTLIST_FOREACH_BEGIN(cfg->recv_by_msg, smartlist_t *, receivers) { + if (!receivers) + continue; + SMARTLIST_FOREACH(receivers, dispatch_rcv_t *, rcv, tor_free(rcv)); + smartlist_free(receivers); + } SMARTLIST_FOREACH_END(receivers); + smartlist_free(cfg->recv_by_msg); + + tor_free(cfg); +} diff --git a/src/lib/dispatch/dispatch_cfg.h b/src/lib/dispatch/dispatch_cfg.h new file mode 100644 index 0000000000..61fade7240 --- /dev/null +++ b/src/lib/dispatch/dispatch_cfg.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_DISPATCH_CFG_H +#define TOR_DISPATCH_CFG_H + +#include "lib/dispatch/msgtypes.h" + +/** + * A "dispatch_cfg" is the configuration used to set up a dispatcher. + * It is created and accessed with a set of dcfg_* functions, and then + * used with dispatcher_new() to make the dispatcher. + */ +typedef struct dispatch_cfg_t dispatch_cfg_t; + +dispatch_cfg_t *dcfg_new(void); + +int dcfg_msg_set_type(dispatch_cfg_t *cfg, message_id_t msg, + msg_type_id_t type); + +int dcfg_msg_set_chan(dispatch_cfg_t *cfg, message_id_t msg, + channel_id_t chan); + +int dcfg_type_set_fns(dispatch_cfg_t *cfg, msg_type_id_t type, + const dispatch_typefns_t *fns); + +int dcfg_add_recv(dispatch_cfg_t *cfg, message_id_t msg, + subsys_id_t sys, recv_fn_t fn); + +/** Free a dispatch_cfg_t. */ +#define dcfg_free(cfg) \ + FREE_AND_NULL(dispatch_cfg_t, dcfg_free_, (cfg)) + +void dcfg_free_(dispatch_cfg_t *cfg); + +#endif /* !defined(TOR_DISPATCH_CFG_H) */ diff --git a/src/lib/dispatch/dispatch_cfg_st.h b/src/lib/dispatch/dispatch_cfg_st.h new file mode 100644 index 0000000000..57b6f0347f --- /dev/null +++ b/src/lib/dispatch/dispatch_cfg_st.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_DISPATCH_CFG_ST_H +#define TOR_DISPATCH_CFG_ST_H + +struct smartlist_t; + +/* Information needed to create a dispatcher, but in a less efficient, more + * mutable format. */ +struct dispatch_cfg_t { + /** A list of msg_type_id_t (cast to void*), indexed by msg_t. */ + struct smartlist_t *type_by_msg; + /** A list of channel_id_t (cast to void*), indexed by msg_t. */ + struct smartlist_t *chan_by_msg; + /** A list of dispatch_rcv_t, indexed by msg_type_id_t. */ + struct smartlist_t *fns_by_type; + /** A list of dispatch_typefns_t, indexed by msg_t. */ + struct smartlist_t *recv_by_msg; +}; + +#endif /* !defined(TOR_DISPATCH_CFG_ST_H) */ diff --git a/src/lib/dispatch/dispatch_core.c b/src/lib/dispatch/dispatch_core.c new file mode 100644 index 0000000000..da54f9b437 --- /dev/null +++ b/src/lib/dispatch/dispatch_core.c @@ -0,0 +1,260 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file dispatch_core.c + * \brief Core module for sending and receiving messages. + */ + +#define DISPATCH_PRIVATE +#include "orconfig.h" + +#include "lib/dispatch/dispatch.h" +#include "lib/dispatch/dispatch_st.h" +#include "lib/dispatch/dispatch_naming.h" + +#include "lib/malloc/malloc.h" +#include "lib/log/util_bug.h" + +#include + +/** + * Use d to drop all storage held for msg. + * + * (We need the dispatcher so we know how to free the auxiliary data.) + **/ +void +dispatch_free_msg_(const dispatch_t *d, msg_t *msg) +{ + if (!msg) + return; + + d->typefns[msg->type].free_fn(msg->aux_data__); + tor_free(msg); +} + +/** + * Format the auxiliary data held by msg. + **/ +char * +dispatch_fmt_msg_data(const dispatch_t *d, const msg_t *msg) +{ + if (!msg) + return NULL; + + return d->typefns[msg->type].fmt_fn(msg->aux_data__); +} + +/** + * Release all storage held by d. + **/ +void +dispatch_free_(dispatch_t *d) +{ + if (d == NULL) + return; + + size_t n_queues = d->n_queues; + for (size_t i = 0; i < n_queues; ++i) { + msg_t *m, *mtmp; + TOR_SIMPLEQ_FOREACH_SAFE(m, &d->queues[i].queue, next, mtmp) { + dispatch_free_msg(d, m); + } + } + + size_t n_msgs = d->n_msgs; + + for (size_t i = 0; i < n_msgs; ++i) { + tor_free(d->table[i]); + } + tor_free(d->table); + tor_free(d->typefns); + tor_free(d->queues); + + // This is the only time we will treat d->cfg as non-const. + //dispatch_cfg_free_((dispatch_items_t *) d->cfg); + + tor_free(d); +} + +/** + * Tell the dispatcher to call fn with userdata whenever + * chan becomes nonempty. Return 0 on success, -1 on error. + **/ +int +dispatch_set_alert_fn(dispatch_t *d, channel_id_t chan, + dispatch_alertfn_t fn, void *userdata) +{ + if (BUG(chan >= d->n_queues)) + return -1; + + dqueue_t *q = &d->queues[chan]; + q->alert_fn = fn; + q->alert_fn_arg = userdata; + return 0; +} + +/** + * Send a message on the appropriate channel notifying that channel if + * necessary. + * + * This function takes ownership of the auxiliary data; it can't be static or + * stack-allocated, and the caller is not allowed to use it afterwards. + * + * This function does not check the various vields of the message object for + * consistency. + **/ +int +dispatch_send(dispatch_t *d, + subsys_id_t sender, + channel_id_t channel, + message_id_t msg, + msg_type_id_t type, + msg_aux_data_t auxdata) +{ + if (!d->table[msg]) { + /* Fast path: nobody wants this data. */ + + d->typefns[type].free_fn(auxdata); + return 0; + } + + msg_t *m = tor_malloc(sizeof(msg_t)); + + m->sender = sender; + m->channel = channel; + m->msg = msg; + m->type = type; + memcpy(&m->aux_data__, &auxdata, sizeof(msg_aux_data_t)); + + return dispatch_send_msg(d, m); +} + +int +dispatch_send_msg(dispatch_t *d, msg_t *m) +{ + if (BUG(!d)) + goto err; + if (BUG(!m)) + goto err; + if (BUG(m->channel >= d->n_queues)) + goto err; + if (BUG(m->msg >= d->n_msgs)) + goto err; + + dtbl_entry_t *ent = d->table[m->msg]; + if (ent) { + if (BUG(m->type != ent->type)) + goto err; + if (BUG(m->channel != ent->channel)) + goto err; + } + + return dispatch_send_msg_unchecked(d, m); + err: + /* Probably it isn't safe to free m, since type could be wrong. */ + return -1; +} + +/** + * Send a message on the appropriate queue, notifying that queue if necessary. + * + * This function takes ownership of the message object and its auxiliary data; + * it can't be static or stack-allocated, and the caller isn't allowed to use + * it afterwards. + * + * This function does not check the various fields of the message object for + * consistency, and can crash if they are out of range. Only functions that + * have already constructed the message in a safe way, or checked it for + * correctness themselves, should call this function. + **/ +int +dispatch_send_msg_unchecked(dispatch_t *d, msg_t *m) +{ + /* Find the right queue. */ + dqueue_t *q = &d->queues[m->channel]; + bool was_empty = TOR_SIMPLEQ_EMPTY(&q->queue); + + /* Append the message. */ + TOR_SIMPLEQ_INSERT_TAIL(&q->queue, m, next); + + if (debug_logging_enabled()) { + char *arg = dispatch_fmt_msg_data(d, m); + log_debug(LD_MESG, + "Queued: %s (%s) from %s, on %s.", + get_message_id_name(m->msg), + arg, + get_subsys_id_name(m->sender), + get_channel_id_name(m->channel)); + tor_free(arg); + } + + /* If we just made the queue nonempty for the first time, call the alert + * function. */ + if (was_empty) { + q->alert_fn(d, m->channel, q->alert_fn_arg); + } + + return 0; +} + +/** + * Run all of the callbacks on d associated with m. + **/ +static void +dispatcher_run_msg_cbs(const dispatch_t *d, msg_t *m) +{ + tor_assert(m->msg <= d->n_msgs); + dtbl_entry_t *ent = d->table[m->msg]; + int n_fns = ent->n_fns; + + if (debug_logging_enabled()) { + char *arg = dispatch_fmt_msg_data(d, m); + log_debug(LD_MESG, + "Delivering: %s (%s) from %s, on %s:", + get_message_id_name(m->msg), + arg, + get_subsys_id_name(m->sender), + get_channel_id_name(m->channel)); + tor_free(arg); + } + + int i; + for (i=0; i < n_fns; ++i) { + if (ent->rcv[i].enabled) { + log_debug(LD_MESG, " Delivering to %s.", + get_subsys_id_name(ent->rcv[i].sys)); + ent->rcv[i].fn(m); + } + } +} + +/** + * Run up to max_msgs callbacks for messages on the channel ch + * on the given dispatcher. Return 0 on success or recoverable failure, + * -1 on unrecoverable error. + **/ +int +dispatch_flush(dispatch_t *d, channel_id_t ch, int max_msgs) +{ + if (BUG(ch >= d->n_queues)) + return 0; + + int n_flushed = 0; + dqueue_t *q = &d->queues[ch]; + + while (n_flushed < max_msgs) { + msg_t *m = TOR_SIMPLEQ_FIRST(&q->queue); + if (!m) + break; + TOR_SIMPLEQ_REMOVE_HEAD(&q->queue, next); + dispatcher_run_msg_cbs(d, m); + dispatch_free_msg(d, m); + ++n_flushed; + } + + return 0; +} diff --git a/src/lib/dispatch/dispatch_naming.c b/src/lib/dispatch/dispatch_naming.c new file mode 100644 index 0000000000..83d9a2d604 --- /dev/null +++ b/src/lib/dispatch/dispatch_naming.c @@ -0,0 +1,63 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" + +#include "lib/cc/compat_compiler.h" + +#include "lib/dispatch/dispatch_naming.h" +#include "lib/dispatch/msgtypes.h" + +#include "lib/container/namemap.h" +#include "lib/container/namemap_st.h" + +#include "lib/log/util_bug.h" +#include "lib/log/log.h" + +#include + +/** Global namemap for message IDs. */ +static namemap_t message_id_map = NAMEMAP_INIT(); +/** Global namemap for subsystem IDs. */ +static namemap_t subsys_id_map = NAMEMAP_INIT(); +/** Global namemap for channel IDs. */ +static namemap_t channel_id_map = NAMEMAP_INIT(); +/** Global namemap for message type IDs. */ +static namemap_t msg_type_id_map = NAMEMAP_INIT(); + +void +dispatch_naming_init(void) +{ +} + +/* Helper macro: declare functions to map IDs to and from names for a given + * type in a namemap_t. + */ +#define DECLARE_ID_MAP_FNS(type) \ + type##_id_t \ + get_##type##_id(const char *name) \ + { \ + unsigned u = namemap_get_or_create_id(&type##_id_map, name); \ + tor_assert(u != NAMEMAP_ERR); \ + tor_assert(u != ERROR_ID); \ + return (type##_id_t) u; \ + } \ + const char * \ + get_##type##_id_name(type##_id_t id) \ + { \ + return namemap_fmt_name(&type##_id_map, id); \ + } \ + size_t \ + get_num_##type##_ids(void) \ + { \ + return namemap_get_size(&type##_id_map); \ + } \ + EAT_SEMICOLON + +DECLARE_ID_MAP_FNS(message); +DECLARE_ID_MAP_FNS(channel); +DECLARE_ID_MAP_FNS(subsys); +DECLARE_ID_MAP_FNS(msg_type); diff --git a/src/lib/dispatch/dispatch_naming.h b/src/lib/dispatch/dispatch_naming.h new file mode 100644 index 0000000000..fd6c83cc12 --- /dev/null +++ b/src/lib/dispatch/dispatch_naming.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_DISPATCH_NAMING_H +#define TOR_DISPATCH_NAMING_H + +#include "lib/dispatch/msgtypes.h" +#include + +/** + * Return an existing channel ID by name, allocating the channel ID if + * if necessary. Returns ERROR_ID if we have run out of + * channels + */ +channel_id_t get_channel_id(const char *); +/** + * Return the name corresponding to a given channel ID. + **/ +const char *get_channel_id_name(channel_id_t); +/** + * Return the total number of _named_ channel IDs. + **/ +size_t get_num_channel_ids(void); + +/* As above, but for messages. */ +message_id_t get_message_id(const char *); +const char *get_message_id_name(message_id_t); +size_t get_num_message_ids(void); + +/* As above, but for subsystems */ +subsys_id_t get_subsys_id(const char *); +const char *get_subsys_id_name(subsys_id_t); +size_t get_num_subsys_ids(void); + +/* As above, but for types. Note that types additionally must be + * "defined", if any message is to use them. */ +msg_type_id_t get_msg_type_id(const char *); +const char *get_msg_type_id_name(msg_type_id_t); +size_t get_num_msg_type_ids(void); + +void dispatch_naming_init(void); + +#endif /* !defined(TOR_DISPATCH_NAMING_H) */ diff --git a/src/lib/dispatch/dispatch_new.c b/src/lib/dispatch/dispatch_new.c new file mode 100644 index 0000000000..b89ef43ea7 --- /dev/null +++ b/src/lib/dispatch/dispatch_new.c @@ -0,0 +1,174 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file dispatch_new.c + * \brief Code to construct a dispatch_t from a dispatch_cfg_t. + **/ + +#define DISPATCH_PRIVATE +#include "orconfig.h" + +#include "lib/dispatch/dispatch.h" +#include "lib/dispatch/dispatch_st.h" +#include "lib/dispatch/dispatch_cfg.h" +#include "lib/dispatch/dispatch_cfg_st.h" + +#include "lib/cc/ctassert.h" +#include "lib/intmath/cmp.h" +#include "lib/malloc/malloc.h" +#include "lib/log/util_bug.h" + +#include + +/** Given a smartlist full of (possibly NULL) pointers to uint16_t values, + * return the largest value, or dflt if the list is empty. */ +static int +max_in_sl(const smartlist_t *sl, int dflt) +{ + uint16_t *maxptr = NULL; + SMARTLIST_FOREACH_BEGIN(sl, uint16_t *, u) { + if (!maxptr) + maxptr = u; + else if (*u > *maxptr) + maxptr = u; + } SMARTLIST_FOREACH_END(u); + + return maxptr ? *maxptr : dflt; +} + +/* The above function is only safe to call if we are sure that channel_id_t + * and msg_type_id_t are really uint16_t. They should be so defined in + * msgtypes.h, but let's be extra cautious. + */ +CTASSERT(sizeof(uint16_t) == sizeof(msg_type_id_t)); +CTASSERT(sizeof(uint16_t) == sizeof(channel_id_t)); + +/** Helper: Format an unformattable message auxiliary data item: just return a +* copy of the string <>. */ +static char * +type_fmt_nop(msg_aux_data_t arg) +{ + (void)arg; + return tor_strdup("<>"); +} + +/** Helper: Free an unfreeable message auxiliary data item: do nothing. */ +static void +type_free_nop(msg_aux_data_t arg) +{ + (void)arg; +} + +/** Type functions to use when no type functions are provided. */ +static dispatch_typefns_t nop_typefns = { + .free_fn = type_free_nop, + .fmt_fn = type_fmt_nop +}; + +/** + * Alert function to use when none is configured: do nothing. + **/ +static void +alert_fn_nop(dispatch_t *d, channel_id_t ch, void *arg) +{ + (void)d; + (void)ch; + (void)arg; +} + +/** + * Given a list of recvfn_t, create and return a new dtbl_entry_t mapping + * to each of those functions. + **/ +static dtbl_entry_t * +dtbl_entry_from_lst(smartlist_t *receivers) +{ + if (!receivers) + return NULL; + + size_t n_recv = smartlist_len(receivers); + dtbl_entry_t *ent; + ent = tor_malloc_zero(offsetof(dtbl_entry_t, rcv) + + sizeof(dispatch_rcv_t) * n_recv); + + ent->n_fns = n_recv; + + SMARTLIST_FOREACH_BEGIN(receivers, const dispatch_rcv_t *, rcv) { + memcpy(&ent->rcv[rcv_sl_idx], rcv, sizeof(*rcv)); + if (rcv->enabled) { + ++ent->n_enabled; + } + } SMARTLIST_FOREACH_END(rcv); + + return ent; +} + +/** Create and return a new dispatcher from a given dispatch_cfg_t. */ +dispatch_t * +dispatch_new(const dispatch_cfg_t *cfg) +{ + dispatch_t *d = tor_malloc_zero(sizeof(dispatch_t)); + + /* Any message that has a type or a receiver counts towards our messages */ + const size_t n_msgs = MAX(smartlist_len(cfg->type_by_msg), + smartlist_len(cfg->recv_by_msg)) + 1; + + /* Any channel that any message has counts towards the number of channels. */ + const size_t n_chans = (size_t) MAX(1, max_in_sl(cfg->chan_by_msg,0)) + 1; + + /* Any type that a message has, or that has functions, counts towards + * the number of types. */ + const size_t n_types = (size_t) MAX(max_in_sl(cfg->type_by_msg,0), + smartlist_len(cfg->fns_by_type)) + 1; + + d->n_msgs = n_msgs; + d->n_queues = n_chans; + d->n_types = n_types; + + /* Initialize the array of type-functions. */ + d->typefns = tor_calloc(n_types, sizeof(dispatch_typefns_t)); + for (size_t i = 0; i < n_types; ++i) { + /* Default to no-op for everything... */ + memcpy(&d->typefns[i], &nop_typefns, sizeof(dispatch_typefns_t)); + } + SMARTLIST_FOREACH_BEGIN(cfg->fns_by_type, dispatch_typefns_t *, fns) { + /* Set the functions if they are provided. */ + if (fns) { + if (fns->free_fn) + d->typefns[fns_sl_idx].free_fn = fns->free_fn; + if (fns->fmt_fn) + d->typefns[fns_sl_idx].fmt_fn = fns->fmt_fn; + } + } SMARTLIST_FOREACH_END(fns); + + /* Initialize the message queues: one for each channel. */ + d->queues = tor_calloc(d->n_queues, sizeof(dqueue_t)); + for (size_t i = 0; i < d->n_queues; ++i) { + TOR_SIMPLEQ_INIT(&d->queues[i].queue); + d->queues[i].alert_fn = alert_fn_nop; + } + + /* Build the dispatch tables mapping message IDs to receivers. */ + d->table = tor_calloc(d->n_msgs, sizeof(dtbl_entry_t *)); + SMARTLIST_FOREACH_BEGIN(cfg->recv_by_msg, smartlist_t *, rcv) { + d->table[rcv_sl_idx] = dtbl_entry_from_lst(rcv); + } SMARTLIST_FOREACH_END(rcv); + + /* Fill in the empty entries in the dispatch tables: + * types and channels for each message. */ + SMARTLIST_FOREACH_BEGIN(cfg->type_by_msg, msg_type_id_t *, type) { + if (d->table[type_sl_idx]) + d->table[type_sl_idx]->type = *type; + } SMARTLIST_FOREACH_END(type); + + SMARTLIST_FOREACH_BEGIN(cfg->chan_by_msg, channel_id_t *, chan) { + if (d->table[chan_sl_idx]) + d->table[chan_sl_idx]->channel = *chan; + } SMARTLIST_FOREACH_END(chan); + + return d; +} diff --git a/src/lib/dispatch/dispatch_st.h b/src/lib/dispatch/dispatch_st.h new file mode 100644 index 0000000000..ee42518b5a --- /dev/null +++ b/src/lib/dispatch/dispatch_st.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file dispatch_st.h + * + * \brief private structures used for the dispatcher module + */ + +#ifndef TOR_DISPATCH_ST_H +#define TOR_DISPATCH_ST_H + +#ifdef DISPATCH_PRIVATE + +#include "lib/container/smartlist.h" + +/** + * Information about the recipient of a message. + **/ +typedef struct dispatch_rcv_t { + /** The subsystem receiving a message. */ + subsys_id_t sys; + /** True iff this recipient is enabled. */ + bool enabled; + /** The function that will handle the message. */ + recv_fn_t fn; +} dispatch_rcv_t; + +/** + * Information used by a dispatcher to handle and dispatch a single message + * ID. It maps that message ID to its type, channel, and list of receiver + * functions. + * + * This structure is used when the dispatcher is running. + **/ +typedef struct dtbl_entry_t { + /** The number of enabled non-stub subscribers for this message. + * + * Note that for now, this will be the same as n_fns, since there is + * no way to turn these subscribers on an off yet. */ + uint16_t n_enabled; + /** The channel that handles this message. */ + channel_id_t channel; + /** The associated C type for this message. */ + msg_type_id_t type; + /** + * The number of functions pointers for subscribers that receive this + * message, in rcv. */ + uint16_t n_fns; + /** + * The recipients for this message. + */ + dispatch_rcv_t rcv[FLEXIBLE_ARRAY_MEMBER]; +} dtbl_entry_t; + +/** + * A queue of messages for a given channel, used by a live dispatcher. + */ +typedef struct dqueue_t { + /** The queue of messages itself. */ + TOR_SIMPLEQ_HEAD( , msg_t) queue; + /** A function to be called when the queue becomes nonempty. */ + dispatch_alertfn_t alert_fn; + /** An argument for the alert_fn. */ + void *alert_fn_arg; +} dqueue_t ; + +/** + * A single dispatcher for cross-module messages. + */ +struct dispatch_t { + /** + * The length of table: the number of message IDs that this + * dispatcher can handle. + */ + size_t n_msgs; + /** + * The length of queues: the number of channels that this dispatcher + * has configured. + */ + size_t n_queues; + /** + * The length of typefns: the number of C type IDs that this + * dispatcher has configured. + */ + size_t n_types; + /** + * An array of message queues, indexed by channel ID. + */ + dqueue_t *queues; + /** + * An array of entries about how to handle particular message types, indexed + * by message ID. + */ + dtbl_entry_t **table; + /** + * An array of function tables for manipulating types, index by message + * type ID. + **/ + dispatch_typefns_t *typefns; +}; + +#endif /* defined(DISPATCH_PRIVATE) */ + +#endif /* !defined(TOR_DISPATCH_ST_H) */ diff --git a/src/lib/dispatch/include.am b/src/lib/dispatch/include.am new file mode 100644 index 0000000000..4a0e0dfd90 --- /dev/null +++ b/src/lib/dispatch/include.am @@ -0,0 +1,27 @@ + +noinst_LIBRARIES += src/lib/libtor-dispatch.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-dispatch-testing.a +endif + +# ADD_C_FILE: INSERT SOURCES HERE. +src_lib_libtor_dispatch_a_SOURCES = \ + src/lib/dispatch/dispatch_cfg.c \ + src/lib/dispatch/dispatch_core.c \ + src/lib/dispatch/dispatch_naming.c \ + src/lib/dispatch/dispatch_new.c + +src_lib_libtor_dispatch_testing_a_SOURCES = \ + $(src_lib_libtor_dispatch_a_SOURCES) +src_lib_libtor_dispatch_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_dispatch_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/lib/dispatch/dispatch.h \ + src/lib/dispatch/dispatch_cfg.h \ + src/lib/dispatch/dispatch_cfg_st.h \ + src/lib/dispatch/dispatch_naming.h \ + src/lib/dispatch/dispatch_st.h \ + src/lib/dispatch/msgtypes.h diff --git a/src/lib/dispatch/msgtypes.h b/src/lib/dispatch/msgtypes.h new file mode 100644 index 0000000000..b4c4a10248 --- /dev/null +++ b/src/lib/dispatch/msgtypes.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file msgtypes.h + * \brief Types used for messages in the dispatcher code. + **/ + +#ifndef TOR_DISPATCH_MSGTYPES_H +#define TOR_DISPATCH_MSGTYPES_H + +#include + +#include "ext/tor_queue.h" + +/** + * These types are aliases for subsystems, channels, and message IDs. + **/ +typedef uint16_t subsys_id_t; +typedef uint16_t channel_id_t; +typedef uint16_t message_id_t; + +/** + * This identifies a C type that can be sent along with a message. + **/ +typedef uint16_t msg_type_id_t; + +/** + * An ID value returned for *_type_t when none exists. + */ +#define ERROR_ID 65535 + +/** + * Auxiliary (untyped) data sent along with a message. + * + * We define this as a union of a pointer and a u64, so that the integer + * types will have the same range across platforms. + **/ +typedef union { + void *ptr; + uint64_t u64; +} msg_aux_data_t; + +/** + * Structure of a received message. + **/ +typedef struct msg_t { + TOR_SIMPLEQ_ENTRY(msg_t) next; + subsys_id_t sender; + channel_id_t channel; + message_id_t msg; + /** We could omit this field, since it is implicit in the message type, but + * IMO let's leave it in for safety. */ + msg_type_id_t type; + /** Untyped auxiliary data. You shouldn't have to mess with this + * directly. */ + msg_aux_data_t aux_data__; +} msg_t; + +/** + * A function that a subscriber uses to receive a message. + **/ +typedef void (*recv_fn_t)(const msg_t *m); + +/** + * Table of functions to use for a given C type. Any omitted (NULL) functions + * will be treated as no-ops. + **/ +typedef struct dispatch_typefns_t { + /** Release storage held for the auxiliary data of this type. */ + void (*free_fn)(msg_aux_data_t); + /** Format and return a newly allocated string describing the contents + * of this data element. */ + char *(*fmt_fn)(msg_aux_data_t); +} dispatch_typefns_t; + +#endif /* !defined(TOR_DISPATCH_MSGTYPES_H) */ diff --git a/src/lib/encoding/binascii.c b/src/lib/encoding/binascii.c index de4d1648bb..fc64e014e7 100644 --- a/src/lib/encoding/binascii.c +++ b/src/lib/encoding/binascii.c @@ -84,7 +84,7 @@ base32_encode(char *dest, size_t destlen, const char *src, size_t srclen) } /** Implements base32 decoding as in RFC 4648. - * Returns 0 if successful, -1 otherwise. + * Return the number of bytes decoded if successful; -1 otherwise. */ int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen) @@ -147,7 +147,7 @@ base32_decode(char *dest, size_t destlen, const char *src, size_t srclen) memset(tmp, 0, srclen); /* on the heap, this should be safe */ tor_free(tmp); tmp = NULL; - return 0; + return i; } #define BASE64_OPENSSL_LINELEN 64 @@ -321,8 +321,10 @@ base64_encode(char *dest, size_t destlen, const char *src, size_t srclen, return (int) enclen; } -/** As base64_encode, but do not add any internal spaces or external padding - * to the output stream. */ +/** As base64_encode, but do not add any internal spaces, and remove external + * padding from the output stream. + * dest must be at least base64_encode_size(srclen, 0), including space for + * the removed external padding. */ int base64_encode_nopad(char *dest, size_t destlen, const uint8_t *src, size_t srclen) diff --git a/src/lib/encoding/binascii.h b/src/lib/encoding/binascii.h index 44998bb85b..40c5593b11 100644 --- a/src/lib/encoding/binascii.h +++ b/src/lib/encoding/binascii.h @@ -58,4 +58,4 @@ size_t base32_encoded_size(size_t srclen); void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen); int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen); -#endif /* !defined(TOR_UTIL_FORMAT_H) */ +#endif /* !defined(TOR_BINASCII_H) */ diff --git a/src/lib/encoding/confline.c b/src/lib/encoding/confline.c index 8110f3dd9c..fdb575e03f 100644 --- a/src/lib/encoding/confline.c +++ b/src/lib/encoding/confline.c @@ -82,6 +82,19 @@ config_line_find(const config_line_t *lines, return NULL; } +/** As config_line_find(), but perform a case-insensitive comparison. */ +const config_line_t * +config_line_find_case(const config_line_t *lines, + const char *key) +{ + const config_line_t *cl; + for (cl = lines; cl; cl = cl->next) { + if (!strcasecmp(cl->key, key)) + return cl; + } + return NULL; +} + /** Auxiliary function that does all the work of config_get_lines. * recursion_level is the count of how many nested %includes we have. * opened_lst will have a list of opened files if provided. diff --git a/src/lib/encoding/confline.h b/src/lib/encoding/confline.h index 3d9ae8a662..56ea36bf61 100644 --- a/src/lib/encoding/confline.h +++ b/src/lib/encoding/confline.h @@ -48,6 +48,8 @@ config_line_t *config_lines_dup_and_filter(const config_line_t *inp, const char *key); const config_line_t *config_line_find(const config_line_t *lines, const char *key); +const config_line_t *config_line_find_case(const config_line_t *lines, + const char *key); int config_lines_eq(config_line_t *a, config_line_t *b); int config_count_key(const config_line_t *a, const char *key); void config_free_lines_(config_line_t *front); diff --git a/src/lib/encoding/include.am b/src/lib/encoding/include.am index 83e9211b6f..48d0120bfc 100644 --- a/src/lib/encoding/include.am +++ b/src/lib/encoding/include.am @@ -4,6 +4,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-encoding-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_encoding_a_SOURCES = \ src/lib/encoding/binascii.c \ src/lib/encoding/confline.c \ @@ -11,6 +12,7 @@ src_lib_libtor_encoding_a_SOURCES = \ src/lib/encoding/keyval.c \ src/lib/encoding/kvline.c \ src/lib/encoding/pem.c \ + src/lib/encoding/qstring.c \ src/lib/encoding/time_fmt.c src_lib_libtor_encoding_testing_a_SOURCES = \ @@ -18,6 +20,7 @@ src_lib_libtor_encoding_testing_a_SOURCES = \ src_lib_libtor_encoding_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_encoding_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/encoding/binascii.h \ src/lib/encoding/confline.h \ @@ -25,4 +28,5 @@ noinst_HEADERS += \ src/lib/encoding/keyval.h \ src/lib/encoding/kvline.h \ src/lib/encoding/pem.h \ + src/lib/encoding/qstring.h \ src/lib/encoding/time_fmt.h diff --git a/src/lib/encoding/keyval.h b/src/lib/encoding/keyval.h index cd327b7a82..dcddfa3396 100644 --- a/src/lib/encoding/keyval.h +++ b/src/lib/encoding/keyval.h @@ -14,4 +14,4 @@ int string_is_key_value(int severity, const char *string); -#endif +#endif /* !defined(TOR_KEYVAL_H) */ diff --git a/src/lib/encoding/kvline.c b/src/lib/encoding/kvline.c index 307adc3f12..d4a8f510ba 100644 --- a/src/lib/encoding/kvline.c +++ b/src/lib/encoding/kvline.c @@ -16,6 +16,7 @@ #include "lib/encoding/confline.h" #include "lib/encoding/cstring.h" #include "lib/encoding/kvline.h" +#include "lib/encoding/qstring.h" #include "lib/malloc/malloc.h" #include "lib/string/compat_ctype.h" #include "lib/string/printf.h" @@ -53,6 +54,15 @@ line_has_no_key(const config_line_t *line) return line->key == NULL || strlen(line->key) == 0; } +/** + * Return true iff the value in line is not set. + **/ +static bool +line_has_no_val(const config_line_t *line) +{ + return line->value == NULL || strlen(line->value) == 0; +} + /** * Return true iff the all the lines in line can be encoded * using flags. @@ -98,14 +108,25 @@ kvline_can_encode_lines(const config_line_t *line, unsigned flags) * If KV_OMIT_KEYS is set in flags, then pairs with empty keys are * allowed, and are encoded as 'Value'. Otherwise, such pairs are not * allowed. + * + * If KV_OMIT_VALS is set in flags, then an empty value is + * encoded as 'Key', not as 'Key=' or 'Key=""'. Mutually exclusive with + * KV_OMIT_KEYS. + * + * KV_QUOTED_QSTRING is not supported. */ char * kvline_encode(const config_line_t *line, unsigned flags) { + 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)); + smartlist_t *elements = smartlist_new(); for (; line; line = line->next) { @@ -126,7 +147,10 @@ kvline_encode(const config_line_t *line, } } - if (esc) { + if ((flags & KV_OMIT_VALS) && line_has_no_val(line)) { + eq = ""; + v = ""; + } else if (esc) { tmp = esc_for_log(line->value); v = tmp; } else { @@ -151,17 +175,30 @@ kvline_encode(const config_line_t *line, * allocated list of pairs on success, or NULL on failure. * * If KV_QUOTED is set in flags, then (double-)quoted values are - * allowed. Otherwise, such values are not allowed. + * allowed and handled as C strings. Otherwise, such values are not allowed. * * If KV_OMIT_KEYS is set in flags, then values without keys are * allowed. Otherwise, such values are not allowed. + * + * If KV_OMIT_VALS is set in flags, then keys without values are + * allowed. Otherwise, such keys are not allowed. Mutually exclusive with + * KV_OMIT_KEYS. + * + * If KV_QUOTED_QSTRING is set in flags, then double-quoted values + * are allowed and handled as QuotedStrings per qstring.c. Do not add + * new users of this flag. */ 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)); + const char *cp = line, *cplast = NULL; - bool omit_keys = (flags & KV_OMIT_KEYS) != 0; - bool quoted = (flags & KV_QUOTED) != 0; + const bool omit_keys = (flags & KV_OMIT_KEYS) != 0; + const bool omit_vals = (flags & KV_OMIT_VALS) != 0; + const bool quoted = (flags & (KV_QUOTED|KV_QUOTED_QSTRING)) != 0; + const bool c_quoted = (flags & (KV_QUOTED)) != 0; config_line_t *result = NULL; config_line_t **next_line = &result; @@ -171,27 +208,33 @@ kvline_parse(const char *line, unsigned flags) while (*cp) { key = val = NULL; + /* skip all spaces */ { size_t idx = strspn(cp, " \t\r\v\n"); cp += idx; } if (BUG(cp == cplast)) { - /* If we didn't parse anything, this code is broken. */ + /* If we didn't parse anything since the last loop, this code is + * broken. */ goto err; // LCOV_EXCL_LINE } cplast = cp; if (! *cp) break; /* End of string; we're done. */ - /* Possible formats are K=V, K="V", V, and "V", depending on flags. */ + /* Possible formats are K=V, K="V", K, V, and "V", depending on flags. */ - /* Find the key. */ + /* Find where the key ends */ if (*cp != '\"') { size_t idx = strcspn(cp, " \t\r\v\n="); if (cp[idx] == '=') { key = tor_memdup_nulterm(cp, idx); cp += idx + 1; + } else if (omit_vals) { + key = tor_memdup_nulterm(cp, idx); + cp += idx; + goto commit; } else { if (!omit_keys) goto err; @@ -203,7 +246,11 @@ kvline_parse(const char *line, unsigned flags) if (!quoted) goto err; size_t len=0; - cp = unescape_string(cp, &val, &len); + if (c_quoted) { + cp = unescape_string(cp, &val, &len); + } else { + cp = decode_qstring(cp, strlen(cp), &val, &len); + } if (cp == NULL || len != strlen(val)) { // The string contains a NUL or is badly coded. goto err; @@ -214,6 +261,7 @@ kvline_parse(const char *line, unsigned flags) cp += idx; } + commit: if (key && strlen(key) == 0) { /* We don't allow empty keys. */ goto err; @@ -221,13 +269,15 @@ kvline_parse(const char *line, unsigned flags) *next_line = tor_malloc_zero(sizeof(config_line_t)); (*next_line)->key = key ? key : tor_strdup(""); - (*next_line)->value = val; + (*next_line)->value = val ? val : tor_strdup(""); next_line = &(*next_line)->next; key = val = NULL; } - if (!kvline_can_encode_lines(result, flags)) { - goto err; + if (! (flags & KV_QUOTED_QSTRING)) { + if (!kvline_can_encode_lines(result, flags)) { + goto err; + } } return result; diff --git a/src/lib/encoding/kvline.h b/src/lib/encoding/kvline.h index 4eed30a223..dea2ce1809 100644 --- a/src/lib/encoding/kvline.h +++ b/src/lib/encoding/kvline.h @@ -17,6 +17,8 @@ struct config_line_t; #define KV_QUOTED (1u<<0) #define KV_OMIT_KEYS (1u<<1) +#define KV_OMIT_VALS (1u<<2) +#define KV_QUOTED_QSTRING (1u<<3) 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/lib/encoding/pem.h b/src/lib/encoding/pem.h index 0bbb06a794..6b20350aa8 100644 --- a/src/lib/encoding/pem.h +++ b/src/lib/encoding/pem.h @@ -23,4 +23,4 @@ int pem_encode(char *dest, size_t destlen, const uint8_t *src, size_t srclen, int pem_decode(uint8_t *dest, size_t destlen, const char *src, size_t srclen, const char *objtype); -#endif +#endif /* !defined(TOR_PEM_H) */ diff --git a/src/lib/encoding/qstring.c b/src/lib/encoding/qstring.c new file mode 100644 index 0000000000..a92d28c706 --- /dev/null +++ b/src/lib/encoding/qstring.c @@ -0,0 +1,90 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file qstring.c + * \brief Implement QuotedString parsing. + * + * Note that this is only used for controller authentication; do not + * create new users for this. Instead, prefer the cstring.c functions. + **/ + +#include "orconfig.h" +#include "lib/encoding/qstring.h" +#include "lib/malloc/malloc.h" +#include "lib/log/util_bug.h" + +/** If the first in_len_max characters in start contain a + * QuotedString, return the length of that + * string (as encoded, including quotes). Otherwise return -1. */ +static inline int +get_qstring_length(const char *start, size_t in_len_max, + int *chars_out) +{ + const char *cp, *end; + int chars = 0; + + if (*start != '\"') + return -1; + + cp = start+1; + end = start+in_len_max; + + /* Calculate length. */ + while (1) { + if (cp >= end) { + return -1; /* Too long. */ + } else if (*cp == '\\') { + if (++cp == end) + return -1; /* Can't escape EOS. */ + ++cp; + ++chars; + } else if (*cp == '\"') { + break; + } else { + ++cp; + ++chars; + } + } + if (chars_out) + *chars_out = chars; + return (int)(cp - start+1); +} + +/** Given a pointer to a string starting at start containing + * in_len_max characters, decode a string beginning with one double + * quote, containing any number of non-quote characters or characters escaped + * with a backslash, and ending with a final double quote. Place the resulting + * string (unquoted, unescaped) into a newly allocated string in *out; + * store its length in out_len. On success, return a pointer to the + * character immediately following the escaped string. On failure, return + * NULL. */ +const char * +decode_qstring(const char *start, size_t in_len_max, + char **out, size_t *out_len) +{ + const char *cp, *end; + char *outp; + int len, n_chars = 0; + + len = get_qstring_length(start, in_len_max, &n_chars); + if (len<0) + return NULL; + + end = start+len-1; /* Index of last quote. */ + tor_assert(*end == '\"'); + outp = *out = tor_malloc(len+1); + *out_len = n_chars; + + cp = start+1; + while (cp < end) { + if (*cp == '\\') + ++cp; + *outp++ = *cp++; + } + *outp = '\0'; + tor_assert((outp - *out) == (int)*out_len); + + return end+1; +} diff --git a/src/lib/encoding/qstring.h b/src/lib/encoding/qstring.h new file mode 100644 index 0000000000..840e1044ce --- /dev/null +++ b/src/lib/encoding/qstring.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file qstring.h + * \brief Header for qstring.c + */ + +#ifndef TOR_ENCODING_QSTRING_H +#define TOR_ENCODING_QSTRING_H + +#include + +const char *decode_qstring(const char *start, size_t in_len_max, + char **out, size_t *out_len); + +#endif /* !defined(TOR_ENCODING_QSTRING_H) */ diff --git a/src/lib/encoding/time_fmt.h b/src/lib/encoding/time_fmt.h index 0ddeca57fc..d14bc1f902 100644 --- a/src/lib/encoding/time_fmt.h +++ b/src/lib/encoding/time_fmt.h @@ -41,4 +41,4 @@ int parse_iso_time_nospace(const char *cp, time_t *t); int parse_http_time(const char *buf, struct tm *tm); int format_time_interval(char *out, size_t out_len, long interval); -#endif +#endif /* !defined(TOR_TIME_FMT_H) */ diff --git a/src/lib/err/.may_include b/src/lib/err/.may_include index daa1b6e4ca..314424545e 100644 --- a/src/lib/err/.may_include +++ b/src/lib/err/.may_include @@ -1,5 +1,6 @@ orconfig.h lib/cc/*.h +lib/defs/*.h lib/err/*.h lib/subsys/*.h -lib/version/*.h \ No newline at end of file +lib/version/*.h diff --git a/src/lib/err/backtrace.c b/src/lib/err/backtrace.c index 1d1b3bcfa3..e6cbe3d326 100644 --- a/src/lib/err/backtrace.c +++ b/src/lib/err/backtrace.c @@ -115,7 +115,7 @@ clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx) * that with a backtrace log. Send messages via the tor_log function at * logger". */ void -log_backtrace_impl(int severity, int domain, const char *msg, +log_backtrace_impl(int severity, log_domain_mask_t domain, const char *msg, tor_log_fn logger) { size_t depth; @@ -240,7 +240,7 @@ remove_bt_handler(void) #ifdef NO_BACKTRACE_IMPL void -log_backtrace_impl(int severity, int domain, const char *msg, +log_backtrace_impl(int severity, log_domain_mask_t domain, const char *msg, tor_log_fn logger) { logger(severity, domain, "%s. (Stack trace not available)", msg); diff --git a/src/lib/err/backtrace.h b/src/lib/err/backtrace.h index 9b313261e6..dcd22cfef2 100644 --- a/src/lib/err/backtrace.h +++ b/src/lib/err/backtrace.h @@ -12,11 +12,14 @@ #include "orconfig.h" #include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" +#include "lib/defs/logging_types.h" -typedef void (*tor_log_fn)(int, unsigned, const char *fmt, ...) +typedef void (*tor_log_fn)(int, log_domain_mask_t, const char *fmt, ...) CHECK_PRINTF(3,4); -void log_backtrace_impl(int severity, int domain, const char *msg, +void log_backtrace_impl(int severity, log_domain_mask_t domain, + const char *msg, tor_log_fn logger); int configure_backtrace_handler(const char *tor_version); void clean_up_backtrace_handler(void); diff --git a/src/lib/err/include.am b/src/lib/err/include.am index 43adcd2694..883ac91511 100644 --- a/src/lib/err/include.am +++ b/src/lib/err/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-err-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_err_a_SOURCES = \ src/lib/err/backtrace.c \ src/lib/err/torerr.c \ @@ -15,6 +16,7 @@ src_lib_libtor_err_testing_a_SOURCES = \ src_lib_libtor_err_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_err_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/err/backtrace.h \ src/lib/err/torerr.h \ diff --git a/src/lib/err/torerr.h b/src/lib/err/torerr.h index 0badaf7c6d..c2da6697a9 100644 --- a/src/lib/err/torerr.h +++ b/src/lib/err/torerr.h @@ -45,4 +45,4 @@ void tor_log_sigsafe_err_set_granularity(int ms); int format_hex_number_sigsafe(unsigned long x, char *buf, int max_len); int format_dec_number_sigsafe(unsigned long x, char *buf, int max_len); -#endif /* !defined(TOR_TORLOG_H) */ +#endif /* !defined(TOR_TORERR_H) */ diff --git a/src/lib/evloop/include.am b/src/lib/evloop/include.am index 6b0076272a..6595b3a34b 100644 --- a/src/lib/evloop/include.am +++ b/src/lib/evloop/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-evloop-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_evloop_a_SOURCES = \ src/lib/evloop/compat_libevent.c \ src/lib/evloop/procmon.c \ @@ -12,12 +13,12 @@ src_lib_libtor_evloop_a_SOURCES = \ src/lib/evloop/token_bucket.c \ src/lib/evloop/workqueue.c - src_lib_libtor_evloop_testing_a_SOURCES = \ $(src_lib_libtor_evloop_a_SOURCES) src_lib_libtor_evloop_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_evloop_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/evloop/compat_libevent.h \ src/lib/evloop/procmon.h \ diff --git a/src/lib/evloop/token_bucket.h b/src/lib/evloop/token_bucket.h index 9398d2baa3..1ce6f1bf94 100644 --- a/src/lib/evloop/token_bucket.h +++ b/src/lib/evloop/token_bucket.h @@ -112,6 +112,6 @@ token_bucket_rw_get_write(const token_bucket_rw_t *bucket) STATIC uint32_t rate_per_sec_to_rate_per_step(uint32_t rate); -#endif +#endif /* defined(TOKEN_BUCKET_PRIVATE) */ -#endif /* TOR_TOKEN_BUCKET_H */ +#endif /* !defined(TOR_TOKEN_BUCKET_H) */ diff --git a/src/lib/evloop/workqueue.c b/src/lib/evloop/workqueue.c index b36a02da5e..015b694290 100644 --- a/src/lib/evloop/workqueue.c +++ b/src/lib/evloop/workqueue.c @@ -59,9 +59,6 @@ struct threadpool_s { * p is work[p]. */ work_tailq_t work[WORKQUEUE_N_PRIORITIES]; - /** Weak RNG, used to decide when to ignore priority. */ - tor_weak_rng_t weak_rng; - /** The current 'update generation' of the threadpool. Any thread that is * at an earlier generation needs to run the update function. */ unsigned generation; @@ -238,7 +235,7 @@ worker_thread_extract_next_work(workerthread_t *thread) this_queue = &pool->work[i]; if (!TOR_TAILQ_EMPTY(this_queue)) { queue = this_queue; - if (! tor_weak_random_one_in_n(&pool->weak_rng, + if (! crypto_fast_rng_one_in_n(get_thread_fast_rng(), thread->lower_priority_chance)) { /* Usually we'll just break now, so that we can get out of the loop * and use the queue where we found work. But with a small @@ -555,11 +552,6 @@ threadpool_new(int n_threads, for (i = WORKQUEUE_PRIORITY_FIRST; i <= WORKQUEUE_PRIORITY_LAST; ++i) { TOR_TAILQ_INIT(&pool->work[i]); } - { - unsigned seed; - crypto_rand((void*)&seed, sizeof(seed)); - tor_init_weak_random(&pool->weak_rng, seed); - } pool->new_thread_state_fn = new_thread_state_fn; pool->new_thread_state_arg = arg; diff --git a/src/lib/fdio/include.am b/src/lib/fdio/include.am index 6c18f00a0d..545bbc929e 100644 --- a/src/lib/fdio/include.am +++ b/src/lib/fdio/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-fdio-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_fdio_a_SOURCES = \ src/lib/fdio/fdio.c @@ -13,5 +14,6 @@ src_lib_libtor_fdio_testing_a_SOURCES = \ src_lib_libtor_fdio_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_fdio_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/fdio/fdio.h diff --git a/src/lib/fs/conffile.h b/src/lib/fs/conffile.h index 7af9119dbb..29115e1085 100644 --- a/src/lib/fs/conffile.h +++ b/src/lib/fs/conffile.h @@ -20,4 +20,4 @@ int config_get_lines_include(const char *string, struct config_line_t **result, int extended, int *has_include, struct smartlist_t *opened_lst); -#endif /* !defined(TOR_CONFLINE_H) */ +#endif /* !defined(TOR_CONFFILE_H) */ diff --git a/src/lib/fs/dir.h b/src/lib/fs/dir.h index 826bc2dfc5..9ff81faa42 100644 --- a/src/lib/fs/dir.h +++ b/src/lib/fs/dir.h @@ -30,4 +30,4 @@ MOCK_DECL(int, check_private_dir, (const char *dirname, cpd_check_t check, MOCK_DECL(struct smartlist_t *, tor_listdir, (const char *dirname)); -#endif +#endif /* !defined(TOR_DIR_H) */ diff --git a/src/lib/fs/files.h b/src/lib/fs/files.h index 52c94c914f..81dba8c140 100644 --- a/src/lib/fs/files.h +++ b/src/lib/fs/files.h @@ -27,7 +27,7 @@ #ifdef HAVE_SYS_STAT_H #include #endif -#endif +#endif /* defined(_WIN32) */ #ifndef O_BINARY #define O_BINARY 0 @@ -108,7 +108,7 @@ char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, * Tor is built for unit tests, or when Tor is built on an operating system * without its own getdelim(). */ ssize_t compat_getdelim_(char **lineptr, size_t *n, int delim, FILE *stream); -#endif +#endif /* !defined(HAVE_GETDELIM) || defined(TOR_UNIT_TESTS) */ #ifdef HAVE_GETDELIM /** @@ -123,10 +123,10 @@ ssize_t compat_getdelim_(char **lineptr, size_t *n, int delim, FILE *stream); */ #define tor_getdelim(lineptr, n, delim, stream) \ getdelim((lineptr), (n), (delim), (stream)) -#else +#else /* !(defined(HAVE_GETDELIM)) */ #define tor_getdelim(lineptr, n, delim, stream) \ compat_getdelim_((lineptr), (n), (delim), (stream)) -#endif +#endif /* defined(HAVE_GETDELIM) */ #ifdef HAVE_GETLINE /** @@ -137,9 +137,9 @@ ssize_t compat_getdelim_(char **lineptr, size_t *n, int delim, FILE *stream); */ #define tor_getline(lineptr, n, stream) \ getline((lineptr), (n), (stream)) -#else +#else /* !(defined(HAVE_GETLINE)) */ #define tor_getline(lineptr, n, stream) \ tor_getdelim((lineptr), (n), '\n', (stream)) -#endif +#endif /* defined(HAVE_GETLINE) */ -#endif +#endif /* !defined(TOR_FS_H) */ diff --git a/src/lib/fs/include.am b/src/lib/fs/include.am index f33e4d6430..493db8f044 100644 --- a/src/lib/fs/include.am +++ b/src/lib/fs/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-fs-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_fs_a_SOURCES = \ src/lib/fs/conffile.c \ src/lib/fs/dir.c \ @@ -25,6 +26,7 @@ src_lib_libtor_fs_testing_a_SOURCES = \ src_lib_libtor_fs_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_fs_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/fs/conffile.h \ src/lib/fs/dir.h \ diff --git a/src/lib/fs/lockfile.h b/src/lib/fs/lockfile.h index 8aeee4cc7f..fc0281e253 100644 --- a/src/lib/fs/lockfile.h +++ b/src/lib/fs/lockfile.h @@ -17,4 +17,4 @@ tor_lockfile_t *tor_lockfile_lock(const char *filename, int blocking, int *locked_out); void tor_lockfile_unlock(tor_lockfile_t *lockfile); -#endif +#endif /* !defined(TOR_LOCKFILE_H) */ diff --git a/src/lib/fs/mmap.c b/src/lib/fs/mmap.c index daaee1f9b1..f71c0cff7a 100644 --- a/src/lib/fs/mmap.c +++ b/src/lib/fs/mmap.c @@ -237,4 +237,4 @@ tor_munmap_file(tor_mmap_t *handle) } #else #error "cannot implement tor_mmap_file" -#endif /* defined(HAVE_MMAP) || ... || ... */ +#endif /* defined(HAVE_MMAP) || defined(RUNNING_DOXYGEN) || ... */ diff --git a/src/lib/fs/mmap.h b/src/lib/fs/mmap.h index 18fb18a13c..61aad544b2 100644 --- a/src/lib/fs/mmap.h +++ b/src/lib/fs/mmap.h @@ -38,4 +38,4 @@ typedef struct tor_mmap_t { tor_mmap_t *tor_mmap_file(const char *filename); int tor_munmap_file(tor_mmap_t *handle); -#endif +#endif /* !defined(TOR_MMAP_H) */ diff --git a/src/lib/fs/path.h b/src/lib/fs/path.h index 4675ac84e8..28a1838b88 100644 --- a/src/lib/fs/path.h +++ b/src/lib/fs/path.h @@ -27,4 +27,4 @@ void clean_fname_for_stat(char *name); int get_parent_directory(char *fname); char *make_path_absolute(char *fname); -#endif +#endif /* !defined(TOR_PATH_H) */ diff --git a/src/lib/fs/userdb.h b/src/lib/fs/userdb.h index 5c39794873..5e5ddb89a3 100644 --- a/src/lib/fs/userdb.h +++ b/src/lib/fs/userdb.h @@ -21,6 +21,6 @@ struct passwd; const struct passwd *tor_getpwnam(const char *username); const struct passwd *tor_getpwuid(uid_t uid); char *get_user_homedir(const char *username); -#endif +#endif /* !defined(_WIN32) */ -#endif +#endif /* !defined(TOR_USERDB_H) */ diff --git a/src/lib/fs/winlib.h b/src/lib/fs/winlib.h index 64a22439e5..7237226c76 100644 --- a/src/lib/fs/winlib.h +++ b/src/lib/fs/winlib.h @@ -17,6 +17,6 @@ #include HANDLE load_windows_system_library(const TCHAR *library_name); -#endif +#endif /* defined(_WIN32) */ -#endif +#endif /* !defined(TOR_WINLIB_H) */ diff --git a/src/lib/geoip/country.h b/src/lib/geoip/country.h index 9a8911d494..a24a1c4c0d 100644 --- a/src/lib/geoip/country.h +++ b/src/lib/geoip/country.h @@ -13,4 +13,4 @@ typedef int16_t country_t; #define COUNTRY_MAX INT16_MAX -#endif +#endif /* !defined(TOR_COUNTRY_H) */ diff --git a/src/lib/geoip/include.am b/src/lib/geoip/include.am index 9710d75ac7..ea426d14bc 100644 --- a/src/lib/geoip/include.am +++ b/src/lib/geoip/include.am @@ -4,6 +4,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-geoip-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_geoip_a_SOURCES = \ src/lib/geoip/geoip.c @@ -12,6 +13,7 @@ src_lib_libtor_geoip_testing_a_SOURCES = \ src_lib_libtor_geoip_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_geoip_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/geoip/geoip.h \ src/lib/geoip/country.h diff --git a/src/lib/intmath/addsub.h b/src/lib/intmath/addsub.h index 83efa82919..3f745d457d 100644 --- a/src/lib/intmath/addsub.h +++ b/src/lib/intmath/addsub.h @@ -16,4 +16,4 @@ uint32_t tor_add_u32_nowrap(uint32_t a, uint32_t b); -#endif /* !defined(TOR_INTMATH_MULDIV_H) */ +#endif /* !defined(TOR_INTMATH_ADDSUB_H) */ diff --git a/src/lib/intmath/include.am b/src/lib/intmath/include.am index 45ee3bd53b..155ffa145a 100644 --- a/src/lib/intmath/include.am +++ b/src/lib/intmath/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-intmath-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_intmath_a_SOURCES = \ src/lib/intmath/addsub.c \ src/lib/intmath/bits.c \ @@ -16,6 +17,7 @@ src_lib_libtor_intmath_testing_a_SOURCES = \ src_lib_libtor_intmath_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_intmath_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/intmath/addsub.h \ src/lib/intmath/cmp.h \ diff --git a/src/lib/intmath/logic.h b/src/lib/intmath/logic.h index a4cecd69cc..b2f77462e1 100644 --- a/src/lib/intmath/logic.h +++ b/src/lib/intmath/logic.h @@ -17,4 +17,4 @@ /** Macro: true if two values have different boolean values. */ #define bool_neq(a,b) (!(a)!=!(b)) -#endif +#endif /* !defined(HAVE_TOR_LOGIC_H) */ diff --git a/src/lib/intmath/weakrng.h b/src/lib/intmath/weakrng.h index e26bf58cbb..40941e59b2 100644 --- a/src/lib/intmath/weakrng.h +++ b/src/lib/intmath/weakrng.h @@ -28,4 +28,4 @@ int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top); * n */ #define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n))) -#endif +#endif /* !defined(TOR_WEAKRNG_H) */ diff --git a/src/lib/lock/compat_mutex.h b/src/lib/lock/compat_mutex.h index b63ce24024..e0c3d7cb78 100644 --- a/src/lib/lock/compat_mutex.h +++ b/src/lib/lock/compat_mutex.h @@ -48,7 +48,7 @@ typedef struct tor_mutex_t { #else /** No-threads only: Dummy variable so that tor_mutex_t takes up space. */ int _unused; -#endif /* defined(USE_WIN32_MUTEX) || ... */ +#endif /* defined(USE_WIN32_THREADS) || ... */ } tor_mutex_t; tor_mutex_t *tor_mutex_new(void); diff --git a/src/lib/lock/include.am b/src/lib/lock/include.am index 4e6f444347..1475b9911b 100644 --- a/src/lib/lock/include.am +++ b/src/lib/lock/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-lock-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_lock_a_SOURCES = \ src/lib/lock/compat_mutex.c @@ -20,5 +21,6 @@ src_lib_libtor_lock_testing_a_SOURCES = \ src_lib_libtor_lock_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_lock_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/lock/compat_mutex.h diff --git a/src/lib/log/.may_include b/src/lib/log/.may_include index 11c87f0a0d..54d96324db 100644 --- a/src/lib/log/.may_include +++ b/src/lib/log/.may_include @@ -1,6 +1,7 @@ orconfig.h lib/cc/*.h +lib/defs/*.h lib/smartlist_core/*.h lib/err/*.h lib/fdio/*.h diff --git a/src/lib/log/escape.h b/src/lib/log/escape.h index 2f726186c5..0b9fc3406b 100644 --- a/src/lib/log/escape.h +++ b/src/lib/log/escape.h @@ -20,4 +20,4 @@ char *esc_for_log(const char *string) ATTR_MALLOC; char *esc_for_log_len(const char *chars, size_t n) ATTR_MALLOC; const char *escaped(const char *string); -#endif /* !defined(TOR_TORLOG_H) */ +#endif /* !defined(TOR_ESCAPE_H) */ diff --git a/src/lib/log/include.am b/src/lib/log/include.am index 9d3dbe3104..5b9f7113ba 100644 --- a/src/lib/log/include.am +++ b/src/lib/log/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-log-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_log_a_SOURCES = \ src/lib/log/escape.c \ src/lib/log/ratelim.c \ @@ -21,6 +22,7 @@ src_lib_libtor_log_testing_a_SOURCES = \ src_lib_libtor_log_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_log_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/log/escape.h \ src/lib/log/ratelim.h \ diff --git a/src/lib/log/log.c b/src/lib/log/log.c index d21d8d1d41..d95bf1ff6e 100644 --- a/src/lib/log/log.c +++ b/src/lib/log/log.c @@ -49,6 +49,7 @@ #include "lib/wallclock/approx_time.h" #include "lib/wallclock/time_to_tm.h" #include "lib/fdio/fdio.h" +#include "lib/cc/ctassert.h" #ifdef HAVE_ANDROID_LOG_H #include @@ -154,7 +155,7 @@ severity_to_android_log_priority(int severity) // LCOV_EXCL_STOP } } -#endif // HAVE_ANDROID_LOG_H. +#endif /* defined(HAVE_ANDROID_LOG_H) */ /** A mutex to guard changes to logfiles and logging. */ static tor_mutex_t log_mutex; @@ -1021,7 +1022,7 @@ flush_pending_log_callbacks(void) do { SMARTLIST_FOREACH_BEGIN(messages, pending_log_message_t *, msg) { const int severity = msg->severity; - const int domain = msg->domain; + const log_domain_mask_t domain = msg->domain; for (lf = logfiles; lf; lf = lf->next) { if (! lf->callback || lf->seems_dead || ! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) { @@ -1232,7 +1233,7 @@ add_android_log(const log_severity_list_t *severity, UNLOCK_LOGS(); return 0; } -#endif // HAVE_ANDROID_LOG_H. +#endif /* defined(HAVE_ANDROID_LOG_H) */ /** If level is a valid log severity, return the corresponding * numeric value. Otherwise, return -1. */ @@ -1268,9 +1269,14 @@ static const char *domain_list[] = { "GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM", "HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV", "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL", - "SCHED", "GUARD", "CONSDIFF", "DOS", "PROCESS", "PT", "BTRACK", NULL + "SCHED", "GUARD", "CONSDIFF", "DOS", "PROCESS", "PT", "BTRACK", "MESG", + NULL }; +CTASSERT(ARRAY_LENGTH(domain_list) == N_LOGGING_DOMAINS + 1); + +CTASSERT((UINT64_C(1)<<(N_LOGGING_DOMAINS-1)) < LOWEST_RESERVED_LD_FLAG_); + /** Return a bitmask for the log domain for which domain is the name, * or 0 if there is no such name. */ static log_domain_mask_t @@ -1371,7 +1377,7 @@ parse_log_severity_config(const char **cfg_ptr, if (!strcmp(domain, "*")) { domains = ~0u; } else { - int d; + log_domain_mask_t d; int negate=0; if (*domain == '~') { negate = 1; diff --git a/src/lib/log/log.h b/src/lib/log/log.h index dbc1c47021..c4a27782c3 100644 --- a/src/lib/log/log.h +++ b/src/lib/log/log.h @@ -11,10 +11,12 @@ **/ #ifndef TOR_TORLOG_H +#define TOR_TORLOG_H #include #include "lib/cc/torint.h" #include "lib/cc/compat_compiler.h" +#include "lib/defs/logging_types.h" #include "lib/testsupport/testsupport.h" #ifdef HAVE_SYSLOG_H @@ -55,81 +57,81 @@ /* Logging domains */ /** Catch-all for miscellaneous events and fatal errors. */ -#define LD_GENERAL (1u<<0) +#define LD_GENERAL (UINT64_C(1)<<0) /** The cryptography subsystem. */ -#define LD_CRYPTO (1u<<1) +#define LD_CRYPTO (UINT64_C(1)<<1) /** Networking. */ -#define LD_NET (1u<<2) +#define LD_NET (UINT64_C(1)<<2) /** Parsing and acting on our configuration. */ -#define LD_CONFIG (1u<<3) +#define LD_CONFIG (UINT64_C(1)<<3) /** Reading and writing from the filesystem. */ -#define LD_FS (1u<<4) +#define LD_FS (UINT64_C(1)<<4) /** Other servers' (non)compliance with the Tor protocol. */ -#define LD_PROTOCOL (1u<<5) +#define LD_PROTOCOL (UINT64_C(1)<<5) /** Memory management. */ -#define LD_MM (1u<<6) +#define LD_MM (UINT64_C(1)<<6) /** HTTP implementation. */ -#define LD_HTTP (1u<<7) +#define LD_HTTP (UINT64_C(1)<<7) /** Application (socks) requests. */ -#define LD_APP (1u<<8) +#define LD_APP (UINT64_C(1)<<8) /** Communication via the controller protocol. */ -#define LD_CONTROL (1u<<9) +#define LD_CONTROL (UINT64_C(1)<<9) /** Building, using, and managing circuits. */ -#define LD_CIRC (1u<<10) +#define LD_CIRC (UINT64_C(1)<<10) /** Hidden services. */ -#define LD_REND (1u<<11) +#define LD_REND (UINT64_C(1)<<11) /** Internal errors in this Tor process. */ -#define LD_BUG (1u<<12) +#define LD_BUG (UINT64_C(1)<<12) /** Learning and using information about Tor servers. */ -#define LD_DIR (1u<<13) +#define LD_DIR (UINT64_C(1)<<13) /** Learning and using information about Tor servers. */ -#define LD_DIRSERV (1u<<14) +#define LD_DIRSERV (UINT64_C(1)<<14) /** Onion routing protocol. */ -#define LD_OR (1u<<15) +#define LD_OR (UINT64_C(1)<<15) /** Generic edge-connection functionality. */ -#define LD_EDGE (1u<<16) +#define LD_EDGE (UINT64_C(1)<<16) #define LD_EXIT LD_EDGE /** Bandwidth accounting. */ -#define LD_ACCT (1u<<17) +#define LD_ACCT (UINT64_C(1)<<17) /** Router history */ -#define LD_HIST (1u<<18) +#define LD_HIST (UINT64_C(1)<<18) /** OR handshaking */ -#define LD_HANDSHAKE (1u<<19) +#define LD_HANDSHAKE (UINT64_C(1)<<19) /** Heartbeat messages */ -#define LD_HEARTBEAT (1u<<20) +#define LD_HEARTBEAT (UINT64_C(1)<<20) /** Abstract channel_t code */ -#define LD_CHANNEL (1u<<21) +#define LD_CHANNEL (UINT64_C(1)<<21) /** Scheduler */ -#define LD_SCHED (1u<<22) +#define LD_SCHED (UINT64_C(1)<<22) /** Guard nodes */ -#define LD_GUARD (1u<<23) +#define LD_GUARD (UINT64_C(1)<<23) /** Generation and application of consensus diffs. */ -#define LD_CONSDIFF (1u<<24) +#define LD_CONSDIFF (UINT64_C(1)<<24) /** Denial of Service mitigation. */ -#define LD_DOS (1u<<25) +#define LD_DOS (UINT64_C(1)<<25) /** Processes */ -#define LD_PROCESS (1u<<26) +#define LD_PROCESS (UINT64_C(1)<<26) /** Pluggable Transports. */ -#define LD_PT (1u<<27) +#define LD_PT (UINT64_C(1)<<27) /** Bootstrap tracker. */ -#define LD_BTRACK (1u<<28) -/** Number of logging domains in the code. */ -#define N_LOGGING_DOMAINS 29 - -/** This log message is not safe to send to a callback-based logger - * immediately. Used as a flag, not a log domain. */ -#define LD_NOCB (1u<<31) -/** This log message should not include a function name, even if it otherwise - * would. Used as a flag, not a log domain. */ -#define LD_NOFUNCNAME (1u<<30) +#define LD_BTRACK (UINT64_C(1)<<28) +/** Message-passing backend. */ +#define LD_MESG (UINT64_C(1)<<29) +#define N_LOGGING_DOMAINS 30 +/** First bit that is reserved in log_domain_mask_t for non-domain flags. */ +#define LOWEST_RESERVED_LD_FLAG_ (UINT64_C(1)<<61) #ifdef TOR_UNIT_TESTS /** This log message should not be intercepted by mock_saving_logv */ -#define LD_NO_MOCK (1u<<29) +#define LD_NO_MOCK (UINT64_C(1)<<61) #endif -/** Mask of zero or more log domains, OR'd together. */ -typedef uint32_t log_domain_mask_t; +/** This log message is not safe to send to a callback-based logger + * immediately. Used as a flag, not a log domain. */ +#define LD_NOCB (UINT64_C(1)<<62) +/** This log message should not include a function name, even if it otherwise + * would. Used as a flag, not a log domain. */ +#define LD_NOFUNCNAME (UINT64_C(1)<<63) /** Configures which severities are logged for each logging domain for a given * log target. */ @@ -140,7 +142,8 @@ typedef struct log_severity_list_t { } log_severity_list_t; /** Callback type used for add_callback_log. */ -typedef void (*log_callback)(int severity, uint32_t domain, const char *msg); +typedef void (*log_callback)(int severity, log_domain_mask_t domain, + const char *msg); void init_logging(int disable_startup_queue); int parse_log_level(const char *level); @@ -192,6 +195,21 @@ void tor_log_get_logfile_names(struct smartlist_t *out); extern int log_global_min_severity_; +#ifdef TOR_COVERAGE +/* For coverage builds, we try to avoid our log_debug optimization, since it + * can have weird effects on internal macro coverage. */ +#define debug_logging_enabled() (1) +#else +static inline bool debug_logging_enabled(void); +/** + * Return true iff debug logging is enabled for at least one domain. + */ +static inline bool debug_logging_enabled(void) +{ + return PREDICT_UNLIKELY(log_global_min_severity_ == LOG_DEBUG); +} +#endif /* defined(TOR_COVERAGE) */ + void log_fn_(int severity, log_domain_mask_t domain, const char *funcname, const char *format, ...) CHECK_PRINTF(4,5); @@ -221,8 +239,8 @@ void tor_log_string(int severity, log_domain_mask_t domain, log_fn_ratelim_(ratelim, severity, domain, __FUNCTION__, args) #define log_debug(domain, args...) \ STMT_BEGIN \ - if (PREDICT_UNLIKELY(log_global_min_severity_ == LOG_DEBUG)) \ - log_fn_(LOG_DEBUG, domain, __FUNCTION__, args); \ + if (debug_logging_enabled()) \ + log_fn_(LOG_DEBUG, domain, __FUNCTION__, args); \ STMT_END #define log_info(domain, args...) \ log_fn_(LOG_INFO, domain, __FUNCTION__, args) @@ -239,8 +257,8 @@ void tor_log_string(int severity, log_domain_mask_t domain, #define log_debug(domain, args, ...) \ STMT_BEGIN \ - if (PREDICT_UNLIKELY(log_global_min_severity_ == LOG_DEBUG)) \ - log_fn_(LOG_DEBUG, domain, __FUNCTION__, args, ##__VA_ARGS__); \ + if (debug_logging_enabled()) \ + log_fn_(LOG_DEBUG, domain, __FUNCTION__, args, ##__VA_ARGS__); \ STMT_END #define log_info(domain, args,...) \ log_fn_(LOG_INFO, domain, __FUNCTION__, args, ##__VA_ARGS__) @@ -278,5 +296,4 @@ MOCK_DECL(STATIC void, logv, (int severity, log_domain_mask_t domain, va_list ap) CHECK_PRINTF(5,0)); #endif -# define TOR_TORLOG_H #endif /* !defined(TOR_TORLOG_H) */ diff --git a/src/lib/log/ratelim.h b/src/lib/log/ratelim.h index 48edd7c849..1db54ba726 100644 --- a/src/lib/log/ratelim.h +++ b/src/lib/log/ratelim.h @@ -50,4 +50,4 @@ typedef struct ratelim_t { char *rate_limit_log(ratelim_t *lim, time_t now); -#endif +#endif /* !defined(TOR_RATELIM_H) */ diff --git a/src/lib/log/util_bug.c b/src/lib/log/util_bug.c index c65a91ae9e..76b97c1a08 100644 --- a/src/lib/log/util_bug.c +++ b/src/lib/log/util_bug.c @@ -70,25 +70,45 @@ tor_set_failed_assertion_callback(void (*fn)(void)) /** Helper for tor_assert: report the assertion failure. */ void +CHECK_PRINTF(5, 6) tor_assertion_failed_(const char *fname, unsigned int line, - const char *func, const char *expr) + const char *func, const char *expr, + const char *fmt, ...) { - char buf[256]; + char *buf = NULL; + char *extra = NULL; + va_list ap; + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#endif + if (fmt) { + va_start(ap,fmt); + tor_vasprintf(&extra, fmt, ap); + va_end(ap); + } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + log_err(LD_BUG, "%s:%u: %s: Assertion %s failed; aborting.", fname, line, func, expr); - tor_snprintf(buf, sizeof(buf), - "Assertion %s failed in %s at %s:%u", - expr, func, fname, line); + tor_asprintf(&buf, "Assertion %s failed in %s at %s:%u: %s", + expr, func, fname, line, extra ? extra : ""); + tor_free(extra); log_backtrace(LOG_ERR, LD_BUG, buf); + tor_free(buf); } /** Helper for tor_assert_nonfatal: report the assertion failure. */ void +CHECK_PRINTF(6, 7) tor_bug_occurred_(const char *fname, unsigned int line, const char *func, const char *expr, - int once) + int once, const char *fmt, ...) { - char buf[256]; + char *buf = NULL; const char *once_str = once ? " (Future instances of this warning will be silenced.)": ""; if (! expr) { @@ -98,7 +118,7 @@ tor_bug_occurred_(const char *fname, unsigned int line, } log_warn(LD_BUG, "%s:%u: %s: This line should not have been reached.%s", fname, line, func, once_str); - tor_snprintf(buf, sizeof(buf), + tor_asprintf(&buf, "Line unexpectedly reached at %s at %s:%u", func, fname, line); } else { @@ -106,13 +126,32 @@ tor_bug_occurred_(const char *fname, unsigned int line, add_captured_bug(expr); return; } + + va_list ap; + char *extra = NULL; + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#endif + if (fmt) { + va_start(ap,fmt); + tor_vasprintf(&extra, fmt, ap); + va_end(ap); + } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + log_warn(LD_BUG, "%s:%u: %s: Non-fatal assertion %s failed.%s", fname, line, func, expr, once_str); - tor_snprintf(buf, sizeof(buf), - "Non-fatal assertion %s failed in %s at %s:%u", - expr, func, fname, line); + tor_asprintf(&buf, "Non-fatal assertion %s failed in %s at %s:%u%s%s", + expr, func, fname, line, fmt ? " : " : "", + extra ? extra : ""); + tor_free(extra); } log_backtrace(LOG_WARN, LD_BUG, buf); + tor_free(buf); #ifdef TOR_UNIT_TESTS if (failed_assertion_cb) { diff --git a/src/lib/log/util_bug.h b/src/lib/log/util_bug.h index 2a4d68127e..546ae1e3ef 100644 --- a/src/lib/log/util_bug.h +++ b/src/lib/log/util_bug.h @@ -80,10 +80,10 @@ tor__assert_tmp_value__; \ } ) #define ASSERT_PREDICT_LIKELY_(e) ASSERT_PREDICT_UNLIKELY_(e) -#else +#else /* !(defined(TOR_UNIT_TESTS) && defined(__GNUC__)) */ #define ASSERT_PREDICT_UNLIKELY_(e) PREDICT_UNLIKELY(e) #define ASSERT_PREDICT_LIKELY_(e) PREDICT_LIKELY(e) -#endif +#endif /* defined(TOR_UNIT_TESTS) && defined(__GNUC__) */ /* Sometimes we don't want to use assertions during branch coverage tests; it * leads to tons of unreached branches which in reality are only assertions we @@ -92,21 +92,28 @@ #define tor_assert(a) STMT_BEGIN \ (void)(a); \ STMT_END -#else +#define tor_assertf(a, fmt, ...) STMT_BEGIN \ + (void)(a); \ + (void)(fmt); \ + STMT_END +#else /* !(defined(TOR_UNIT_TESTS) && ... */ /** Like assert(3), but send assertion failures to the log as well as to * stderr. */ -#define tor_assert(expr) STMT_BEGIN \ +#define tor_assert(expr) tor_assertf(expr, NULL) + +#define tor_assertf(expr, fmt, ...) STMT_BEGIN \ if (ASSERT_PREDICT_LIKELY_(expr)) { \ } else { \ - tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, #expr); \ - tor_abort_(); \ + tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, #expr, \ + fmt, ##__VA_ARGS__); \ + tor_abort_(); \ } STMT_END #endif /* defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS) */ #define tor_assert_unreached() \ STMT_BEGIN { \ tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, \ - "line should be unreached"); \ + "line should be unreached", NULL); \ tor_abort_(); \ } STMT_END @@ -136,34 +143,47 @@ #ifdef ALL_BUGS_ARE_FATAL #define tor_assert_nonfatal_unreached() tor_assert(0) #define tor_assert_nonfatal(cond) tor_assert((cond)) +#define tor_assertf_nonfatal(cond, fmt, ...) \ + tor_assertf(cond, fmt, ##__VA_ARGS__) #define tor_assert_nonfatal_unreached_once() tor_assert(0) #define tor_assert_nonfatal_once(cond) tor_assert((cond)) #define BUG(cond) \ (ASSERT_PREDICT_UNLIKELY_(cond) ? \ - (tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,"!("#cond")"), \ + (tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",NULL), \ tor_abort_(), 1) \ : 0) #elif defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS) #define tor_assert_nonfatal_unreached() STMT_NIL #define tor_assert_nonfatal(cond) ((void)(cond)) +#define tor_assertf_nonfatal(cond, fmt, ...) STMT_BEGIN \ + (void)cond; \ + (void)fmt; \ + STMT_END #define tor_assert_nonfatal_unreached_once() STMT_NIL #define tor_assert_nonfatal_once(cond) ((void)(cond)) #define BUG(cond) (ASSERT_PREDICT_UNLIKELY_(cond) ? 1 : 0) #else /* Normal case, !ALL_BUGS_ARE_FATAL, !DISABLE_ASSERTS_IN_UNIT_TESTS */ #define tor_assert_nonfatal_unreached() STMT_BEGIN \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 0); \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 0, NULL); \ STMT_END #define tor_assert_nonfatal(cond) STMT_BEGIN \ if (ASSERT_PREDICT_LIKELY_(cond)) { \ } else { \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0); \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0, NULL);\ + } \ + STMT_END +#define tor_assertf_nonfatal(cond, fmt, ...) STMT_BEGIN \ + if (ASSERT_PREDICT_UNLIKELY_(cond)) { \ + } else { \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0, \ + fmt, ##__VA_ARGS__); \ } \ STMT_END #define tor_assert_nonfatal_unreached_once() STMT_BEGIN \ static int warning_logged__ = 0; \ if (!warning_logged__) { \ warning_logged__ = 1; \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 1); \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 1, NULL); \ } \ STMT_END #define tor_assert_nonfatal_once(cond) STMT_BEGIN \ @@ -171,12 +191,12 @@ if (ASSERT_PREDICT_LIKELY_(cond)) { \ } else if (!warning_logged__) { \ warning_logged__ = 1; \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1); \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1, NULL);\ } \ STMT_END #define BUG(cond) \ (ASSERT_PREDICT_UNLIKELY_(cond) ? \ - (tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",0), 1) \ + (tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",1,NULL),1) \ : 0) #endif /* defined(ALL_BUGS_ARE_FATAL) || ... */ @@ -188,7 +208,7 @@ if (bool_result && !var) { \ var = 1; \ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \ - "!("#cond")", 1); \ + "!("#cond")", 1, NULL); \ } \ bool_result; } )) #else /* !(defined(__GNUC__)) */ @@ -198,7 +218,7 @@ (var ? 1 : \ (var=1, \ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \ - "!("#cond")", 1), \ + "!("#cond")", 1, NULL), \ 1)) \ : 0) #endif /* defined(__GNUC__) */ @@ -221,10 +241,11 @@ #define tor_fragile_assert() tor_assert_nonfatal_unreached_once() void tor_assertion_failed_(const char *fname, unsigned int line, - const char *func, const char *expr); + const char *func, const char *expr, + const char *fmt, ...); void tor_bug_occurred_(const char *fname, unsigned int line, const char *func, const char *expr, - int once); + int once, const char *fmt, ...); void tor_abort_(void) ATTR_NORETURN; diff --git a/src/lib/log/win32err.h b/src/lib/log/win32err.h index 33413dfd15..ecfa88792d 100644 --- a/src/lib/log/win32err.h +++ b/src/lib/log/win32err.h @@ -19,4 +19,4 @@ char *format_win32_error(DWORD err); #endif -#endif +#endif /* !defined(TOR_WIN32ERR_H) */ diff --git a/src/lib/malloc/include.am b/src/lib/malloc/include.am index 95d96168e1..b74292bc6e 100644 --- a/src/lib/malloc/include.am +++ b/src/lib/malloc/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-malloc-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_malloc_a_SOURCES = \ src/lib/malloc/malloc.c \ src/lib/malloc/map_anon.c @@ -18,6 +19,7 @@ src_lib_libtor_malloc_testing_a_SOURCES = \ src_lib_libtor_malloc_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_malloc_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/malloc/malloc.h \ src/lib/malloc/map_anon.h diff --git a/src/lib/malloc/malloc.h b/src/lib/malloc/malloc.h index ef6b509ca4..8c81d30dd5 100644 --- a/src/lib/malloc/malloc.h +++ b/src/lib/malloc/malloc.h @@ -48,12 +48,12 @@ void tor_free_(void *mem); raw_free(*tor_free__tmpvar); \ *tor_free__tmpvar=NULL; \ STMT_END -#else +#else /* !(defined(__GNUC__)) */ #define tor_free(p) STMT_BEGIN \ raw_free(p); \ (p)=NULL; \ STMT_END -#endif +#endif /* defined(__GNUC__) */ #define tor_malloc(size) tor_malloc_(size) #define tor_malloc_zero(size) tor_malloc_zero_(size) diff --git a/src/lib/malloc/map_anon.c b/src/lib/malloc/map_anon.c index 2fc6e89ea2..0f6a4150c7 100644 --- a/src/lib/malloc/map_anon.c +++ b/src/lib/malloc/map_anon.c @@ -50,12 +50,16 @@ #ifdef INHERIT_ZERO #define FLAG_ZERO INHERIT_ZERO +#elif defined(MAP_INHERIT_ZERO) +#define FLAG_ZERO MAP_INHERIT_ZERO #endif #ifdef INHERIT_NONE #define FLAG_NOINHERIT INHERIT_NONE #elif defined(VM_INHERIT_NONE) #define FLAG_NOINHERIT VM_INHERIT_NONE -#endif +#elif defined(MAP_INHERIT_NONE) +#define FLAG_NOINHERIT MAP_INHERIT_NONE +#endif /* defined(INHERIT_NONE) || ... */ #elif defined(HAVE_MADVISE) @@ -68,6 +72,11 @@ #define FLAG_NOINHERIT MADV_DONTFORK #endif +#endif /* defined(HAVE_MINHERIT) || ... */ + +#if defined(HAVE_MINHERIT) && !defined(FLAG_ZERO) && !defined(FLAG_NOINHERIT) +#warn "minherit() is defined, but we couldn't find the right flag for it." +#warn "This is probably a bug in Tor's support for this platform." #endif /** @@ -87,7 +96,7 @@ lock_mem(void *mem, size_t sz) (void) sz; return 0; -#endif +#endif /* defined(_WIN32) || ... */ } /** @@ -104,7 +113,7 @@ nodump_mem(void *mem, size_t sz) (void) mem; (void) sz; return 0; -#endif +#endif /* defined(MADV_DONTDUMP) */ } /** @@ -113,22 +122,32 @@ nodump_mem(void *mem, size_t sz) * fork, and if that doesn't work, by having them unmapped after a fork. * Return 0 on success or if the facility is not available on this OS; return * -1 on failure. + * + * If we successfully make the memory uninheritable, adjust the value of + * *inherit_result_out. */ static int -noinherit_mem(void *mem, size_t sz) +noinherit_mem(void *mem, size_t sz, inherit_res_t *inherit_result_out) { #ifdef FLAG_ZERO int r = MINHERIT(mem, sz, FLAG_ZERO); - if (r == 0) + if (r == 0) { + *inherit_result_out = INHERIT_RES_ZERO; return 0; -#endif + } +#endif /* defined(FLAG_ZERO) */ #ifdef FLAG_NOINHERIT - return MINHERIT(mem, sz, FLAG_NOINHERIT); -#else + int r2 = MINHERIT(mem, sz, FLAG_NOINHERIT); + if (r2 == 0) { + *inherit_result_out = INHERIT_RES_DROP; + } + return r2; +#else /* !(defined(FLAG_NOINHERIT)) */ + (void)inherit_result_out; (void)mem; (void)sz; return 0; -#endif +#endif /* defined(FLAG_NOINHERIT) */ } /** @@ -144,14 +163,25 @@ noinherit_mem(void *mem, size_t sz) * Memory returned from this function must be released with * tor_munmap_anonymous(). * + * If inherit_result_out is non-NULL, set it to one of + * INHERIT_RES_KEEP, INHERIT_RES_DROP, or INHERIT_RES_ZERO, depending on the + * properties of the returned memory. + * * [Note: OS people use the word "anonymous" here to mean that the memory * isn't associated with any file. This has *nothing* to do with the kind of * anonymity that Tor is trying to provide.] */ void * -tor_mmap_anonymous(size_t sz, unsigned flags) +tor_mmap_anonymous(size_t sz, unsigned flags, + inherit_res_t *inherit_result_out) { void *ptr; + inherit_res_t itmp=0; + if (inherit_result_out == NULL) { + inherit_result_out = &itmp; + } + *inherit_result_out = INHERIT_RES_KEEP; + #if defined(_WIN32) HANDLE mapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, /*attributes*/ @@ -174,7 +204,7 @@ tor_mmap_anonymous(size_t sz, unsigned flags) raw_assert(ptr != NULL); #else ptr = tor_malloc_zero(sz); -#endif +#endif /* defined(_WIN32) || ... */ if (flags & ANONMAP_PRIVATE) { int lock_result = lock_mem(ptr, sz); @@ -184,7 +214,7 @@ tor_mmap_anonymous(size_t sz, unsigned flags) } if (flags & ANONMAP_NOINHERIT) { - int noinherit_result = noinherit_mem(ptr, sz); + int noinherit_result = noinherit_mem(ptr, sz, inherit_result_out); raw_assert(noinherit_result == 0); } @@ -209,5 +239,5 @@ tor_munmap_anonymous(void *mapping, size_t sz) #else (void)sz; tor_free(mapping); -#endif +#endif /* defined(_WIN32) || ... */ } diff --git a/src/lib/malloc/map_anon.h b/src/lib/malloc/map_anon.h index cc5797e4ec..4c4690e12f 100644 --- a/src/lib/malloc/map_anon.h +++ b/src/lib/malloc/map_anon.h @@ -31,7 +31,41 @@ */ #define ANONMAP_NOINHERIT (1u<<1) -void *tor_mmap_anonymous(size_t sz, unsigned flags); +typedef enum { + /** Possible value for inherit_result_out: the memory will be kept + * by any child process. */ + INHERIT_RES_KEEP=0, + /** Possible value for inherit_result_out: the memory will be dropped in the + * child process. Attempting to access it will likely cause a segfault. */ + INHERIT_RES_DROP, + /** Possible value for inherit_result_out: the memory will be cleared in + * the child process. */ + INHERIT_RES_ZERO +} inherit_res_t; + +/* Here we define the NOINHERIT_CAN_FAIL macro if and only if + * it's possible that ANONMAP_NOINHERIT might yield inheritable memory. + */ +#ifdef _WIN32 +/* Windows can't fork, so NOINHERIT is never needed. */ +#elif defined(HAVE_MINHERIT) +/* minherit() will always have a working MAP_INHERIT_NONE or MAP_INHERIT_ZERO. + * NOINHERIT should always work. + */ +#elif defined(HAVE_MADVISE) +/* madvise() sometimes has neither MADV_DONTFORK and MADV_WIPEONFORK. + * We need to be ready for the possibility it failed. + * + * (Linux added DONTFORK in 2.6.16 and WIPEONFORK in 4.14. If we someday + * require 2.6.16 or later, we can assume that DONTFORK will work.) + */ +#define NOINHERIT_CAN_FAIL +#else +#define NOINHERIT_CAN_FAIL +#endif /* defined(_WIN32) || ... */ + +void *tor_mmap_anonymous(size_t sz, unsigned flags, + inherit_res_t *inherit_result_out); void tor_munmap_anonymous(void *mapping, size_t sz); #endif /* !defined(TOR_MAP_ANON_H) */ diff --git a/src/lib/math/fp.h b/src/lib/math/fp.h index cb24649e6c..a73789c945 100644 --- a/src/lib/math/fp.h +++ b/src/lib/math/fp.h @@ -21,4 +21,4 @@ int64_t tor_llround(double d) ATTR_CONST; int64_t clamp_double_to_int64(double number); int tor_isinf(double x); -#endif +#endif /* !defined(TOR_FP_H) */ diff --git a/src/lib/math/include.am b/src/lib/math/include.am index 6d65ce90a7..b2ca280f47 100644 --- a/src/lib/math/include.am +++ b/src/lib/math/include.am @@ -5,17 +5,18 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-math-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_math_a_SOURCES = \ src/lib/math/fp.c \ src/lib/math/laplace.c \ src/lib/math/prob_distr.c - src_lib_libtor_math_testing_a_SOURCES = \ $(src_lib_libtor_math_a_SOURCES) src_lib_libtor_math_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_math_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/math/fp.h \ src/lib/math/laplace.h \ diff --git a/src/lib/math/laplace.h b/src/lib/math/laplace.h index e8651e5197..02b0e890f0 100644 --- a/src/lib/math/laplace.h +++ b/src/lib/math/laplace.h @@ -19,4 +19,4 @@ int64_t sample_laplace_distribution(double mu, double b, double p); int64_t add_laplace_noise(int64_t signal, double random, double delta_f, double epsilon); -#endif +#endif /* !defined(TOR_LAPLACE_H) */ diff --git a/src/lib/math/prob_distr.c b/src/lib/math/prob_distr.c index c952dadc06..d44dc28265 100644 --- a/src/lib/math/prob_distr.c +++ b/src/lib/math/prob_distr.c @@ -46,26 +46,27 @@ #include "lib/crypt_ops/crypto_rand.h" #include "lib/cc/ctassert.h" +#include "lib/log/util_bug.h" #include #include #include -/** Validators for downcasting macros below */ -#define validate_container_of(PTR, TYPE, FIELD) \ - (0 * sizeof((PTR) - &((TYPE *)(((char *)(PTR)) - \ - offsetof(TYPE, FIELD)))->FIELD)) -#define validate_const_container_of(PTR, TYPE, FIELD) \ - (0 * sizeof((PTR) - &((const TYPE *)(((const char *)(PTR)) - \ - offsetof(TYPE, FIELD)))->FIELD)) -/** Downcasting macro */ -#define container_of(PTR, TYPE, FIELD) \ - ((TYPE *)(((char *)(PTR)) - offsetof(TYPE, FIELD)) \ - + validate_container_of(PTR, TYPE, FIELD)) -/** Constified downcasting macro */ -#define const_container_of(PTR, TYPE, FIELD) \ - ((const TYPE *)(((const char *)(PTR)) - offsetof(TYPE, FIELD)) \ - + validate_const_container_of(PTR, TYPE, FIELD)) +/** Declare a function that downcasts from a generic dist struct to the actual + * subtype probablity distribution it represents. */ +#define DECLARE_PROB_DISTR_DOWNCAST_FN(name) \ + static inline \ + const struct name * \ + dist_to_const_##name(const struct dist *obj) { \ + tor_assert(obj->ops == &name##_ops); \ + return SUBTYPE_P(obj, struct name, base); \ + } +DECLARE_PROB_DISTR_DOWNCAST_FN(uniform) +DECLARE_PROB_DISTR_DOWNCAST_FN(geometric) +DECLARE_PROB_DISTR_DOWNCAST_FN(logistic) +DECLARE_PROB_DISTR_DOWNCAST_FN(log_logistic) +DECLARE_PROB_DISTR_DOWNCAST_FN(genpareto) +DECLARE_PROB_DISTR_DOWNCAST_FN(weibull) /** * Count number of one bits in 32-bit word. @@ -458,7 +459,7 @@ random_uniform_01(void) * system is broken. */ z = 0; - while ((x = crypto_rand_u32()) == 0) { + while ((x = crypto_fast_rng_get_u32(get_thread_fast_rng())) == 0) { if (z >= 1088) /* Your bit sampler is broken. Go home. */ return 0; @@ -472,8 +473,8 @@ random_uniform_01(void) * occur only with measure zero in the uniform distribution on * [0, 1]. */ - hi = crypto_rand_u32() | UINT32_C(0x80000000); - lo = crypto_rand_u32() | UINT32_C(0x00000001); + hi = crypto_fast_rng_get_u32(get_thread_fast_rng()) | UINT32_C(0x80000000); + lo = crypto_fast_rng_get_u32(get_thread_fast_rng()) | UINT32_C(0x00000001); /* Round to nearest scaled significand in [2^63, 2^64]. */ s = hi*(double)4294967296 + lo; @@ -1315,40 +1316,48 @@ sample_geometric(uint32_t s, double p0, double p) /** Public API for probability distributions: * - * For each probability distribution we define each public functions - * (sample/cdf/sf/icdf/isf) as part of its dist_ops structure. + * These are wrapper functions on top of the various probability distribution + * operations using the generic dist structure. + + * These are the functions that should be used by consumers of this API. */ +/** Returns the name of the distribution in dist. */ const char * dist_name(const struct dist *dist) { return dist->ops->name; } +/* Sample a value from dist and return it. */ double dist_sample(const struct dist *dist) { return dist->ops->sample(dist); } +/** Compute the CDF of dist at x. */ double dist_cdf(const struct dist *dist, double x) { return dist->ops->cdf(dist, x); } +/** Compute the SF (Survival function) of dist at x. */ double dist_sf(const struct dist *dist, double x) { return dist->ops->sf(dist, x); } +/** Compute the iCDF (Inverse CDF) of dist at x. */ double dist_icdf(const struct dist *dist, double p) { return dist->ops->icdf(dist, p); } +/** Compute the iSF (Inverse Survival function) of dist at x. */ double dist_isf(const struct dist *dist, double p) { @@ -1360,8 +1369,7 @@ dist_isf(const struct dist *dist, double p) static double uniform_sample(const struct dist *dist) { - const struct uniform *U = const_container_of(dist, struct uniform, - base); + const struct uniform *U = dist_to_const_uniform(dist); double p0 = random_uniform_01(); return sample_uniform_interval(p0, U->a, U->b); @@ -1370,9 +1378,7 @@ uniform_sample(const struct dist *dist) static double uniform_cdf(const struct dist *dist, double x) { - const struct uniform *U = const_container_of(dist, struct uniform, - base); - + const struct uniform *U = dist_to_const_uniform(dist); if (x < U->a) return 0; else if (x < U->b) @@ -1384,8 +1390,7 @@ uniform_cdf(const struct dist *dist, double x) static double uniform_sf(const struct dist *dist, double x) { - const struct uniform *U = const_container_of(dist, struct uniform, - base); + const struct uniform *U = dist_to_const_uniform(dist); if (x > U->b) return 0; @@ -1398,8 +1403,7 @@ uniform_sf(const struct dist *dist, double x) static double uniform_icdf(const struct dist *dist, double p) { - const struct uniform *U = const_container_of(dist, struct uniform, - base); + const struct uniform *U = dist_to_const_uniform(dist); double w = U->b - U->a; return (p < 0.5 ? (U->a + w*p) : (U->b - w*(1 - p))); @@ -1408,8 +1412,7 @@ uniform_icdf(const struct dist *dist, double p) static double uniform_isf(const struct dist *dist, double p) { - const struct uniform *U = const_container_of(dist, struct uniform, - base); + const struct uniform *U = dist_to_const_uniform(dist); double w = U->b - U->a; return (p < 0.5 ? (U->b - w*p) : (U->a + w*(1 - p))); @@ -1424,14 +1427,17 @@ const struct dist_ops uniform_ops = { .isf = uniform_isf, }; +/*******************************************************************/ + +/** Private functions for each probability distribution. */ + /** Functions for logistic distribution: */ static double logistic_sample(const struct dist *dist) { - const struct logistic *L = const_container_of(dist, struct logistic, - base); - uint32_t s = crypto_rand_u32(); + const struct logistic *L = dist_to_const_logistic(dist); + uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng()); double t = random_uniform_01(); double p0 = random_uniform_01(); @@ -1441,36 +1447,28 @@ logistic_sample(const struct dist *dist) static double logistic_cdf(const struct dist *dist, double x) { - const struct logistic *L = const_container_of(dist, struct logistic, - base); - + const struct logistic *L = dist_to_const_logistic(dist); return cdf_logistic(x, L->mu, L->sigma); } static double logistic_sf(const struct dist *dist, double x) { - const struct logistic *L = const_container_of(dist, struct logistic, - base); - + const struct logistic *L = dist_to_const_logistic(dist); return sf_logistic(x, L->mu, L->sigma); } static double logistic_icdf(const struct dist *dist, double p) { - const struct logistic *L = const_container_of(dist, struct logistic, - base); - + const struct logistic *L = dist_to_const_logistic(dist); return icdf_logistic(p, L->mu, L->sigma); } static double logistic_isf(const struct dist *dist, double p) { - const struct logistic *L = const_container_of(dist, struct logistic, - base); - + const struct logistic *L = dist_to_const_logistic(dist); return isf_logistic(p, L->mu, L->sigma); } @@ -1488,9 +1486,8 @@ const struct dist_ops logistic_ops = { static double log_logistic_sample(const struct dist *dist) { - const struct log_logistic *LL = const_container_of(dist, struct - log_logistic, base); - uint32_t s = crypto_rand_u32(); + const struct log_logistic *LL = dist_to_const_log_logistic(dist); + uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng()); double p0 = random_uniform_01(); return sample_log_logistic_scaleshape(s, p0, LL->alpha, LL->beta); @@ -1499,36 +1496,28 @@ log_logistic_sample(const struct dist *dist) static double log_logistic_cdf(const struct dist *dist, double x) { - const struct log_logistic *LL = const_container_of(dist, - struct log_logistic, base); - + const struct log_logistic *LL = dist_to_const_log_logistic(dist); return cdf_log_logistic(x, LL->alpha, LL->beta); } static double log_logistic_sf(const struct dist *dist, double x) { - const struct log_logistic *LL = const_container_of(dist, - struct log_logistic, base); - + const struct log_logistic *LL = dist_to_const_log_logistic(dist); return sf_log_logistic(x, LL->alpha, LL->beta); } static double log_logistic_icdf(const struct dist *dist, double p) { - const struct log_logistic *LL = const_container_of(dist, - struct log_logistic, base); - + const struct log_logistic *LL = dist_to_const_log_logistic(dist); return icdf_log_logistic(p, LL->alpha, LL->beta); } static double log_logistic_isf(const struct dist *dist, double p) { - const struct log_logistic *LL = const_container_of(dist, - struct log_logistic, base); - + const struct log_logistic *LL = dist_to_const_log_logistic(dist); return isf_log_logistic(p, LL->alpha, LL->beta); } @@ -1546,9 +1535,8 @@ const struct dist_ops log_logistic_ops = { static double weibull_sample(const struct dist *dist) { - const struct weibull *W = const_container_of(dist, struct weibull, - base); - uint32_t s = crypto_rand_u32(); + const struct weibull *W = dist_to_const_weibull(dist); + uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng()); double p0 = random_uniform_01(); return sample_weibull(s, p0, W->lambda, W->k); @@ -1557,36 +1545,28 @@ weibull_sample(const struct dist *dist) static double weibull_cdf(const struct dist *dist, double x) { - const struct weibull *W = const_container_of(dist, struct weibull, - base); - + const struct weibull *W = dist_to_const_weibull(dist); return cdf_weibull(x, W->lambda, W->k); } static double weibull_sf(const struct dist *dist, double x) { - const struct weibull *W = const_container_of(dist, struct weibull, - base); - + const struct weibull *W = dist_to_const_weibull(dist); return sf_weibull(x, W->lambda, W->k); } static double weibull_icdf(const struct dist *dist, double p) { - const struct weibull *W = const_container_of(dist, struct weibull, - base); - + const struct weibull *W = dist_to_const_weibull(dist); return icdf_weibull(p, W->lambda, W->k); } static double weibull_isf(const struct dist *dist, double p) { - const struct weibull *W = const_container_of(dist, struct weibull, - base); - + const struct weibull *W = dist_to_const_weibull(dist); return isf_weibull(p, W->lambda, W->k); } @@ -1604,9 +1584,8 @@ const struct dist_ops weibull_ops = { static double genpareto_sample(const struct dist *dist) { - const struct genpareto *GP = const_container_of(dist, struct genpareto, - base); - uint32_t s = crypto_rand_u32(); + const struct genpareto *GP = dist_to_const_genpareto(dist); + uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng()); double p0 = random_uniform_01(); return sample_genpareto_locscale(s, p0, GP->mu, GP->sigma, GP->xi); @@ -1615,36 +1594,28 @@ genpareto_sample(const struct dist *dist) static double genpareto_cdf(const struct dist *dist, double x) { - const struct genpareto *GP = const_container_of(dist, struct genpareto, - base); - + const struct genpareto *GP = dist_to_const_genpareto(dist); return cdf_genpareto(x, GP->mu, GP->sigma, GP->xi); } static double genpareto_sf(const struct dist *dist, double x) { - const struct genpareto *GP = const_container_of(dist, struct genpareto, - base); - + const struct genpareto *GP = dist_to_const_genpareto(dist); return sf_genpareto(x, GP->mu, GP->sigma, GP->xi); } static double genpareto_icdf(const struct dist *dist, double p) { - const struct genpareto *GP = const_container_of(dist, struct genpareto, - base); - + const struct genpareto *GP = dist_to_const_genpareto(dist); return icdf_genpareto(p, GP->mu, GP->sigma, GP->xi); } static double genpareto_isf(const struct dist *dist, double p) { - const struct genpareto *GP = const_container_of(dist, struct genpareto, - base); - + const struct genpareto *GP = dist_to_const_genpareto(dist); return isf_genpareto(p, GP->mu, GP->sigma, GP->xi); } @@ -1662,8 +1633,8 @@ const struct dist_ops genpareto_ops = { static double geometric_sample(const struct dist *dist) { - const struct geometric *G = const_container_of(dist, struct geometric, base); - uint32_t s = crypto_rand_u32(); + const struct geometric *G = dist_to_const_geometric(dist); + uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng()); double p0 = random_uniform_01(); return sample_geometric(s, p0, G->p); @@ -1672,7 +1643,7 @@ geometric_sample(const struct dist *dist) static double geometric_cdf(const struct dist *dist, double x) { - const struct geometric *G = const_container_of(dist, struct geometric, base); + const struct geometric *G = dist_to_const_geometric(dist); if (x < 1) return 0; @@ -1683,7 +1654,7 @@ geometric_cdf(const struct dist *dist, double x) static double geometric_sf(const struct dist *dist, double x) { - const struct geometric *G = const_container_of(dist, struct geometric, base); + const struct geometric *G = dist_to_const_geometric(dist); if (x < 1) return 0; @@ -1694,7 +1665,7 @@ geometric_sf(const struct dist *dist, double x) static double geometric_icdf(const struct dist *dist, double p) { - const struct geometric *G = const_container_of(dist, struct geometric, base); + const struct geometric *G = dist_to_const_geometric(dist); return log1p(-p)/log1p(-G->p); } @@ -1702,7 +1673,7 @@ geometric_icdf(const struct dist *dist, double p) static double geometric_isf(const struct dist *dist, double p) { - const struct geometric *G = const_container_of(dist, struct geometric, base); + const struct geometric *G = dist_to_const_geometric(dist); return log(p)/log1p(-G->p); } diff --git a/src/lib/math/prob_distr.h b/src/lib/math/prob_distr.h index 66acb796fd..7254dc8623 100644 --- a/src/lib/math/prob_distr.h +++ b/src/lib/math/prob_distr.h @@ -19,10 +19,100 @@ struct dist { const struct dist_ops *ops; }; +/** + * Untyped initializer element for struct dist using the specified + * struct dist_ops pointer. Don't actually use this directly -- use + * the type-specific macro built out of DIST_BASE_TYPED below -- but if + * you did use this directly, it would be something like: + * + * struct weibull mydist = { + * DIST_BASE(&weibull_ops), + * .lambda = ..., + * .k = ..., + * }; + * + * Note there is NO COMPILER FEEDBACK if you accidentally do something + * like + * + * struct geometric mydist = { + * DIST_BASE(&weibull_ops), + * ... + * }; + */ #define DIST_BASE(OPS) { .ops = (OPS) } + +/** A compile-time type-checking macro for use with DIST_BASE_TYPED. + * + * This macro works by checking that &OBJ is a pointer type that is the same + * type (except for qualifiers) as (const TYPE *)&OBJ. It's a C constraint + * violation (which requires a diagnostic) if two pointers are different types + * and are subtracted. The sizeof() forces compile-time evaluation, and the + * multiplication by zero is to discard the result of the sizeof() from the + * expression. + * + * We define this conditionally to suppress false positives from + * Coverity, which gets confused by the sizeof business. + */ +#ifdef __COVERITY__ +#define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) 0 +#else +#define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) \ + (0*sizeof(&(OBJ) - (const TYPE *)&(OBJ))) +#endif /* defined(__COVERITY__) */ + +/** +* Typed initializer element for struct dist using the specified struct +* dist_ops pointer. Don't actually use this directly -- use a +* type-specific macro built out of it -- but if you did use this +* directly, it would be something like: +* +* struct weibull mydist = { +* DIST_BASE_TYPED(&weibull_ops, mydist, struct weibull), +* .lambda = ..., +* .k = ..., +* }; +* +* If you want to define a distribution type, define a canonical set of +* operations and define a type-specific initializer element like so: +* +* struct foo { +* struct dist base; +* int omega; +* double tau; +* double phi; +* }; +* +* struct dist_ops foo_ops = ...; +* +* #define FOO(OBJ) DIST_BASE_TYPED(&foo_ops, OBJ, struct foo) +* +* Then users can do: +* +* struct foo mydist = { +* FOO(mydist), +* .omega = ..., +* .tau = ..., +* .phi = ..., +* }; +* +* If you accidentally write +* +* struct bar mydist = { +* FOO(mydist), +* ... +* }; +* +* then the compiler will report a type mismatch in the sizeof +* expression, which otherwise evaporates at runtime. +*/ #define DIST_BASE_TYPED(OPS, OBJ, TYPE) \ - DIST_BASE((OPS) + 0*sizeof(&(OBJ) - (const TYPE *)&(OBJ))) + DIST_BASE((OPS) + TYPE_CHECK_OBJ(OPS,OBJ,TYPE)) +/** + * Generic operations on distributions. These simply defer to the + * corresponding dist_ops function. In the parlance of C++, these call + * virtual member functions. + */ const char *dist_name(const struct dist *); double dist_sample(const struct dist *); double dist_cdf(const struct dist *, double x); @@ -30,6 +120,11 @@ double dist_sf(const struct dist *, double x); double dist_icdf(const struct dist *, double p); double dist_isf(const struct dist *, double p); +/** + * Set of operations on a potentially parametric family of + * distributions. In the parlance of C++, this would be called a + * `vtable' and the members are virtual member functions. + */ struct dist_ops { const char *name; double (*sample)(const struct dist *); @@ -153,6 +248,6 @@ STATIC double icdf_genpareto(double p, double mu, double sigma, double xi); STATIC double isf_genpareto(double p, double mu, double sigma, double xi); STATIC double sample_genpareto(uint32_t s, double p0, double xi); -#endif +#endif /* defined(PROB_DISTR_PRIVATE) */ -#endif +#endif /* !defined(TOR_PROB_DISTR_H) */ diff --git a/src/lib/memarea/include.am b/src/lib/memarea/include.am index 94343dcead..83fb99ec73 100644 --- a/src/lib/memarea/include.am +++ b/src/lib/memarea/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-memarea-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_memarea_a_SOURCES = \ src/lib/memarea/memarea.c @@ -13,5 +14,6 @@ src_lib_libtor_memarea_testing_a_SOURCES = \ src_lib_libtor_memarea_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_memarea_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/memarea/memarea.h diff --git a/src/lib/meminfo/include.am b/src/lib/meminfo/include.am index d1fdde6313..12c1bff72d 100644 --- a/src/lib/meminfo/include.am +++ b/src/lib/meminfo/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-meminfo-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_meminfo_a_SOURCES = \ src/lib/meminfo/meminfo.c @@ -13,5 +14,6 @@ src_lib_libtor_meminfo_testing_a_SOURCES = \ src_lib_libtor_meminfo_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_meminfo_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/meminfo/meminfo.h diff --git a/src/lib/meminfo/meminfo.h b/src/lib/meminfo/meminfo.h index 2d64e1ab06..9580640f4d 100644 --- a/src/lib/meminfo/meminfo.h +++ b/src/lib/meminfo/meminfo.h @@ -18,4 +18,4 @@ void tor_log_mallinfo(int severity); MOCK_DECL(int, get_total_system_memory, (size_t *mem_out)); -#endif +#endif /* !defined(TOR_MEMINFO_H) */ diff --git a/src/lib/net/address.c b/src/lib/net/address.c index 214d8aa3eb..546af800a9 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -339,7 +339,7 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate) break; case AF_INET6: /* Shortest addr [ :: ] + \0 */ - if (len < (3 + (decorate ? 2 : 0))) + if (len < (3u + (decorate ? 2 : 0))) return NULL; if (decorate) @@ -2027,8 +2027,12 @@ string_is_valid_nonrfc_hostname(const char *string) smartlist_split_string(components,string,".",0,0); - if (BUG(smartlist_len(components) == 0)) - return 0; // LCOV_EXCL_LINE should be impossible given the earlier checks. + if (BUG(smartlist_len(components) == 0)) { + // LCOV_EXCL_START should be impossible given the earlier checks. + smartlist_free(components); + return 0; + // LCOV_EXCL_STOP + } /* Allow a single terminating '.' used rarely to indicate domains * are FQDNs rather than relative. */ diff --git a/src/lib/net/alertsock.h b/src/lib/net/alertsock.h index c45f42be81..4d0d0dd57c 100644 --- a/src/lib/net/alertsock.h +++ b/src/lib/net/alertsock.h @@ -42,4 +42,4 @@ typedef struct alert_sockets_t { int alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags); void alert_sockets_close(alert_sockets_t *socks); -#endif +#endif /* !defined(TOR_ALERTSOCK_H) */ diff --git a/src/lib/net/buffers_net.h b/src/lib/net/buffers_net.h index a3a90172a1..5058dd0a26 100644 --- a/src/lib/net/buffers_net.h +++ b/src/lib/net/buffers_net.h @@ -31,4 +31,4 @@ int buf_read_from_pipe(struct buf_t *buf, int fd, size_t at_most, int buf_flush_to_pipe(struct buf_t *buf, int fd, size_t sz, size_t *buf_flushlen); -#endif /* !defined(TOR_BUFFERS_H) */ +#endif /* !defined(TOR_BUFFERS_NET_H) */ diff --git a/src/lib/net/gethostname.h b/src/lib/net/gethostname.h index 69b0528bc0..b3b77b0589 100644 --- a/src/lib/net/gethostname.h +++ b/src/lib/net/gethostname.h @@ -16,4 +16,4 @@ MOCK_DECL(int,tor_gethostname,(char *name, size_t namelen)); -#endif +#endif /* !defined(TOR_GETHOSTNAME_H) */ diff --git a/src/lib/net/inaddr.h b/src/lib/net/inaddr.h index 36352b65ea..602573944c 100644 --- a/src/lib/net/inaddr.h +++ b/src/lib/net/inaddr.h @@ -24,4 +24,4 @@ int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len); const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len); int tor_inet_pton(int af, const char *src, void *dst); -#endif +#endif /* !defined(TOR_INADDR_H) */ diff --git a/src/lib/net/inaddr_st.h b/src/lib/net/inaddr_st.h index 806f2c096a..230f29a63a 100644 --- a/src/lib/net/inaddr_st.h +++ b/src/lib/net/inaddr_st.h @@ -104,4 +104,4 @@ struct sockaddr_in6 { }; #endif /* !defined(HAVE_STRUCT_SOCKADDR_IN6) */ -#endif /* TOR_INADDR_ST_H */ +#endif /* !defined(TOR_INADDR_ST_H) */ diff --git a/src/lib/net/include.am b/src/lib/net/include.am index 8a88f0f2ae..485019f4b7 100644 --- a/src/lib/net/include.am +++ b/src/lib/net/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-net-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_net_a_SOURCES = \ src/lib/net/address.c \ src/lib/net/alertsock.c \ @@ -21,6 +22,7 @@ src_lib_libtor_net_testing_a_SOURCES = \ src_lib_libtor_net_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_net_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/net/address.h \ src/lib/net/alertsock.h \ diff --git a/src/lib/net/nettypes.h b/src/lib/net/nettypes.h index 6209bbe18a..0eb352c657 100644 --- a/src/lib/net/nettypes.h +++ b/src/lib/net/nettypes.h @@ -41,4 +41,4 @@ typedef int socklen_t; #define TOR_INVALID_SOCKET (-1) #endif /* defined(_WIN32) */ -#endif +#endif /* !defined(TOR_NET_TYPES_H) */ diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c index 49c263faa2..2dda491d14 100644 --- a/src/lib/net/resolve.c +++ b/src/lib/net/resolve.c @@ -421,7 +421,7 @@ tor_make_getaddrinfo_cache_active(void) { sandbox_getaddrinfo_is_active = 1; } -#else +#else /* !(defined(USE_SANDBOX_GETADDRINFO)) */ void sandbox_disable_getaddrinfo_cache(void) { @@ -430,4 +430,4 @@ void tor_make_getaddrinfo_cache_active(void) { } -#endif +#endif /* defined(USE_SANDBOX_GETADDRINFO) */ diff --git a/src/lib/net/resolve.h b/src/lib/net/resolve.h index 0fb77f1661..d11c902a91 100644 --- a/src/lib/net/resolve.h +++ b/src/lib/net/resolve.h @@ -55,4 +55,4 @@ void tor_free_getaddrinfo_cache(void); void sandbox_disable_getaddrinfo_cache(void); void tor_make_getaddrinfo_cache_active(void); -#endif +#endif /* !defined(TOR_RESOLVE_H) */ diff --git a/src/lib/net/socket.c b/src/lib/net/socket.c index f978deeab8..e824a05045 100644 --- a/src/lib/net/socket.c +++ b/src/lib/net/socket.c @@ -84,9 +84,9 @@ check_network_configuration(bool server_mode) "so your relay makes it harder to figure out how busy it is."); } } -#else +#else /* !(defined(__FreeBSD__)) */ (void) server_mode; -#endif +#endif /* defined(__FreeBSD__) */ } /* When set_max_file_sockets() is called, update this with the max file @@ -487,11 +487,11 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) r = socketpair(family, type, protocol, fd); if (r < 0) return -errno; -#else +#else /* !(defined(HAVE_SOCKETPAIR) && !defined(_WIN32)) */ r = tor_ersatz_socketpair(family, type, protocol, fd); if (r < 0) return -r; -#endif +#endif /* defined(HAVE_SOCKETPAIR) && !defined(_WIN32) */ #if defined(FD_CLOEXEC) if (SOCKET_OK(fd[0])) { diff --git a/src/lib/net/socket.h b/src/lib/net/socket.h index 86ae336dfb..193ad91e4c 100644 --- a/src/lib/net/socket.h +++ b/src/lib/net/socket.h @@ -116,4 +116,4 @@ const char *tor_socket_strerror(int e); #define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747b #endif -#endif +#endif /* !defined(TOR_SOCKET_H) */ diff --git a/src/lib/net/socketpair.c b/src/lib/net/socketpair.c index 15c706bec7..3be7b26f7f 100644 --- a/src/lib/net/socketpair.c +++ b/src/lib/net/socketpair.c @@ -22,11 +22,11 @@ #include #define socket_errno() (WSAGetLastError()) #define SOCKET_EPROTONOSUPPORT WSAEPROTONOSUPPORT -#else +#else /* !(defined(_WIN32)) */ #define closesocket(x) close(x) #define socket_errno() (errno) #define SOCKET_EPROTONOSUPPORT EPROTONOSUPPORT -#endif +#endif /* defined(_WIN32) */ #ifdef NEED_ERSATZ_SOCKETPAIR diff --git a/src/lib/net/socketpair.h b/src/lib/net/socketpair.h index 6be0803881..5820606973 100644 --- a/src/lib/net/socketpair.h +++ b/src/lib/net/socketpair.h @@ -16,4 +16,4 @@ int tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2]); #endif -#endif +#endif /* !defined(TOR_SOCKETPAIR_H) */ diff --git a/src/lib/net/socks5_status.h b/src/lib/net/socks5_status.h index e55242ce66..e55119e0b0 100644 --- a/src/lib/net/socks5_status.h +++ b/src/lib/net/socks5_status.h @@ -29,4 +29,4 @@ typedef enum { SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08, } socks5_reply_status_t; -#endif +#endif /* !defined(TOR_SOCKS5_STATUS_H) */ diff --git a/src/lib/osinfo/include.am b/src/lib/osinfo/include.am index 16c5812604..84bd7feb00 100644 --- a/src/lib/osinfo/include.am +++ b/src/lib/osinfo/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-osinfo-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_osinfo_a_SOURCES = \ src/lib/osinfo/uname.c @@ -13,5 +14,6 @@ src_lib_libtor_osinfo_testing_a_SOURCES = \ src_lib_libtor_osinfo_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_osinfo_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/osinfo/uname.h diff --git a/src/lib/osinfo/uname.h b/src/lib/osinfo/uname.h index fcce629074..443a30d358 100644 --- a/src/lib/osinfo/uname.h +++ b/src/lib/osinfo/uname.h @@ -15,4 +15,4 @@ MOCK_DECL(const char *, get_uname,(void)); -#endif +#endif /* !defined(HAVE_TOR_UNAME_H) */ diff --git a/src/lib/process/daemon.h b/src/lib/process/daemon.h index 20920e0aae..423c498837 100644 --- a/src/lib/process/daemon.h +++ b/src/lib/process/daemon.h @@ -18,4 +18,4 @@ int finish_daemon(const char *desired_cwd); bool start_daemon_has_been_called(void); -#endif +#endif /* !defined(TOR_DAEMON_H) */ diff --git a/src/lib/process/env.h b/src/lib/process/env.h index 15d59351e0..19c2235970 100644 --- a/src/lib/process/env.h +++ b/src/lib/process/env.h @@ -38,4 +38,4 @@ void set_environment_variable_in_smartlist(struct smartlist_t *env_vars, const char *new_var, void (*free_old)(void*), int free_p); -#endif +#endif /* !defined(TOR_ENV_H) */ diff --git a/src/lib/process/include.am b/src/lib/process/include.am index 83b67bf029..af5f99617b 100644 --- a/src/lib/process/include.am +++ b/src/lib/process/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-process-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_process_a_SOURCES = \ src/lib/process/daemon.c \ src/lib/process/env.c \ @@ -23,6 +24,7 @@ src_lib_libtor_process_testing_a_SOURCES = \ src_lib_libtor_process_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_process_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/process/daemon.h \ src/lib/process/env.h \ diff --git a/src/lib/process/pidfile.h b/src/lib/process/pidfile.h index dfeb39e046..af59041f80 100644 --- a/src/lib/process/pidfile.h +++ b/src/lib/process/pidfile.h @@ -13,4 +13,4 @@ int write_pidfile(const char *filename); -#endif +#endif /* !defined(TOR_PIDFILE_H) */ diff --git a/src/lib/process/process.c b/src/lib/process/process.c index 422942dc83..631c7169f1 100644 --- a/src/lib/process/process.c +++ b/src/lib/process/process.c @@ -83,7 +83,7 @@ struct process_t { #else /** Our Win32 process handle. */ process_win32_t *win32_process; -#endif +#endif /* !defined(_WIN32) */ }; /** Convert a given process status in status to its string @@ -205,7 +205,7 @@ process_new(const char *command) #else /* Prepare our Win32 process handle. */ process->win32_process = process_win32_new(); -#endif +#endif /* !defined(_WIN32) */ smartlist_add(processes, process); @@ -240,7 +240,7 @@ process_free_(process_t *process) #else /* Cleanup our Win32 process handle. */ process_win32_free(process->win32_process); -#endif +#endif /* !defined(_WIN32) */ smartlist_remove(processes, process); @@ -513,7 +513,7 @@ process_get_unix_process(const process_t *process) tor_assert(process->unix_process); return process->unix_process; } -#else +#else /* !(!defined(_WIN32)) */ /** Get the internal handle for Windows backend. */ process_win32_t * process_get_win32_process(const process_t *process) @@ -522,7 +522,7 @@ process_get_win32_process(const process_t *process) tor_assert(process->win32_process); return process->win32_process; } -#endif +#endif /* !defined(_WIN32) */ /** Write size bytes of data to the given process's standard * input. */ diff --git a/src/lib/process/process.h b/src/lib/process/process.h index 14069923a0..05c091a5bf 100644 --- a/src/lib/process/process.h +++ b/src/lib/process/process.h @@ -111,7 +111,7 @@ struct process_unix_t *process_get_unix_process(const process_t *process); #else struct process_win32_t; struct process_win32_t *process_get_win32_process(const process_t *process); -#endif +#endif /* !defined(_WIN32) */ void process_write(process_t *process, const uint8_t *data, size_t size); @@ -140,6 +140,6 @@ STATIC void process_read_buffer(process_t *process, STATIC void process_read_lines(process_t *process, buf_t *buffer, process_read_callback_t callback); -#endif /* defined(PROCESS_PRIVATE). */ +#endif /* defined(PROCESS_PRIVATE) */ -#endif /* defined(TOR_PROCESS_H). */ +#endif /* !defined(TOR_PROCESS_H) */ diff --git a/src/lib/process/process_unix.c b/src/lib/process/process_unix.c index 790ab897e9..17ade87463 100644 --- a/src/lib/process/process_unix.c +++ b/src/lib/process/process_unix.c @@ -702,4 +702,4 @@ process_unix_close_file_descriptors(process_unix_t *unix_process) return success; } -#endif /* defined(_WIN32). */ +#endif /* !defined(_WIN32) */ diff --git a/src/lib/process/process_unix.h b/src/lib/process/process_unix.h index a1d8f72993..da40b3e567 100644 --- a/src/lib/process/process_unix.h +++ b/src/lib/process/process_unix.h @@ -61,8 +61,8 @@ STATIC int process_unix_read_handle(process_t *, process_unix_handle_t *, buf_t *); STATIC bool process_unix_close_file_descriptors(process_unix_t *); -#endif /* defined(PROCESS_UNIX_PRIVATE). */ +#endif /* defined(PROCESS_UNIX_PRIVATE) */ -#endif /* defined(_WIN32). */ +#endif /* !defined(_WIN32) */ -#endif /* defined(TOR_PROCESS_UNIX_H). */ +#endif /* !defined(TOR_PROCESS_UNIX_H) */ diff --git a/src/lib/process/process_win32.c b/src/lib/process/process_win32.c index ddbe76bfd9..624333d4a3 100644 --- a/src/lib/process/process_win32.c +++ b/src/lib/process/process_win32.c @@ -741,7 +741,7 @@ process_win32_cleanup_handle(process_win32_handle_t *handle) format_win32_error(error_code)); } } -#endif +#endif /* 0 */ /* Close our handle. */ if (handle->pipe != INVALID_HANDLE_VALUE) { @@ -1084,4 +1084,4 @@ tor_join_win_cmdline(const char *argv[]) return joined_argv; } -#endif /* ! defined(_WIN32). */ +#endif /* defined(_WIN32) */ diff --git a/src/lib/process/process_win32.h b/src/lib/process/process_win32.h index d79dde157e..a50d86df5b 100644 --- a/src/lib/process/process_win32.h +++ b/src/lib/process/process_win32.h @@ -90,8 +90,8 @@ STATIC bool process_win32_handle_read_completion(process_win32_handle_t *, STATIC char *format_win_cmdline_argument(const char *arg); STATIC char *tor_join_win_cmdline(const char *argv[]); -#endif /* defined(PROCESS_WIN32_PRIVATE). */ +#endif /* defined(PROCESS_WIN32_PRIVATE) */ -#endif /* ! defined(_WIN32). */ +#endif /* defined(_WIN32) */ -#endif /* defined(TOR_PROCESS_WIN32_H). */ +#endif /* !defined(TOR_PROCESS_WIN32_H) */ diff --git a/src/lib/process/setuid.h b/src/lib/process/setuid.h index 7d03e1f025..a2125d2d06 100644 --- a/src/lib/process/setuid.h +++ b/src/lib/process/setuid.h @@ -19,4 +19,4 @@ int have_capability_support(void); #define SWITCH_ID_WARN_IF_NO_CAPS (1<<1) int switch_id(const char *user, unsigned flags); -#endif +#endif /* !defined(TOR_SETUID_H) */ diff --git a/src/lib/process/winprocess_sys.c b/src/lib/process/winprocess_sys.c index 1266babca8..48c0888658 100644 --- a/src/lib/process/winprocess_sys.c +++ b/src/lib/process/winprocess_sys.c @@ -51,7 +51,7 @@ subsys_winprocess_initialize(void) return 0; } -#else /* !defined(_WIN32) */ +#else /* !(defined(_WIN32)) */ #define WINPROCESS_SYS_ENABLED false #define subsys_winprocess_initialize NULL #endif /* defined(_WIN32) */ diff --git a/src/lib/pubsub/.may_include b/src/lib/pubsub/.may_include new file mode 100644 index 0000000000..5623492f00 --- /dev/null +++ b/src/lib/pubsub/.may_include @@ -0,0 +1,10 @@ +orconfig.h + +lib/cc/*.h +lib/container/*.h +lib/dispatch/*.h +lib/intmath/*.h +lib/log/*.h +lib/malloc/*.h +lib/pubsub/*.h +lib/string/*.h diff --git a/src/lib/pubsub/include.am b/src/lib/pubsub/include.am new file mode 100644 index 0000000000..e2abebcd40 --- /dev/null +++ b/src/lib/pubsub/include.am @@ -0,0 +1,28 @@ + +noinst_LIBRARIES += src/lib/libtor-pubsub.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-pubsub-testing.a +endif + +# ADD_C_FILE: INSERT SOURCES HERE. +src_lib_libtor_pubsub_a_SOURCES = \ + src/lib/pubsub/pubsub_build.c \ + src/lib/pubsub/pubsub_check.c \ + src/lib/pubsub/pubsub_publish.c + +src_lib_libtor_pubsub_testing_a_SOURCES = \ + $(src_lib_libtor_pubsub_a_SOURCES) +src_lib_libtor_pubsub_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_pubsub_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/lib/pubsub/pub_binding_st.h \ + src/lib/pubsub/pubsub.h \ + src/lib/pubsub/pubsub_build.h \ + src/lib/pubsub/pubsub_builder_st.h \ + src/lib/pubsub/pubsub_connect.h \ + src/lib/pubsub/pubsub_flags.h \ + src/lib/pubsub/pubsub_macros.h \ + src/lib/pubsub/pubsub_publish.h diff --git a/src/lib/pubsub/pub_binding_st.h b/src/lib/pubsub/pub_binding_st.h new file mode 100644 index 0000000000..d841bf3f54 --- /dev/null +++ b/src/lib/pubsub/pub_binding_st.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file pub_binding_st.h + * @brief Declaration of pub_binding_t. + * + * This is an internal type for the pubsub implementation. + */ + +#ifndef TOR_PUB_BINDING_ST_H +#define TOR_PUB_BINDING_ST_H + +#include "lib/dispatch/msgtypes.h" +struct dispatch_t; + +/** + * A pub_binding_t is an opaque object that subsystems use to publish + * messages. The DISPATCH_ADD_PUB*() macros set it up. + **/ +typedef struct pub_binding_t { + /** + * A pointer to a configured dispatch_t object. This is filled in + * when the dispatch_t is finally constructed. + **/ + struct dispatch_t *dispatch_ptr; + /** + * A template for the msg_t fields that are filled in for this message. + * This is copied into outgoing messages, ensuring that their fields are set + * corretly. + **/ + msg_t msg_template; +} pub_binding_t; + +#endif /* !defined(TOR_PUB_BINDING_ST_H) */ diff --git a/src/lib/pubsub/pubsub.h b/src/lib/pubsub/pubsub.h new file mode 100644 index 0000000000..5346b07517 --- /dev/null +++ b/src/lib/pubsub/pubsub.h @@ -0,0 +1,89 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file pubsub.h + * @brief Header for OO publish-subscribe functionality. + * + * This module provides a wrapper around the "dispatch" module, + * ensuring type-safety and allowing us to do static analysis on + * publication and subscriptions. + * + * With this module, we enforce: + *
    + *
  • that every message has (potential) publishers and subscribers; + *
  • that every message is published and subscribed from the correct + * channels, with the correct type ID, every time it is published. + *
  • that type IDs correspond to a single C type, and that the C types are + * used correctly. + *
  • that when a message is published or subscribed, it is done with + * a correct subsystem identifier + *
+ * + * We do this by making "publication requests" and "subscription requests" + * into objects, and doing some computation on them before we create + * a dispatch_t with them. + * + * Rather than using the dispatch module directly, a publishing module + * receives a "binding" object that it uses to send messages with the right + * settings. + * + * Most users of this module will want to use this header, and the + * pubsub_macros.h header for convenience. + */ + +/* + * + * Overview: Messages are sent over channels. Before sending a message on a + * channel, or receiving a message on a channel, a subsystem needs to register + * that it publishes, or subscribes, to that message, on that channel. + * + * Messages, channels, and subsystems are represented internally as short + * integers, though they are associated with human-readable strings for + * initialization and debugging. + * + * When registering for a message, a subsystem must say whether it is an + * exclusive publisher/subscriber to that message type, or whether other + * subsystems may also publish/subscribe to it. + * + * All messages and their publishers/subscribers must be registered early in + * the initialization process. + * + * By default, it is an error for a message type to have publishers and no + * subscribers on a channel, or subscribers and no publishers on a channel. + * + * A subsystem may register for a message with a note that delivery or + * production is disabled -- for example, because the subsystem is + * disabled at compile-time. It is not an error for a message type to + * have all of its publishers or subscribers disabled. + * + * After a message is sent, it is delivered to every recipient. This + * delivery happens from the top level of the event loop; it may be + * interleaved with network events, timers, etc. + * + * Messages may have associated data. This data is typed, and is owned + * by the message. Strings, byte-arrays, and integers have built-in + * support. Other types may be added. If objects are to be sent, + * they should be identified by handle. If an object requires cleanup, + * it should be declared with an associated free function. + * + * Semantically, if two subsystems communicate only by this kind of + * message passing, neither is considered to depend on the other, though + * both are considered to have a dependency on the message and on any + * types it contains. + * + * (Or generational index?) + */ +#ifndef TOR_PUBSUB_PUBSUB_H +#define TOR_PUBSUB_PUBSUB_H + +#include "lib/pubsub/pub_binding_st.h" +#include "lib/pubsub/pubsub_connect.h" +#include "lib/pubsub/pubsub_flags.h" +#include "lib/pubsub/pubsub_macros.h" +#include "lib/pubsub/pubsub_publish.h" + +#endif /* !defined(TOR_PUBSUB_PUBSUB_H) */ diff --git a/src/lib/pubsub/pubsub_build.c b/src/lib/pubsub/pubsub_build.c new file mode 100644 index 0000000000..e44b7d76ec --- /dev/null +++ b/src/lib/pubsub/pubsub_build.c @@ -0,0 +1,307 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file pubsub_build.c + * @brief Construct a dispatch_t in safer, more OO way. + **/ + +#define PUBSUB_PRIVATE + +#include "lib/dispatch/dispatch.h" +#include "lib/dispatch/dispatch_cfg.h" +#include "lib/dispatch/dispatch_naming.h" +#include "lib/dispatch/msgtypes.h" +#include "lib/pubsub/pubsub_flags.h" +#include "lib/pubsub/pub_binding_st.h" +#include "lib/pubsub/pubsub_build.h" +#include "lib/pubsub/pubsub_builder_st.h" +#include "lib/pubsub/pubsub_connect.h" + +#include "lib/container/smartlist.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/malloc.h" + + #include + +/** Construct and return a new empty pubsub_items_t. */ +static pubsub_items_t * +pubsub_items_new(void) +{ + pubsub_items_t *cfg = tor_malloc_zero(sizeof(*cfg)); + cfg->items = smartlist_new(); + cfg->type_items = smartlist_new(); + return cfg; +} + +/** Release all storage held in a pubsub_items_t. */ +void +pubsub_items_free_(pubsub_items_t *cfg) +{ + if (! cfg) + return; + SMARTLIST_FOREACH(cfg->items, pubsub_cfg_t *, item, tor_free(item)); + SMARTLIST_FOREACH(cfg->type_items, + pubsub_type_cfg_t *, item, tor_free(item)); + smartlist_free(cfg->items); + smartlist_free(cfg->type_items); + tor_free(cfg); +} + +/** Construct and return a new pubsub_builder_t. */ +pubsub_builder_t * +pubsub_builder_new(void) +{ + dispatch_naming_init(); + + pubsub_builder_t *pb = tor_malloc_zero(sizeof(*pb)); + pb->cfg = dcfg_new(); + pb->items = pubsub_items_new(); + return pb; +} + +/** + * Release all storage held by a pubsub_builder_t. + * + * You'll (mostly) only want to call this function on an error case: if you're + * constructing a dispatch_t instead, you should call + * pubsub_builder_finalize() to consume the pubsub_builder_t. + */ +void +pubsub_builder_free_(pubsub_builder_t *pb) +{ + if (pb == NULL) + return; + pubsub_items_free(pb->items); + dcfg_free(pb->cfg); + tor_free(pb); +} + +/** + * Create and return a pubsub_connector_t for the subsystem with ID + * subsys to use in adding publications, subscriptions, and types to + * builder. + **/ +pubsub_connector_t * +pubsub_connector_for_subsystem(pubsub_builder_t *builder, + subsys_id_t subsys) +{ + tor_assert(builder); + ++builder->n_connectors; + + pubsub_connector_t *con = tor_malloc_zero(sizeof(*con)); + + con->builder = builder; + con->subsys_id = subsys; + + return con; +} + +/** + * Release all storage held by a pubsub_connector_t. + **/ +void +pubsub_connector_free_(pubsub_connector_t *con) +{ + if (!con) + return; + + if (con->builder) { + --con->builder->n_connectors; + tor_assert(con->builder->n_connectors >= 0); + } + tor_free(con); +} + +/** + * Use con to add a request for being able to publish messages of type + * msg with auxiliary data of type on channel. + **/ +int +pubsub_add_pub_(pubsub_connector_t *con, + pub_binding_t *out, + channel_id_t channel, + message_id_t msg, + msg_type_id_t type, + unsigned flags, + const char *file, + unsigned line) +{ + pubsub_cfg_t *cfg = tor_malloc_zero(sizeof(*cfg)); + + memset(out, 0, sizeof(*out)); + cfg->is_publish = true; + + out->msg_template.sender = cfg->subsys = con->subsys_id; + out->msg_template.channel = cfg->channel = channel; + out->msg_template.msg = cfg->msg = msg; + out->msg_template.type = cfg->type = type; + + cfg->flags = flags; + cfg->added_by_file = file; + cfg->added_by_line = line; + + /* We're grabbing a pointer to the pub_binding_t so we can tell it about + * the dispatcher later on. + */ + cfg->pub_binding = out; + + smartlist_add(con->builder->items->items, cfg); + + if (dcfg_msg_set_type(con->builder->cfg, msg, type) < 0) + goto err; + if (dcfg_msg_set_chan(con->builder->cfg, msg, channel) < 0) + goto err; + + return 0; + err: + ++con->builder->n_errors; + return -1; +} + +/** + * Use con to add a request for being able to publish messages of type + * msg with auxiliary data of type on channel, + * passing them to the callback in recv_fn. + **/ +int +pubsub_add_sub_(pubsub_connector_t *con, + recv_fn_t recv_fn, + channel_id_t channel, + message_id_t msg, + msg_type_id_t type, + unsigned flags, + const char *file, + unsigned line) +{ + pubsub_cfg_t *cfg = tor_malloc_zero(sizeof(*cfg)); + + cfg->is_publish = false; + cfg->subsys = con->subsys_id; + cfg->channel = channel; + cfg->msg = msg; + cfg->type = type; + cfg->flags = flags; + cfg->added_by_file = file; + cfg->added_by_line = line; + + cfg->recv_fn = recv_fn; + + smartlist_add(con->builder->items->items, cfg); + + if (dcfg_msg_set_type(con->builder->cfg, msg, type) < 0) + goto err; + if (dcfg_msg_set_chan(con->builder->cfg, msg, channel) < 0) + goto err; + if (! (flags & DISP_FLAG_STUB)) { + if (dcfg_add_recv(con->builder->cfg, msg, cfg->subsys, recv_fn) < 0) + goto err; + } + + return 0; + err: + ++con->builder->n_errors; + return -1; +} + +/** + * Use con to define the functions to use for manipulating the type + * type. Any function pointers left as NULL will be implemented as + * no-ops. + **/ +int +pubsub_connector_register_type_(pubsub_connector_t *con, + msg_type_id_t type, + dispatch_typefns_t *fns, + const char *file, + unsigned line) +{ + pubsub_type_cfg_t *cfg = tor_malloc_zero(sizeof(*cfg)); + cfg->type = type; + memcpy(&cfg->fns, fns, sizeof(*fns)); + cfg->subsys = con->subsys_id; + cfg->added_by_file = file; + cfg->added_by_line = line; + + smartlist_add(con->builder->items->type_items, cfg); + + if (dcfg_type_set_fns(con->builder->cfg, type, fns) < 0) + goto err; + + return 0; + err: + ++con->builder->n_errors; + return -1; +} + +/** + * Initialize the dispatch_ptr field in every relevant publish binding + * for d. + */ +static void +pubsub_items_install_bindings(pubsub_items_t *items, + dispatch_t *d) +{ + SMARTLIST_FOREACH_BEGIN(items->items, pubsub_cfg_t *, cfg) { + if (cfg->pub_binding) { + // XXXX we could skip this for STUB publishers, and for any publishers + // XXXX where all subscribers are STUB. + cfg->pub_binding->dispatch_ptr = d; + } + } SMARTLIST_FOREACH_END(cfg); +} + +/** + * Remove the dispatch_ptr fields for all the relevant publish bindings + * in items. The prevents subsequent dispatch_pub_() calls from + * sending messages to a dispatcher that has been freed. + **/ +void +pubsub_items_clear_bindings(pubsub_items_t *items) +{ + SMARTLIST_FOREACH_BEGIN(items->items, pubsub_cfg_t *, cfg) { + if (cfg->pub_binding) { + cfg->pub_binding->dispatch_ptr = NULL; + } + } SMARTLIST_FOREACH_END(cfg); +} + +/** + * Create a new dispatcher as configured in a pubsub_builder_t. + * + * Consumes and frees its input. + **/ +dispatch_t * +pubsub_builder_finalize(pubsub_builder_t *builder, + pubsub_items_t **items_out) +{ + dispatch_t *dispatcher = NULL; + tor_assert_nonfatal(builder->n_connectors == 0); + + if (pubsub_builder_check(builder) < 0) + goto err; + + if (builder->n_errors) { + log_warn(LD_GENERAL, "At least one error occurred previously when " + "configuring the dispatcher."); + goto err; + } + + dispatcher = dispatch_new(builder->cfg); + + if (!dispatcher) + goto err; + + pubsub_items_install_bindings(builder->items, dispatcher); + if (items_out) { + *items_out = builder->items; + builder->items = NULL; /* Prevent free */ + } + + err: + pubsub_builder_free(builder); + return dispatcher; +} diff --git a/src/lib/pubsub/pubsub_build.h b/src/lib/pubsub/pubsub_build.h new file mode 100644 index 0000000000..5a0c5f5bd3 --- /dev/null +++ b/src/lib/pubsub/pubsub_build.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file pubsub_build.h + * @brief Header used for constructing the OO publish-subscribe facility. + * + * (See pubsub.h for more general information on this API.) + **/ + +#ifndef TOR_PUBSUB_BUILD_H +#define TOR_PUBSUB_BUILD_H + +#include "lib/dispatch/msgtypes.h" + +struct dispatch_t; +struct pubsub_connector_t; + +/** + * A "dispatch builder" is an incomplete dispatcher, used when + * registering messages. It does not have the same integrity guarantees + * as a dispatcher. It cannot actually handle messages itself: once all + * subsystems have registered, it is converted into a dispatch_t. + **/ +typedef struct pubsub_builder_t pubsub_builder_t; + +/** + * A "pubsub items" holds the configuration items used to configure a + * pubsub_builder. After the builder is finalized, this field is extracted, + * and used later to tear down pointers that enable publishing. + **/ +typedef struct pubsub_items_t pubsub_items_t; + +/** + * Create a new pubsub_builder. This should only happen in the + * main-init code. + */ +pubsub_builder_t *pubsub_builder_new(void); + +/** DOCDOC */ +int pubsub_builder_check(pubsub_builder_t *); + +/** + * Free a pubsub builder. This should only happen on error paths, where + * we have decided not to construct a dispatcher for some reason. + */ +#define pubsub_builder_free(db) \ + FREE_AND_NULL(pubsub_builder_t, pubsub_builder_free_, (db)) + +/** Internal implementation of pubsub_builder_free(). */ +void pubsub_builder_free_(pubsub_builder_t *); + +/** + * Create a pubsub connector that a single subsystem will use to + * register its messages. The main-init code does this during susbsystem + * initialization. + */ +struct pubsub_connector_t *pubsub_connector_for_subsystem(pubsub_builder_t *, + subsys_id_t); + +/** + * The main-init code does this after subsystem initialization. + */ +#define pubsub_connector_free(c) \ + FREE_AND_NULL(struct pubsub_connector_t, pubsub_connector_free_, (c)) + +void pubsub_connector_free_(struct pubsub_connector_t *); + +/** + * Constructs a dispatcher from a dispatch_builder, after checking that the + * invariances on the messages, channels, and connections have been + * respected. + * + * This should happen after every subsystem has initialized, and before + * entering the mainloop. + */ +struct dispatch_t *pubsub_builder_finalize(pubsub_builder_t *, + pubsub_items_t **items_out); + +/** + * Clear all pub_binding_t backpointers in items. + **/ +void pubsub_items_clear_bindings(pubsub_items_t *items); + +#define pubsub_items_free(cfg) \ + FREE_AND_NULL(pubsub_items_t, pubsub_items_free_, (cfg)) +void pubsub_items_free_(pubsub_items_t *cfg); + +#endif /* !defined(TOR_PUBSUB_BUILD_H) */ diff --git a/src/lib/pubsub/pubsub_builder_st.h b/src/lib/pubsub/pubsub_builder_st.h new file mode 100644 index 0000000000..545aa3f3ef --- /dev/null +++ b/src/lib/pubsub/pubsub_builder_st.h @@ -0,0 +1,161 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file pubsub_builder_st.h + * + * @brief private structures used for configuring dispatchers and messages. + */ + +#ifndef TOR_PUBSUB_BUILDER_ST_H +#define TOR_PUBSUB_BUILDER_ST_H + +#ifdef PUBSUB_PRIVATE + +#include +#include + +struct dispatch_cfg_t; +struct smartlist_t; +struct pub_binding_t; + +/** + * Configuration for a single publication or subscription request. + * + * These can be stored while the dispatcher is in use, but are only used for + * setup, teardown, and debugging. + * + * There are various fields in this request describing the message; all of + * them must match other descriptions of the message, or a bug has occurred. + **/ +typedef struct pubsub_cfg_t { + /** True if this is a publishing request; false for a subscribing request. */ + bool is_publish; + /** The system making this request. */ + subsys_id_t subsys; + /** The channel on which the message is to be sent. */ + channel_id_t channel; + /** The message ID to be sent or received. */ + message_id_t msg; + /** The C type associated with the message. */ + msg_type_id_t type; + /** One or more DISP_FLAGS_* items, combined with bitwise OR. */ + unsigned flags; + + /** + * Publishing only: a pub_binding object that will receive the binding for + * this request. We will finish filling this in when the dispatcher is + * constructed, so that the subsystem can publish then and not before. + */ + struct pub_binding_t *pub_binding; + + /** + * Subscribing only: a function to receive message objects for this request. + */ + recv_fn_t recv_fn; + + /** The file from which this message was configured */ + const char *added_by_file; + /** The line at which this message was configured */ + unsigned added_by_line; +} pubsub_cfg_t; + +/** + * Configuration request for a single C type. + * + * These are stored while the dispatcher is in use, but are only used for + * setup, teardown, and debugging. + **/ +typedef struct pubsub_type_cfg_t { + /** + * The identifier for this type. + */ + msg_type_id_t type; + /** + * Functions to use when manipulating the type. + */ + dispatch_typefns_t fns; + + /** The subsystem that configured this type. */ + subsys_id_t subsys; + /** The file from which this type was configured */ + const char *added_by_file; + /** The line at which this type was configured */ + unsigned added_by_line; +} pubsub_type_cfg_t; + +/** + * The set of configuration requests for a dispatcher, as made by various + * subsystems. + **/ +struct pubsub_items_t { + /** List of pubsub_cfg_t. */ + struct smartlist_t *items; + /** List of pubsub_type_cfg_t. */ + struct smartlist_t *type_items; +}; + +/** + * Type used to construct a dispatcher. We use this type to build up the + * configuration for a dispatcher, and then pass ownership of that + * configuration to the newly constructed dispatcher. + **/ +struct pubsub_builder_t { + /** Number of outstanding pubsub_connector_t objects pointing to this + * pubsub_builder_t. */ + int n_connectors; + /** Number of errors encountered while constructing this object so far. */ + int n_errors; + /** In-progress configuration that we're constructing, as a list of the + * requests that have been made. */ + struct pubsub_items_t *items; + /** In-progress configuration that we're constructing, in a form that can + * be converted to a dispatch_t. */ + struct dispatch_cfg_t *cfg; +}; + +/** + * Type given to a subsystem when adding connections to a pubsub_builder_t. + * We use this type to force each subsystem to get blamed for the + * publications, subscriptions, and types that it adds. + **/ +struct pubsub_connector_t { + /** The pubsub_builder that this connector refers to. */ + struct pubsub_builder_t *builder; + /** The subsystem that has been given this connector. */ + subsys_id_t subsys_id; +}; + +/** + * Helper structure used when constructing a dispatcher that sorts the + * pubsub_cfg_t objects in various ways. + **/ +typedef struct pubsub_adjmap_t { + /* XXXX The next three fields are currently constructed but not yet + * XXXX used. I believe we'll want them in the future, though. -nickm + */ + /** Number of subsystems; length of the *_by_subsys arrays. */ + size_t n_subsystems; + /** Array of lists of publisher pubsub_cfg_t objects, indexed by + * subsystem. */ + struct smartlist_t **pub_by_subsys; + /** Array of lists of subscriber pubsub_cfg_t objects, indexed by + * subsystem. */ + struct smartlist_t **sub_by_subsys; + + /** Number of message IDs; length of the *_by_msg arrays. */ + size_t n_msgs; + /** Array of lists of publisher pubsub_cfg_t objects, indexed by + * message ID. */ + struct smartlist_t **pub_by_msg; + /** Array of lists of subscriber pubsub_cfg_t objects, indexed by + * message ID. */ + struct smartlist_t **sub_by_msg; +} pubsub_adjmap_t; + +#endif /* defined(PUBSUB_PRIVATE) */ + +#endif /* !defined(TOR_PUBSUB_BUILDER_ST_H) */ diff --git a/src/lib/pubsub/pubsub_check.c b/src/lib/pubsub/pubsub_check.c new file mode 100644 index 0000000000..a3c22d4f25 --- /dev/null +++ b/src/lib/pubsub/pubsub_check.c @@ -0,0 +1,428 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file pubsub_check.c + * @brief Enforce various requirements on a pubsub_builder. + **/ + +#define PUBSUB_PRIVATE + +#include "lib/dispatch/dispatch_naming.h" +#include "lib/dispatch/msgtypes.h" +#include "lib/pubsub/pubsub_flags.h" +#include "lib/pubsub/pubsub_builder_st.h" +#include "lib/pubsub/pubsub_build.h" + +#include "lib/container/bitarray.h" +#include "lib/container/smartlist.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/malloc.h" +#include "lib/string/compat_string.h" + +#include + +static void pubsub_adjmap_add(pubsub_adjmap_t *map, + const pubsub_cfg_t *item); + +/** + * Helper: contruct and return a new pubsub_adjacency_map from cfg. + * Return NULL on error. + **/ +static pubsub_adjmap_t * +pubsub_build_adjacency_map(const pubsub_items_t *cfg) +{ + pubsub_adjmap_t *map = tor_malloc_zero(sizeof(*map)); + const size_t n_subsystems = get_num_subsys_ids(); + const size_t n_msgs = get_num_message_ids(); + + map->n_subsystems = n_subsystems; + map->n_msgs = n_msgs; + + map->pub_by_subsys = tor_calloc(n_subsystems, sizeof(smartlist_t*)); + map->sub_by_subsys = tor_calloc(n_subsystems, sizeof(smartlist_t*)); + map->pub_by_msg = tor_calloc(n_msgs, sizeof(smartlist_t*)); + map->sub_by_msg = tor_calloc(n_msgs, sizeof(smartlist_t*)); + + SMARTLIST_FOREACH_BEGIN(cfg->items, const pubsub_cfg_t *, item) { + pubsub_adjmap_add(map, item); + } SMARTLIST_FOREACH_END(item); + + return map; +} + +/** + * Helper: add a single pubsub_cfg_t to an adjacency map. + **/ +static void +pubsub_adjmap_add(pubsub_adjmap_t *map, + const pubsub_cfg_t *item) +{ + smartlist_t **by_subsys; + smartlist_t **by_msg; + + tor_assert(item->subsys < map->n_subsystems); + tor_assert(item->msg < map->n_msgs); + + if (item->is_publish) { + by_subsys = &map->pub_by_subsys[item->subsys]; + by_msg = &map->pub_by_msg[item->msg]; + } else { + by_subsys = &map->sub_by_subsys[item->subsys]; + by_msg = &map->sub_by_msg[item->msg]; + } + + if (! *by_subsys) + *by_subsys = smartlist_new(); + if (! *by_msg) + *by_msg = smartlist_new(); + smartlist_add(*by_subsys, (void*) item); + smartlist_add(*by_msg, (void *) item); +} + +/** + * Release all storage held by m and set m to NULL. + **/ +#define pubsub_adjmap_free(m) \ + FREE_AND_NULL(pubsub_adjmap_t, pubsub_adjmap_free_, m) + +/** + * Free every element of an n-element array of smartlists, then + * free the array itself. + **/ +static void +pubsub_adjmap_free_helper(smartlist_t **lsts, size_t n) +{ + if (!lsts) + return; + + for (unsigned i = 0; i < n; ++i) { + smartlist_free(lsts[i]); + } + tor_free(lsts); +} + +/** + * Release all storage held by map. + **/ +static void +pubsub_adjmap_free_(pubsub_adjmap_t *map) +{ + if (!map) + return; + pubsub_adjmap_free_helper(map->pub_by_subsys, map->n_subsystems); + pubsub_adjmap_free_helper(map->sub_by_subsys, map->n_subsystems); + pubsub_adjmap_free_helper(map->pub_by_msg, map->n_msgs); + pubsub_adjmap_free_helper(map->sub_by_msg, map->n_msgs); + tor_free(map); +} + +/** + * Helper: return the length of sl, or 0 if sl is NULL. + **/ +static int +smartlist_len_opt(const smartlist_t *sl) +{ + if (sl) + return smartlist_len(sl); + else + return 0; +} + +/** Return a pointer to a statically allocated string encoding the + * dispatcher flags in flags. */ +static const char * +format_flags(unsigned flags) +{ + static char buf[32]; + buf[0] = 0; + if (flags & DISP_FLAG_EXCL) { + strlcat(buf, " EXCL", sizeof(buf)); + } + if (flags & DISP_FLAG_STUB) { + strlcat(buf, " STUB", sizeof(buf)); + } + return buf[0] ? buf+1 : buf; +} + +/** + * Log a message containing a description of cfg at severity, prefixed + * by the string prefix. + */ +static void +pubsub_cfg_dump(const pubsub_cfg_t *cfg, int severity, const char *prefix) +{ + tor_assert(prefix); + + tor_log(severity, LD_MESG, + "%s%s %s: %s{%s} on %s (%s) <%u %u %u %u %x> [%s:%d]", + prefix, + get_subsys_id_name(cfg->subsys), + cfg->is_publish ? "PUB" : "SUB", + get_message_id_name(cfg->msg), + get_msg_type_id_name(cfg->type), + get_channel_id_name(cfg->channel), + format_flags(cfg->flags), + cfg->subsys, cfg->msg, cfg->type, cfg->channel, cfg->flags, + cfg->added_by_file, cfg->added_by_line); +} + +/** + * Helper: fill a bitarray out with entries corresponding to the + * subsystems listed in items. If any subsystem is listed more than + * once, log a warning. Return 0 on success, -1 on failure. + **/ +static int +get_message_bitarray(const pubsub_adjmap_t *map, + message_id_t msg, + const smartlist_t *items, + const char *operation, + bitarray_t **out) +{ + bool ok = true; + *out = bitarray_init_zero((unsigned)map->n_subsystems); + if (! items) + return 0; + + SMARTLIST_FOREACH_BEGIN(items, const pubsub_cfg_t *, cfg) { + if (bitarray_is_set(*out, cfg->subsys)) { + log_warn(LD_MESG|LD_BUG, + "Message \"%s\" is configured to be %s by subsystem " + "\"%s\" more than once.", + get_message_id_name(msg), operation, + get_subsys_id_name(cfg->subsys)); + ok = false; + } + bitarray_set(*out, cfg->subsys); + } SMARTLIST_FOREACH_END(cfg); + + return ok ? 0 : -1; +} + +/** + * Helper for lint_message: check that all the pubsub_cfg_t items in the two + * respective smartlists obey our local graph topology rules. + * + * (Right now this is just a matter of "each subsystem only + * publishes/subscribes once; no subsystem is a publisher and subscriber for + * the same message.") + * + * Return 0 on success, -1 on failure. + **/ +static int +lint_message_graph(const pubsub_adjmap_t *map, + message_id_t msg, + const smartlist_t *pub, + const smartlist_t *sub) +{ + bitarray_t *published_by = NULL; + bitarray_t *subscribed_by = NULL; + bool ok = true; + + if (get_message_bitarray(map, msg, pub, "published", &published_by) < 0) + ok = false; + if (get_message_bitarray(map, msg, sub, "subscribed", &subscribed_by) < 0) + ok = false; + + /* Check whether any subsystem is publishing and subscribing the same + * message. [??] + */ + for (unsigned i = 0; i < map->n_subsystems; ++i) { + if (bitarray_is_set(published_by, i) && + bitarray_is_set(subscribed_by, i)) { + log_warn(LD_MESG|LD_BUG, + "Message \"%s\" is published and subscribed by the same " + "subsystem \"%s\".", + get_message_id_name(msg), + get_subsys_id_name(i)); + ok = false; + } + } + + bitarray_free(published_by); + bitarray_free(subscribed_by); + + return ok ? 0 : -1; +} + +/** + * Helper for lint_message: check that all the pubsub_cfg_t items in the two + * respective smartlists have compatible flags, channels, and types. + **/ +static int +lint_message_consistency(message_id_t msg, + const smartlist_t *pub, + const smartlist_t *sub) +{ + if (!smartlist_len_opt(pub) && !smartlist_len_opt(sub)) + return 0; // LCOV_EXCL_LINE -- this was already checked. + + /* The 'all' list has the publishers and the subscribers. */ + smartlist_t *all = smartlist_new(); + if (pub) + smartlist_add_all(all, pub); + if (sub) + smartlist_add_all(all, sub); + + const pubsub_cfg_t *item0 = smartlist_get(all, 0); + + /* Indicates which subsystems we've found publishing/subscribing here. */ + bool pub_excl = false, sub_excl = false, chan_same = true, type_same = true; + + /* Simple message consistency properties across messages. + */ + SMARTLIST_FOREACH_BEGIN(all, const pubsub_cfg_t *, cfg) { + chan_same &= (cfg->channel == item0->channel); + type_same &= (cfg->type == item0->type); + if (cfg->is_publish) + pub_excl |= (cfg->flags & DISP_FLAG_EXCL) != 0; + else + sub_excl |= (cfg->flags & DISP_FLAG_EXCL) != 0; + } SMARTLIST_FOREACH_END(cfg); + + bool ok = true; + + if (! chan_same) { + log_warn(LD_MESG|LD_BUG, + "Message \"%s\" is associated with multiple inconsistent " + "channels.", + get_message_id_name(msg)); + ok = false; + } + if (! type_same) { + log_warn(LD_MESG|LD_BUG, + "Message \"%s\" is associated with multiple inconsistent " + "message types.", + get_message_id_name(msg)); + ok = false; + } + + /* Enforce exclusive-ness for publishers and subscribers that have asked for + * it. + */ + if (pub_excl && smartlist_len_opt(pub) > 1) { + log_warn(LD_MESG|LD_BUG, + "Message \"%s\" has multiple publishers, but at least one is " + "marked as exclusive.", + get_message_id_name(msg)); + ok = false; + } + if (sub_excl && smartlist_len_opt(sub) > 1) { + log_warn(LD_MESG|LD_BUG, + "Message \"%s\" has multiple subscribers, but at least one is " + "marked as exclusive.", + get_message_id_name(msg)); + ok = false; + } + + smartlist_free(all); + + return ok ? 0 : -1; +} + +/** + * Check whether there are any errors or inconsistencies for the message + * described by msg in map. If there are problems, log about + * them, and return -1. Otherwise return 0. + **/ +static int +lint_message(const pubsub_adjmap_t *map, message_id_t msg) +{ + /* NOTE: Some of the checks in this function are maybe over-zealous, and we + * might not want to have them forever. I've marked them with [?] below. + */ + if (BUG(msg >= map->n_msgs)) + return 0; // LCOV_EXCL_LINE + + const smartlist_t *pub = map->pub_by_msg[msg]; + const smartlist_t *sub = map->sub_by_msg[msg]; + + const size_t n_pub = smartlist_len_opt(pub); + const size_t n_sub = smartlist_len_opt(sub); + + if (n_pub == 0 && n_sub == 0) { + log_info(LD_MESG, "Nobody is publishing or subscribing to message " + "\"%s\".", + get_message_id_name(msg)); + return 0; // No publishers or subscribers: nothing to do. + } + /* We'll set this to false if there are any problems. */ + bool ok = true; + + /* First make sure that if there are publishers, there are subscribers. */ + if (n_pub == 0) { + log_warn(LD_MESG|LD_BUG, + "Message \"%s\" has subscribers, but no publishers.", + get_message_id_name(msg)); + ok = false; + } else if (n_sub == 0) { + log_warn(LD_MESG|LD_BUG, + "Message \"%s\" has publishers, but no subscribers.", + get_message_id_name(msg)); + ok = false; + } + + /* Check the message graph topology. */ + if (lint_message_graph(map, msg, pub, sub) < 0) + ok = false; + + /* Check whether the messages have the same fields set on them. */ + if (lint_message_consistency(msg, pub, sub) < 0) + ok = false; + + if (!ok) { + /* There was a problem -- let's log all the publishers and subscribers on + * this message */ + if (pub) { + SMARTLIST_FOREACH(pub, pubsub_cfg_t *, cfg, + pubsub_cfg_dump(cfg, LOG_WARN, " ")); + } + if (sub) { + SMARTLIST_FOREACH(sub, pubsub_cfg_t *, cfg, + pubsub_cfg_dump(cfg, LOG_WARN, " ")); + } + } + + return ok ? 0 : -1; +} + +/** + * Check all the messages in map for consistency. Return 0 on success, + * -1 on problems. + **/ +static int +pubsub_adjmap_check(const pubsub_adjmap_t *map) +{ + bool all_ok = true; + for (unsigned i = 0; i < map->n_msgs; ++i) { + if (lint_message(map, i) < 0) { + all_ok = false; + } + } + return all_ok ? 0 : -1; +} + +/** + * Check builder for consistency and various constraints. Return 0 on success, + * -1 on failure. + **/ +int +pubsub_builder_check(pubsub_builder_t *builder) +{ + pubsub_adjmap_t *map = pubsub_build_adjacency_map(builder->items); + int rv = -1; + + if (!map) + goto err; // should be impossible + + if (pubsub_adjmap_check(map) < 0) + goto err; + + rv = 0; + err: + pubsub_adjmap_free(map); + return rv; +} diff --git a/src/lib/pubsub/pubsub_connect.h b/src/lib/pubsub/pubsub_connect.h new file mode 100644 index 0000000000..0ad106044e --- /dev/null +++ b/src/lib/pubsub/pubsub_connect.h @@ -0,0 +1,54 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file pubsub_connect.h + * @brief Header for functions that add relationships to a pubsub builder. + * + * These functions are used by modules that need to add publication and + * subscription requests. Most users will want to call these functions + * indirectly, via the macros in pubsub_macros.h. + **/ + +#ifndef TOR_PUBSUB_CONNECT_H +#define TOR_PUBSUB_CONNECT_H + +#include "lib/dispatch/msgtypes.h" + +struct pub_binding_t; +/** + * A "dispatch connector" is a view of the dispatcher that a subsystem + * uses while initializing itself. It is specific to the subsystem, and + * ensures that each subsystem doesn't need to identify itself + * repeatedly while registering its messages. + **/ +typedef struct pubsub_connector_t pubsub_connector_t; + +int pubsub_add_pub_(struct pubsub_connector_t *con, + struct pub_binding_t *out, + channel_id_t channel, + message_id_t msg, + msg_type_id_t type, + unsigned flags, + const char *file, + unsigned line); + +int pubsub_add_sub_(struct pubsub_connector_t *con, + recv_fn_t recv_fn, + channel_id_t channel, + message_id_t msg, + msg_type_id_t type, + unsigned flags, + const char *file, + unsigned line); + +int pubsub_connector_register_type_(struct pubsub_connector_t *, + msg_type_id_t, + dispatch_typefns_t *, + const char *file, + unsigned line); + +#endif /* !defined(TOR_PUBSUB_CONNECT_H) */ diff --git a/src/lib/pubsub/pubsub_flags.h b/src/lib/pubsub/pubsub_flags.h new file mode 100644 index 0000000000..53c6e49565 --- /dev/null +++ b/src/lib/pubsub/pubsub_flags.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file pubsub_flags.h + * @brief Flags that can be set on publish/subscribe messages. + **/ + +#ifndef TOR_PUBSUB_FLAGS_H +#define TOR_PUBSUB_FLAGS_H + +/** + * Flag for registering a message: declare that no other module is allowed to + * publish this message if we are publishing it, or subscribe to it if we are + * subscribing to it. + */ +#define DISP_FLAG_EXCL (1u<<0) + +/** + * Flag for registering a message: declare that this message is a stub, and we + * will not actually publish/subscribe it, but that the dispatcher should + * treat us as if we did when typechecking. + * + * We use this so that messages aren't treated as "dangling" if they are + * potentially used by some other build of Tor. + */ +#define DISP_FLAG_STUB (1u<<1) + +#endif /* !defined(TOR_PUBSUB_FLAGS_H) */ diff --git a/src/lib/pubsub/pubsub_macros.h b/src/lib/pubsub/pubsub_macros.h new file mode 100644 index 0000000000..357e59fd54 --- /dev/null +++ b/src/lib/pubsub/pubsub_macros.h @@ -0,0 +1,373 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file pubsub_macros.h + * \brief Macros to help with the publish/subscribe dispatch API. + * + * The dispatch API allows different subsystems of Tor to communicate with + * another asynchronously via a shared "message" system. Some subsystems + * declare that they publish a given message, and others declare that they + * subscribe to it. Both subsystems depend on the message, but not upon one + * another. + * + * To declare a message, use DECLARE_MESSAGE() (for messages that take their + * data as a pointer) or DECLARE_MESSAGE_INT() (for messages that take their + * data as an integer. For example, you might say + * + * DECLARE_MESSAGE(new_circuit, circ, circuit_handle_t *); + * or + * DECLARE_MESSAGE_INT(shutdown_requested, boolean, bool); + * + * Every message has a unique name, a "type name" that the dispatch system + * uses to manage associated data, and a C type name. You'll want to put + * these declarations in a header, to be included by all publishers and all + * subscribers. + * + * When a subsystem wants to publish a message, it uses DECLARE_PUBLISH() at + * file scope to create necessary static functions. Then, in its subsystem + * initialization (in the "bind to dispatcher" callback) (TODO: name this + * properly!), it calls DISPATCH_ADD_PUB() to tell the dispatcher about its + * intent to publish. When it actually wants to publish, it uses the + * PUBLISH() macro. For example: + * + * // At file scope + * DECLARE_PUBLISH(shutdown_requested); + * + * static void bind_to_dispatcher(pubsub_connector_t *con) + * { + * DISPATCH_ADD_PUB(con, mainchannel, shutdown_requested); + * } + * + * // somewhere in a function + * { + * PUBLISH(shutdown_requested, true); + * } + * + * When a subsystem wants to subscribe to a message, it uses + * DECLARE_SUBSCRIBE() at file scope to declare static functions. It must + * declare a hook function that receives the message type. Then, in its "bind + * to dispatcher" function, it calls DISPATCHER_ADD_SUB() to tell the + * dispatcher about its intent to subscribe. When another module publishes + * the message, the dispatcher will call the provided hook function. + * + * // At file scope. The first argument is the message that you're + * // subscribing to; the second argument is the hook function to declare. + * DECLARE_SUBSCRIBE(shutdown_requested, on_shutdown_req_cb); + * + * // You need to declare this function. + * static void on_shutdown_req_cb(const msg_t *msg, + * bool value) + * { + * // (do something here.) + * } + * + * static void bind_to_dispatcher(pubsub_connector_t *con) + * { + * DISPATCH_ADD_SUB(con, mainchannel, shutdown_requested); + * } + * + * Where did these types come from? Somewhere in the code, you need to call + * DISPATCH_REGISTER_TYPE() to make sure that the dispatcher can manage the + * message auxiliary data. It associates a vtbl-like structure with the + * type name, so that the dispatcher knows how to manipulate the type you're + * giving it. + * + * For example, the "boolean" type we're using above could be defined as: + * + * static char *boolean_fmt(msg_aux_data_t d) + * { + * // This is used for debugging and dumping messages. + * if (d.u64) + * return tor_strdup("true"); + * else + * return tor_strdup("false"); + * } + * + * static void boolean_free(msg_aux_data_t d) + * { + * // We don't actually need to do anything to free a boolean. + * // We could use "NULL" instead of this function, but I'm including + * // it as an example. + * } + * + * static void bind_to_dispatcher(pubsub_connector_t *con) + * { + * dispatch_typefns_t boolean_fns = { + * .fmt_fn = boolean_fmt, + * .free_fn = boolean_free, + * }; + * DISPATCH_REGISTER_TYPE(con, boolean, &boolean_fns); + * } + * + * + * + * So, how does this all work? (You can stop reading here, unless you're + * debugging something.) + * + * When you declare a message in a header with DECLARE_MESSAGE() or + * DECLARE_MESSAGE_INT(), it creates five things: + * + * * two typedefs for the message argument (constant and non-constant + * variants). + * * a constant string to hold the declared message type name + * * two inline functions, to coerce the message argument type to and from + * a "msg_aux_data_t" union. + * + * All of these declarations have names based on the message name. + * + * Later, when you say DECLARE_PUBLISH() or DECLARE_SUBSCRIBE(), we use the + * elements defined by DECLARE_MESSAGE() to make sure that the publish + * function takes the correct argument type, and that the subscription hook is + * declared with the right argument type. + **/ + +#ifndef TOR_DISPATCH_MSG_H +#define TOR_DISPATCH_MSG_H + +#include "lib/cc/compat_compiler.h" +#include "lib/dispatch/dispatch_naming.h" +#include "lib/pubsub/pub_binding_st.h" +#include "lib/pubsub/pubsub_connect.h" +#include "lib/pubsub/pubsub_flags.h" +#include "lib/pubsub/pubsub_publish.h" + +/* Implemenation notes: + * + * For a messagename "foo", the DECLARE_MESSAGE*() macros must declare: + * + * msg_arg_type__foo -- a typedef for the argument type of the foo message. + * msg_arg_consttype__foo -- a typedef for the const argument type of the + * foo message. + * msg_arg_name__foo[] -- a static string constant holding the unique + * identifier for the type of the foo message. + * msg_arg_get__foo() -- an inline function taking a msg_aux_data_t and + * returning the C data type. + * msg_arg_set__foo() -- an inline function taking a msg_aux_data_t and + * the C type, setting the msg_aux_data_t to hold the C type. + * + * For a messagename "foo", the DECLARE_PUBLISH() macro must declare: + * + * pub_binding__foo -- A static pub_binding_t object used to send messages + * from this module. + * publish_fn__foo -- A function taking an argument of the appropriate + * C type, to be invoked by PUBLISH(). + * + * For a messagename "foo", the DECLARE_SUBSCRIBE() macro must declare: + * + * hookfn -- A user-provided function name, with the correct signature. + * recv_fn__foo -- A wrapper callback that takes a msg_t *, and calls + * hookfn with the appropriate arguments. + */ + +/* Macro to declare common elements shared by DECLARE_MESSAGE and + * DECLARE_MESSAGE_INT. Don't call this directly. + * + * Note that the "msg_arg_name" string constant is defined in each + * translation unit. This might be undesirable; we can tweak it in the + * future if need be. + */ +#define DECLARE_MESSAGE_COMMON__(messagename, typename, c_type) \ + typedef c_type msg_arg_type__ ##messagename; \ + typedef const c_type msg_arg_consttype__ ##messagename; \ + ATTR_UNUSED static const char msg_arg_name__ ##messagename[] = # typename; + +/** + * Use this macro in a header to declare the existence of a given message, + * taking a pointer as auxiliary data. + * + * "messagename" is a unique identifier for the message; it must be a valid + * C identifier. + * + * "typename" is a unique identifier for the type of the auxiliary data. + * It needs to be defined somewhere in Tor, using + * "DISPATCH_REGISTER_TYPE." + * + * "c_ptr_type" is a C pointer type (like "char *" or "struct foo *"). + * The "*" needs to be included. + */ +#define DECLARE_MESSAGE(messagename, typename, c_ptr_type) \ + DECLARE_MESSAGE_COMMON__(messagename, typename, c_ptr_type) \ + ATTR_UNUSED static inline c_ptr_type \ + msg_arg_get__ ##messagename(msg_aux_data_t m) \ + { \ + return m.ptr; \ + } \ + ATTR_UNUSED static inline void \ + msg_arg_set__ ##messagename(msg_aux_data_t *m, c_ptr_type v) \ + { \ + m->ptr = v; \ + } \ + EAT_SEMICOLON + +/** + * Use this macro in a header to declare the existence of a given message, + * taking an integer as auxiliary data. + * + * "messagename" is a unique identifier for the message; it must be a valid + * C identifier. + * + * "typename" is a unique identifier for the type of the auxiliary data. It + * needs to be defined somewhere in Tor, using "DISPATCH_REGISTER_TYPE." + * + * "c_type" is a C integer type, like "int" or "bool". It needs to fit inside + * a uint64_t. + */ +#define DECLARE_MESSAGE_INT(messagename, typename, c_type) \ + DECLARE_MESSAGE_COMMON__(messagename, typename, c_type) \ + ATTR_UNUSED static inline c_type \ + msg_arg_get__ ##messagename(msg_aux_data_t m) \ + { \ + return (c_type)m.u64; \ + } \ + ATTR_UNUSED static inline void \ + msg_arg_set__ ##messagename(msg_aux_data_t *m, c_type v) \ + { \ + m->u64 = (uint64_t)v; \ + } \ + EAT_SEMICOLON + +/** + * Use this macro inside a C module declare that we'll be publishing a given + * message type from within this module. + * + * It creates necessary functions and wrappers to publish a message whose + * unique identifier is "messagename". + * + * Before you use this, you need to include the header where DECLARE_MESSAGE*() + * was used for this message. + * + * You can only use this once per message in each subsystem. + */ +#define DECLARE_PUBLISH(messagename) \ + static pub_binding_t pub_binding__ ##messagename; \ + static void \ + publish_fn__ ##messagename(msg_arg_type__ ##messagename arg) \ + { \ + msg_aux_data_t data; \ + msg_arg_set__ ##messagename(&data, arg); \ + pubsub_pub_(&pub_binding__ ##messagename, data); \ + } \ + EAT_SEMICOLON + +/** + * Use this macro inside a C file to declare that we're subscribing to a + * given message and associating it with a given "hook function". It + * declares the hook function static, and helps with strong typing. + * + * Before you use this, you need to include the header where + * DECLARE_MESSAGE*() was used for the message whose unique identifier is + * "messagename". + * + * You will need to define a function with the name that you provide for + * "hookfn". The type of this function will be: + * static void hookfn(const msg_t *, const c_type) + * where c_type is the c type that you declared in the header. + * + * You can only use this once per message in each subsystem. + */ +#define DECLARE_SUBSCRIBE(messagename, hookfn) \ + static void hookfn(const msg_t *, \ + const msg_arg_consttype__ ##messagename); \ + static void recv_fn__ ## messagename(const msg_t *m) \ + { \ + msg_arg_type__ ## messagename arg; \ + arg = msg_arg_get__ ##messagename(m->aux_data__); \ + hookfn(m, arg); \ + } \ + EAT_SEMICOLON + +/** + * Add a fake use of the publish function for 'messagename', so that + * the compiler does not call it unused. + */ +#define DISPATCH__FAKE_USE_OF_PUBFN_(messagename) \ + ( 0 ? (publish_fn__ ##messagename((msg_arg_type__##messagename)0), 1) \ + : 1) + +/* + * This macro is for internal use. It backs DISPATCH_ADD_PUB*() + */ +#define DISPATCH_ADD_PUB_(connector, channel, messagename, flags) \ + ( \ + DISPATCH__FAKE_USE_OF_PUBFN_(messagename), \ + pubsub_add_pub_((connector), \ + &pub_binding__ ##messagename, \ + get_channel_id(# channel), \ + get_message_id(# messagename), \ + get_msg_type_id(msg_arg_name__ ## messagename), \ + (flags), \ + __FILE__, \ + __LINE__) \ + ) + +/** + * Use a given connector and channel name to declare that this subsystem will + * publish a given message type. + * + * Call this macro from within the add_subscriptions() function of a module. + */ +#define DISPATCH_ADD_PUB(connector, channel, messagename) \ + DISPATCH_ADD_PUB_(connector, channel, messagename, 0) + +/** + * Use a given connector and channel name to declare that this subsystem will + * publish a given message type, and that no other subsystem is allowed to. + * + * Call this macro from within the add_subscriptions() function of a module. + */ +#define DISPATCH_ADD_PUB_EXCL(connector, channel, messagename) \ + DISPATCH_ADD_PUB_(connector, channel, messagename, DISP_FLAG_EXCL) + +/* + * This macro is for internal use. It backs DISPATCH_ADD_SUB*() + */ +#define DISPATCH_ADD_SUB_(connector, channel, messagename, flags) \ + pubsub_add_sub_((connector), \ + recv_fn__ ##messagename, \ + get_channel_id(#channel), \ + get_message_id(# messagename), \ + get_msg_type_id(msg_arg_name__ ##messagename), \ + (flags), \ + __FILE__, \ + __LINE__) +/* + * Use a given connector and channel name to declare that this subsystem will + * receive a given message type. + * + * Call this macro from within the add_subscriptions() function of a module. + */ +#define DISPATCH_ADD_SUB(connector, channel, messagename) \ + DISPATCH_ADD_SUB_(connector, channel, messagename, 0) +/** + * Use a given connector and channel name to declare that this subsystem will + * receive a given message type, and that no other subsystem is allowed to do + * so. + * + * Call this macro from within the add_subscriptions() function of a module. + */ +#define DISPATCH_ADD_SUB_EXCL(connector, channel, messagename) \ + DISPATCH_ADD_SUB_(connector, channel, messagename, DISP_FLAG_EXCL) + +/** + * Publish a given message with a given argument. (Takes ownership of the + * argument if it is a pointer.) + */ +#define PUBLISH(messagename, arg) \ + publish_fn__ ##messagename(arg) + +/** + * Use a given connector to declare that the functions to be used to manipuate + * a certain C type. + **/ +#define DISPATCH_REGISTER_TYPE(con, type, fns) \ + pubsub_connector_register_type_((con), \ + get_msg_type_id(#type), \ + (fns), \ + __FILE__, \ + __LINE__) + +#endif /* !defined(TOR_DISPATCH_MSG_H) */ diff --git a/src/lib/pubsub/pubsub_publish.c b/src/lib/pubsub/pubsub_publish.c new file mode 100644 index 0000000000..454a335a78 --- /dev/null +++ b/src/lib/pubsub/pubsub_publish.c @@ -0,0 +1,72 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file pubsub_publish.c + * @brief Header for functions to publish using a pub_binding_t. + **/ + +#define PUBSUB_PRIVATE +#define DISPATCH_PRIVATE +#include "orconfig.h" + +#include "lib/dispatch/dispatch.h" +#include "lib/dispatch/dispatch_st.h" + +#include "lib/pubsub/pub_binding_st.h" +#include "lib/pubsub/pubsub_publish.h" + +#include "lib/malloc/malloc.h" +#include "lib/log/util_bug.h" + +#include + +/** + * Publish a message from the publication binding pub using the + * auxiliary data auxdata. + * + * Return 0 on success, -1 on failure. + **/ +int +pubsub_pub_(const pub_binding_t *pub, msg_aux_data_t auxdata) +{ + dispatch_t *d = pub->dispatch_ptr; + if (BUG(! d)) { + /* Tried to publish a message before the dispatcher was configured. */ + /* (Without a dispatcher, we don't know how to free auxdata.) */ + return -1; + } + + if (BUG(pub->msg_template.type >= d->n_types)) { + /* The type associated with this message is not known to the dispatcher. */ + /* (Without a correct type, we don't know how to free auxdata.) */ + return -1; + } + + if (BUG(pub->msg_template.msg >= d->n_msgs) || + BUG(pub->msg_template.channel >= d->n_queues)) { + /* The message ID or channel ID was out of bounds. */ + // LCOV_EXCL_START + d->typefns[pub->msg_template.type].free_fn(auxdata); + return -1; + // LCOV_EXCL_STOP + } + + if (! d->table[pub->msg_template.msg]) { + /* Fast path: nobody wants this data. */ + + // XXXX Faster path: we could store this in the pub_binding_t. + d->typefns[pub->msg_template.type].free_fn(auxdata); + return 0; + } + + /* Construct the message object */ + msg_t *m = tor_malloc(sizeof(msg_t)); + memcpy(m, &pub->msg_template, sizeof(msg_t)); + m->aux_data__ = auxdata; + + return dispatch_send_msg_unchecked(d, m); +} diff --git a/src/lib/pubsub/pubsub_publish.h b/src/lib/pubsub/pubsub_publish.h new file mode 100644 index 0000000000..0686a465de --- /dev/null +++ b/src/lib/pubsub/pubsub_publish.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_PUBSUB_PUBLISH_H +#define TOR_PUBSUB_PUBLISH_H + +#include "lib/dispatch/msgtypes.h" +struct pub_binding_t; + +int pubsub_pub_(const struct pub_binding_t *pub, msg_aux_data_t auxdata); + +#endif /* !defined(TOR_PUBSUB_PUBLISH_H) */ diff --git a/src/lib/sandbox/include.am b/src/lib/sandbox/include.am index adfda6bde5..e81f14b55f 100644 --- a/src/lib/sandbox/include.am +++ b/src/lib/sandbox/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-sandbox-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_sandbox_a_SOURCES = \ src/lib/sandbox/sandbox.c @@ -13,6 +14,7 @@ src_lib_libtor_sandbox_testing_a_SOURCES = \ src_lib_libtor_sandbox_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_sandbox_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/sandbox/linux_syscalls.inc \ src/lib/sandbox/sandbox.h diff --git a/src/lib/smartlist_core/include.am b/src/lib/smartlist_core/include.am index 99d65f0b23..548179bc4f 100644 --- a/src/lib/smartlist_core/include.am +++ b/src/lib/smartlist_core/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-smartlist-core-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_smartlist_core_a_SOURCES = \ src/lib/smartlist_core/smartlist_core.c \ src/lib/smartlist_core/smartlist_split.c @@ -15,6 +16,7 @@ src_lib_libtor_smartlist_core_testing_a_CPPFLAGS = \ $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_smartlist_core_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/smartlist_core/smartlist_core.h \ src/lib/smartlist_core/smartlist_foreach.h \ diff --git a/src/lib/smartlist_core/smartlist_core.c b/src/lib/smartlist_core/smartlist_core.c index ac85a6cc84..6b0a305a93 100644 --- a/src/lib/smartlist_core/smartlist_core.c +++ b/src/lib/smartlist_core/smartlist_core.c @@ -88,6 +88,30 @@ smartlist_ensure_capacity(smartlist_t *sl, size_t size) #undef MAX_CAPACITY } +/** Expand sl so that its length is at least new_size, + * filling in previously unused entries with NULL> + * + * Do nothing if sl already had at least new_size elements. + */ +void +smartlist_grow(smartlist_t *sl, size_t new_size) +{ + smartlist_ensure_capacity(sl, new_size); + + if (new_size > (size_t)sl->num_used) { + /* This memset() should be a no-op: everything else in the smartlist code + * tries to make sure that unused entries are always NULL. Still, that is + * meant as a safety mechanism, so let's clear the memory here. + */ + memset(sl->list + sl->num_used, 0, + sizeof(void *) * (new_size - sl->num_used)); + + /* This cast is safe, since we already asserted that we were below + * MAX_CAPACITY in smartlist_ensure_capacity(). */ + sl->num_used = (int)new_size; + } +} + /** Append element to the end of the list. */ void smartlist_add(smartlist_t *sl, void *element) @@ -153,6 +177,8 @@ smartlist_remove_keeporder(smartlist_t *sl, const void *element) sl->list[i++] = sl->list[j]; } } + memset(sl->list + sl->num_used, 0, + sizeof(void *) * (num_used_orig - sl->num_used)); } /** If sl is nonempty, remove and return the final element. Otherwise, diff --git a/src/lib/smartlist_core/smartlist_core.h b/src/lib/smartlist_core/smartlist_core.h index a7fbaa099b..795741c447 100644 --- a/src/lib/smartlist_core/smartlist_core.h +++ b/src/lib/smartlist_core/smartlist_core.h @@ -43,6 +43,7 @@ void smartlist_clear(smartlist_t *sl); void smartlist_add(smartlist_t *sl, void *element); void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2); void smartlist_add_strdup(struct smartlist_t *sl, const char *string); +void smartlist_grow(smartlist_t *sl, size_t new_size); void smartlist_remove(smartlist_t *sl, const void *element); void smartlist_remove_keeporder(smartlist_t *sl, const void *element); @@ -97,4 +98,4 @@ void smartlist_del(smartlist_t *sl, int idx); void smartlist_del_keeporder(smartlist_t *sl, int idx); void smartlist_insert(smartlist_t *sl, int idx, void *val); -#endif /* !defined(TOR_CONTAINER_H) */ +#endif /* !defined(TOR_SMARTLIST_CORE_H) */ diff --git a/src/lib/smartlist_core/smartlist_split.h b/src/lib/smartlist_core/smartlist_split.h index 4f72376125..e2cc7245b7 100644 --- a/src/lib/smartlist_core/smartlist_split.h +++ b/src/lib/smartlist_core/smartlist_split.h @@ -17,4 +17,4 @@ int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, int flags, int max); -#endif +#endif /* !defined(TOR_SMARTLIST_SPLIT_H) */ diff --git a/src/lib/string/compat_string.h b/src/lib/string/compat_string.h index a0e37bb6dc..4f30bf5392 100644 --- a/src/lib/string/compat_string.h +++ b/src/lib/string/compat_string.h @@ -25,14 +25,14 @@ static inline int strncasecmp(const char *a, const char *b, size_t n); static inline int strncasecmp(const char *a, const char *b, size_t n) { return _strnicmp(a,b,n); } -#endif +#endif /* !defined(HAVE_STRNCASECMP) */ #ifndef HAVE_STRCASECMP static inline int strcasecmp(const char *a, const char *b); static inline int strcasecmp(const char *a, const char *b) { return _stricmp(a,b); } -#endif -#endif +#endif /* !defined(HAVE_STRCASECMP) */ +#endif /* defined(_WIN32) */ #if defined __APPLE__ /* On OSX 10.9 and later, the overlap-checking code for strlcat would @@ -59,4 +59,4 @@ char *tor_strtok_r_impl(char *str, const char *sep, char **lasts); #define tor_strtok_r(str, sep, lasts) tor_strtok_r_impl(str, sep, lasts) #endif -#endif +#endif /* !defined(TOR_COMPAT_STRING_H) */ diff --git a/src/lib/string/include.am b/src/lib/string/include.am index edd74b8a3e..82d35cc5af 100644 --- a/src/lib/string/include.am +++ b/src/lib/string/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-string-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_string_a_SOURCES = \ src/lib/string/compat_ctype.c \ src/lib/string/compat_string.c \ @@ -18,6 +19,7 @@ src_lib_libtor_string_testing_a_SOURCES = \ src_lib_libtor_string_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_string_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/string/compat_ctype.h \ src/lib/string/compat_string.h \ diff --git a/src/lib/string/parse_int.h b/src/lib/string/parse_int.h index 925547942e..50d48b44c5 100644 --- a/src/lib/string/parse_int.h +++ b/src/lib/string/parse_int.h @@ -22,4 +22,4 @@ double tor_parse_double(const char *s, double min, double max, int *ok, uint64_t tor_parse_uint64(const char *s, int base, uint64_t min, uint64_t max, int *ok, char **next); -#endif +#endif /* !defined(TOR_PARSE_INT_H) */ diff --git a/src/lib/string/printf.c b/src/lib/string/printf.c index 415d4ac4a7..26203932e4 100644 --- a/src/lib/string/printf.c +++ b/src/lib/string/printf.c @@ -117,8 +117,8 @@ tor_vasprintf(char **strp, const char *fmt, va_list args) *strp = NULL; return -1; } - strp_tmp = tor_malloc(len + 1); - r = _vsnprintf(strp_tmp, len+1, fmt, args); + strp_tmp = tor_malloc((size_t)len + 1); + r = _vsnprintf(strp_tmp, (size_t)len+1, fmt, args); if (r != len) { tor_free(strp_tmp); *strp = NULL; @@ -131,21 +131,31 @@ tor_vasprintf(char **strp, const char *fmt, va_list args) * characters we need. We give it a try on a short buffer first, since * it might be nice to avoid the second vsnprintf call. */ + /* XXXX This code spent a number of years broken (see bug 30651). It is + * possible that no Tor users actually run on systems without vasprintf() or + * _vscprintf(). If so, we should consider removing this code. */ char buf[128]; int len, r; va_list tmp_args; va_copy(tmp_args, args); - /* vsnprintf() was properly checked but tor_vsnprintf() available so - * why not use it? */ - len = tor_vsnprintf(buf, sizeof(buf), fmt, tmp_args); + /* Use vsnprintf to retrieve needed length. tor_vsnprintf() is not an + * option here because it will simply return -1 if buf is not large enough + * to hold the complete string. + */ + len = vsnprintf(buf, sizeof(buf), fmt, tmp_args); va_end(tmp_args); + buf[sizeof(buf) - 1] = '\0'; + if (len < 0) { + *strp = NULL; + return -1; + } if (len < (int)sizeof(buf)) { *strp = tor_strdup(buf); return len; } - strp_tmp = tor_malloc(len+1); + strp_tmp = tor_malloc((size_t)len+1); /* use of tor_vsnprintf() will ensure string is null terminated */ - r = tor_vsnprintf(strp_tmp, len+1, fmt, args); + r = tor_vsnprintf(strp_tmp, (size_t)len+1, fmt, args); if (r != len) { tor_free(strp_tmp); *strp = NULL; diff --git a/src/lib/string/printf.h b/src/lib/string/printf.h index 2cc13d6bee..6e90770f81 100644 --- a/src/lib/string/printf.h +++ b/src/lib/string/printf.h @@ -27,4 +27,4 @@ int tor_asprintf(char **strp, const char *fmt, ...) int tor_vasprintf(char **strp, const char *fmt, va_list args) CHECK_PRINTF(2,0); -#endif /* !defined(TOR_UTIL_STRING_H) */ +#endif /* !defined(TOR_UTIL_PRINTF_H) */ diff --git a/src/lib/string/scanf.h b/src/lib/string/scanf.h index 6673173de5..b642e242db 100644 --- a/src/lib/string/scanf.h +++ b/src/lib/string/scanf.h @@ -21,4 +21,4 @@ int tor_vsscanf(const char *buf, const char *pattern, va_list ap) \ int tor_sscanf(const char *buf, const char *pattern, ...) CHECK_SCANF(2, 3); -#endif /* !defined(TOR_UTIL_STRING_H) */ +#endif /* !defined(TOR_UTIL_SCANF_H) */ diff --git a/src/lib/string/util_string.c b/src/lib/string/util_string.c index 0c4e399008..f5061a11d2 100644 --- a/src/lib/string/util_string.c +++ b/src/lib/string/util_string.c @@ -71,7 +71,7 @@ tor_memstr(const void *haystack, size_t hlen, const char *needle) /** Return true iff the 'len' bytes at 'mem' are all zero. */ int -tor_mem_is_zero(const char *mem, size_t len) +fast_mem_is_zero(const char *mem, size_t len) { static const char ZERO[] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, @@ -95,17 +95,14 @@ tor_mem_is_zero(const char *mem, size_t len) int tor_digest_is_zero(const char *digest) { - static const uint8_t ZERO_DIGEST[] = { - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 - }; - return tor_memeq(digest, ZERO_DIGEST, DIGEST_LEN); + return safe_mem_is_zero(digest, DIGEST_LEN); } /** Return true iff the DIGEST256_LEN bytes in digest are all zero. */ int tor_digest256_is_zero(const char *digest) { - return tor_mem_is_zero(digest, DIGEST256_LEN); + return safe_mem_is_zero(digest, DIGEST256_LEN); } /** Remove from the string s every character which appears in diff --git a/src/lib/string/util_string.h b/src/lib/string/util_string.h index da4fab159c..b3c6841d41 100644 --- a/src/lib/string/util_string.h +++ b/src/lib/string/util_string.h @@ -20,7 +20,10 @@ const void *tor_memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen); const void *tor_memstr(const void *haystack, size_t hlen, const char *needle); -int tor_mem_is_zero(const char *mem, size_t len); +int fast_mem_is_zero(const char *mem, size_t len); +#define fast_digest_is_zero(d) fast_mem_is_zero((d), DIGEST_LEN) +#define fast_digetst256_is_zero(d) fast_mem_is_zero((d), DIGEST256_LEN) + int tor_digest_is_zero(const char *digest); int tor_digest256_is_zero(const char *digest); diff --git a/src/lib/subsys/include.am b/src/lib/subsys/include.am index 4741126b14..c9ab54ca73 100644 --- a/src/lib/subsys/include.am +++ b/src/lib/subsys/include.am @@ -1,3 +1,4 @@ +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/subsys/subsys.h diff --git a/src/lib/subsys/subsys.h b/src/lib/subsys/subsys.h index 241ad7829c..21f984f32d 100644 --- a/src/lib/subsys/subsys.h +++ b/src/lib/subsys/subsys.h @@ -8,7 +8,7 @@ #include -struct dispatch_connector_t; +struct pubsub_connector_t; /** * A subsystem is a part of Tor that is initialized, shut down, configured, @@ -58,7 +58,7 @@ typedef struct subsys_fns_t { /** * Connect a subsystem to the message dispatch system. **/ - int (*add_pubsub)(struct dispatch_connector_t *); + int (*add_pubsub)(struct pubsub_connector_t *); /** * Perform any necessary pre-fork cleanup. This function may not fail. @@ -92,4 +92,4 @@ typedef struct subsys_fns_t { * less than this value. */ #define SUBSYS_LEVEL_LIBS -10 -#endif +#endif /* !defined(TOR_SUBSYS_T) */ diff --git a/src/lib/term/getpass.h b/src/lib/term/getpass.h index a9c146ea8f..aa597ec423 100644 --- a/src/lib/term/getpass.h +++ b/src/lib/term/getpass.h @@ -15,4 +15,4 @@ ssize_t tor_getpass(const char *prompt, char *output, size_t buflen); -#endif +#endif /* !defined(TOR_GETPASS_H) */ diff --git a/src/lib/term/include.am b/src/lib/term/include.am index 55fe548ebc..a120bba0cb 100644 --- a/src/lib/term/include.am +++ b/src/lib/term/include.am @@ -11,6 +11,7 @@ else readpassphrase_source= endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_term_a_SOURCES = \ src/lib/term/getpass.c \ $(readpassphrase_source) @@ -20,5 +21,6 @@ src_lib_libtor_term_testing_a_SOURCES = \ src_lib_libtor_term_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_term_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/term/getpass.h diff --git a/src/lib/testsupport/include.am b/src/lib/testsupport/include.am index b2aa620985..a5ed46eb67 100644 --- a/src/lib/testsupport/include.am +++ b/src/lib/testsupport/include.am @@ -1,3 +1,4 @@ +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/testsupport/testsupport.h diff --git a/src/lib/testsupport/testsupport.h b/src/lib/testsupport/testsupport.h index 9363a9ba66..631ec0228c 100644 --- a/src/lib/testsupport/testsupport.h +++ b/src/lib/testsupport/testsupport.h @@ -21,7 +21,7 @@ * tests. */ #define STATIC #define EXTERN(type, name) extern type name; -#else +#else /* !(defined(TOR_UNIT_TESTS)) */ #define STATIC static #define EXTERN(type, name) #endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/lib/thread/include.am b/src/lib/thread/include.am index 695795a2c8..cd8016b5df 100644 --- a/src/lib/thread/include.am +++ b/src/lib/thread/include.am @@ -12,6 +12,7 @@ if THREADS_WIN32 threads_impl_source=src/lib/thread/compat_winthreads.c endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_thread_a_SOURCES = \ src/lib/thread/compat_threads.c \ src/lib/thread/numcpus.c \ @@ -22,6 +23,7 @@ src_lib_libtor_thread_testing_a_SOURCES = \ src_lib_libtor_thread_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_thread_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/thread/numcpus.h \ src/lib/thread/thread_sys.h \ diff --git a/src/lib/thread/numcpus.h b/src/lib/thread/numcpus.h index 3f0a29ce7c..2f1ea16eb9 100644 --- a/src/lib/thread/numcpus.h +++ b/src/lib/thread/numcpus.h @@ -13,4 +13,4 @@ int compute_num_cpus(void); -#endif +#endif /* !defined(TOR_NUMCPUS_H) */ diff --git a/src/lib/time/compat_time.c b/src/lib/time/compat_time.c index c6625c7806..3f41500f3a 100644 --- a/src/lib/time/compat_time.c +++ b/src/lib/time/compat_time.c @@ -164,6 +164,8 @@ static int64_t last_tick_count = 0; * to be monotonic; increments them as appropriate so that they actually * _are_ monotonic. * + * The returned time may be the same as the previous returned time. + * * Caller must hold lock. */ STATIC int64_t ratchet_performance_counter(int64_t count_raw) @@ -202,6 +204,8 @@ static struct timeval timeofday_offset = { 0, 0 }; * supposed to be monotonic; increments them as appropriate so that they * actually _are_ monotonic. * + * The returned time may be the same as the previous returned time. + * * Caller must hold lock. */ STATIC void ratchet_timeval(const struct timeval *timeval_raw, struct timeval *out) @@ -270,7 +274,9 @@ monotime_init_internal(void) } /** - * Set "out" to the most recent monotonic time value + * Set "out" to the most recent monotonic time value. + * + * The returned time may be the same as the previous returned time. */ void monotime_get(monotime_t *out) @@ -298,10 +304,12 @@ monotime_coarse_get(monotime_coarse_t *out) #endif /* defined(TOR_UNIT_TESTS) */ out->abstime_ = mach_approximate_time(); } -#endif +#endif /* defined(HAVE_MACH_APPROXIMATE_TIME) */ /** * Return the number of nanoseconds between start and end. + * + * The returned value may be equal to zero. */ int64_t monotime_diff_nsec(const monotime_t *start, @@ -519,7 +527,7 @@ monotime_init_internal(void) HANDLE h = load_windows_system_library(TEXT("kernel32.dll")); if (h) { - GetTickCount64_fn = (GetTickCount64_fn_t) + GetTickCount64_fn = (GetTickCount64_fn_t) (void(*)(void)) GetProcAddress(h, "GetTickCount64"); } // We can't call FreeLibrary(h) here, because freeing the handle may @@ -759,7 +767,7 @@ monotime_coarse_zero(monotime_coarse_t *out) { memset(out, 0, sizeof(*out)); } -#endif +#endif /* defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT) */ int64_t monotime_diff_usec(const monotime_t *start, @@ -825,7 +833,7 @@ monotime_coarse_absolute_msec(void) { return monotime_coarse_absolute_nsec() / ONE_MILLION; } -#else +#else /* !(defined(MONOTIME_COARSE_FN_IS_DIFFERENT)) */ #define initialized_at_coarse initialized_at #endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ @@ -857,7 +865,7 @@ monotime_msec_to_approx_coarse_stamp_units(uint64_t msec) mach_time_info.numer; return abstime_val >> monotime_shift; } -#else +#else /* !(defined(__APPLE__)) */ uint64_t monotime_coarse_stamp_units_to_approx_msec(uint64_t units) { @@ -868,4 +876,4 @@ monotime_msec_to_approx_coarse_stamp_units(uint64_t msec) { return (msec * STAMP_TICKS_PER_SECOND) / 1000; } -#endif +#endif /* defined(__APPLE__) */ diff --git a/src/lib/time/compat_time.h b/src/lib/time/compat_time.h index 2cd4b3bee3..8c7661d7cb 100644 --- a/src/lib/time/compat_time.h +++ b/src/lib/time/compat_time.h @@ -15,11 +15,29 @@ * of tens of milliseconds. */ -/* Q: Should you use monotime or monotime_coarse as your source? +/* Q: When should I use monotonic time? + * + * A: If you need a time that never decreases, use monotonic time. If you need + * to send a time to a user or another process, or store a time, use the + * wall-clock time. + * + * Q: Should you use monotime or monotime_coarse as your source? * * A: Generally, you get better precision with monotime, but better * performance with monotime_coarse. * + * Q: What is a "monotonic" time, exactly? + * + * A: Monotonic times are strictly non-decreasing. The difference between any + * previous monotonic time, and the current monotonic time, is always greater + * than *or equal to* zero. + * Zero deltas happen more often: + * - on Windows (due to an OS bug), + * - when using monotime_coarse, or on systems with low-resolution timers, + * - on platforms where we emulate monotonic time using wall-clock time, and + * - when using time units that are larger than nanoseconds (due to + * truncation on division). + * * Q: Should you use monotime_t or monotime_coarse_t directly? Should you use * usec? msec? "stamp units?" * @@ -95,7 +113,7 @@ * All, "timestamp units": Cheap everywhere: it never divides. * * Q: This is only somewhat related, but how much precision could I hope for - * from a libevent time.? + * from a libevent time? * * A: Actually, it's _very_ related if you're timing in order to have a * timeout happen. @@ -182,26 +200,36 @@ void monotime_init(void); void monotime_get(monotime_t *out); /** * Return the number of nanoseconds between start and end. + * The returned value may be equal to zero. */ int64_t monotime_diff_nsec(const monotime_t *start, const monotime_t *end); /** * Return the number of microseconds between start and end. + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ int64_t monotime_diff_usec(const monotime_t *start, const monotime_t *end); /** * Return the number of milliseconds between start and end. + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ int64_t monotime_diff_msec(const monotime_t *start, const monotime_t *end); /** * Return the number of nanoseconds since the timer system was initialized. + * The returned value may be equal to zero. */ uint64_t monotime_absolute_nsec(void); /** * Return the number of microseconds since the timer system was initialized. + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ MOCK_DECL(uint64_t, monotime_absolute_usec,(void)); /** * Return the number of milliseconds since the timer system was initialized. + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ uint64_t monotime_absolute_msec(void); @@ -225,6 +253,9 @@ void monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec); * Set out to the current coarse time. */ void monotime_coarse_get(monotime_coarse_t *out); +/** + * Like monotime_absolute_*(), but faster on some platforms. + */ uint64_t monotime_coarse_absolute_nsec(void); uint64_t monotime_coarse_absolute_usec(void); uint64_t monotime_coarse_absolute_msec(void); @@ -248,18 +279,27 @@ uint32_t monotime_coarse_to_stamp(const monotime_coarse_t *t); /** * Convert a difference, expressed in the units of monotime_coarse_to_stamp, * into an approximate number of milliseconds. + * + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ uint64_t monotime_coarse_stamp_units_to_approx_msec(uint64_t units); uint64_t monotime_msec_to_approx_coarse_stamp_units(uint64_t msec); uint32_t monotime_coarse_get_stamp(void); #if defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT) +/** + * Like monotime_diff_*(), but faster on some platforms. + */ int64_t monotime_coarse_diff_nsec(const monotime_coarse_t *start, const monotime_coarse_t *end); int64_t monotime_coarse_diff_usec(const monotime_coarse_t *start, const monotime_coarse_t *end); int64_t monotime_coarse_diff_msec(const monotime_coarse_t *start, const monotime_coarse_t *end); +/** + * Like monotime_*(), but faster on some platforms. + */ void monotime_coarse_zero(monotime_coarse_t *out); int monotime_coarse_is_zero(const monotime_coarse_t *val); void monotime_coarse_add_msec(monotime_coarse_t *out, @@ -278,6 +318,9 @@ void monotime_coarse_add_msec(monotime_coarse_t *out, * * Requires that the difference fit into an int32_t; not for use with * large time differences. + * + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ int32_t monotime_coarse_diff_msec32_(const monotime_coarse_t *start, const monotime_coarse_t *end); @@ -287,6 +330,9 @@ int32_t monotime_coarse_diff_msec32_(const monotime_coarse_t *start, * * Requires that the difference fit into an int32_t; not for use with * large time differences. + * + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. */ static inline int32_t monotime_coarse_diff_msec32(const monotime_coarse_t *start, @@ -298,7 +344,7 @@ monotime_coarse_diff_msec32(const monotime_coarse_t *start, #else #define USING_32BIT_MSEC_HACK return monotime_coarse_diff_msec32_(start, end); -#endif +#endif /* SIZEOF_VOID_P == 8 */ } #ifdef TOR_UNIT_TESTS diff --git a/src/lib/time/include.am b/src/lib/time/include.am index dae16f49ac..dcb199b142 100644 --- a/src/lib/time/include.am +++ b/src/lib/time/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-time-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_time_a_SOURCES = \ src/lib/time/compat_time.c \ src/lib/time/time_sys.c \ @@ -15,6 +16,7 @@ src_lib_libtor_time_testing_a_SOURCES = \ src_lib_libtor_time_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_time_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/time/compat_time.h \ src/lib/time/time_sys.h \ diff --git a/src/lib/time/tvdiff.h b/src/lib/time/tvdiff.h index 724af1528a..657cb99553 100644 --- a/src/lib/time/tvdiff.h +++ b/src/lib/time/tvdiff.h @@ -20,4 +20,4 @@ int64_t tv_to_msec(const struct timeval *tv); time_t time_diff(const time_t from, const time_t to); -#endif +#endif /* !defined(TOR_TVDIFF_H) */ diff --git a/src/lib/tls/include.am b/src/lib/tls/include.am index 1817739eef..7e05ef4f8c 100644 --- a/src/lib/tls/include.am +++ b/src/lib/tls/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-tls-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_tls_a_SOURCES = \ src/lib/tls/buffers_tls.c \ src/lib/tls/tortls.c \ @@ -29,6 +30,7 @@ src_lib_libtor_tls_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_tls_testing_a_CFLAGS = \ $(AM_CFLAGS) $(TOR_CFLAGS_CRYPTLIB) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/tls/ciphers.inc \ src/lib/tls/buffers_tls.h \ diff --git a/src/lib/tls/nss_countbytes.h b/src/lib/tls/nss_countbytes.h index 8b31603923..47f220c4c1 100644 --- a/src/lib/tls/nss_countbytes.h +++ b/src/lib/tls/nss_countbytes.h @@ -22,4 +22,4 @@ int tor_get_prfiledesc_byte_counts(struct PRFileDesc *fd, uint64_t *n_read_out, uint64_t *n_written_out); -#endif +#endif /* !defined(TOR_NSS_COUNTBYTES_H) */ diff --git a/src/lib/tls/tortls.h b/src/lib/tls/tortls.h index 8efc7a1c98..9e195c6af2 100644 --- a/src/lib/tls/tortls.h +++ b/src/lib/tls/tortls.h @@ -25,12 +25,12 @@ struct ssl_ctx_st; struct ssl_session_st; typedef struct ssl_ctx_st tor_tls_context_impl_t; typedef struct ssl_st tor_tls_impl_t; -#else +#else /* !(defined(ENABLE_OPENSSL)) */ struct PRFileDesc; typedef struct PRFileDesc tor_tls_context_impl_t; typedef struct PRFileDesc tor_tls_impl_t; -#endif -#endif +#endif /* defined(ENABLE_OPENSSL) */ +#endif /* defined(TORTLS_PRIVATE) */ struct tor_x509_cert_t; @@ -144,9 +144,9 @@ void check_no_tls_errors_(const char *fname, int line); void tor_tls_log_one_error(tor_tls_t *tls, unsigned long err, int severity, int domain, const char *doing); -#else +#else /* !(defined(ENABLE_OPENSSL)) */ #define check_no_tls_errors() STMT_NIL -#endif +#endif /* defined(ENABLE_OPENSSL) */ int tor_tls_get_my_certs(int server, const struct tor_x509_cert_t **link_cert_out, diff --git a/src/lib/tls/tortls_internal.h b/src/lib/tls/tortls_internal.h index 071c506561..866483a94c 100644 --- a/src/lib/tls/tortls_internal.h +++ b/src/lib/tls/tortls_internal.h @@ -61,8 +61,8 @@ STATIC int tor_tls_session_secret_cb(struct ssl_st *ssl, void *secret, void *arg); STATIC int find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher); -#endif -#endif +#endif /* defined(TORTLS_OPENSSL_PRIVATE) */ +#endif /* defined(ENABLE_OPENSSL) */ #ifdef TOR_UNIT_TESTS extern int tor_tls_object_ex_data_index; @@ -73,4 +73,4 @@ extern uint64_t total_bytes_written_over_tls; extern uint64_t total_bytes_written_by_tls; #endif /* defined(TOR_UNIT_TESTS) */ -#endif /* defined(TORTLS_INTERNAL_H) */ +#endif /* !defined(TORTLS_INTERNAL_H) */ diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c index b40f948a3b..86f0ac42cc 100644 --- a/src/lib/tls/tortls_openssl.c +++ b/src/lib/tls/tortls_openssl.c @@ -25,7 +25,7 @@ * and mess things up, in at least some openssl versions. */ #include #include -#endif +#endif /* defined(_WIN32) */ #include "lib/crypt_ops/crypto_cipher.h" #include "lib/crypt_ops/crypto_rand.h" @@ -318,7 +318,7 @@ tor_tls_init(void) #else SSL_library_init(); SSL_load_error_strings(); -#endif +#endif /* defined(OPENSSL_1_1_API) */ #if (SIZEOF_VOID_P >= 8 && \ OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1)) @@ -383,7 +383,7 @@ static const char SERVER_CIPHER_LIST[] = * conclude that it has no valid ciphers if it's running with TLS1.3. */ TLS1_3_TXT_AES_128_GCM_SHA256 ":" -#endif +#endif /* defined(TLS1_3_TXT_AES_128_GCM_SHA256) */ TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" TLS1_TXT_DHE_RSA_WITH_AES_128_SHA; @@ -657,7 +657,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, if (r < 0) goto error; } -#else +#else /* !(defined(SSL_CTX_set1_groups_list) || ...) */ if (! is_client) { int nid; EC_KEY *ec_key; @@ -673,7 +673,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, SSL_CTX_set_tmp_ecdh(result->ctx, ec_key); EC_KEY_free(ec_key); } -#endif +#endif /* defined(SSL_CTX_set1_groups_list) || ...) */ SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER, always_accept_verify_cb); /* let us realloc bufs that we're writing from */ @@ -1062,7 +1062,7 @@ tor_tls_new(tor_socket_t sock, int isServer) /* We can't actually use TLS 1.3 until this bug is fixed. */ SSL_set_max_proto_version(result->ssl, TLS1_2_VERSION); } -#endif +#endif /* defined(SSL_CTRL_SET_MAX_PROTO_VERSION) */ if (!SSL_set_cipher_list(result->ssl, isServer ? SERVER_CIPHER_LIST : CLIENT_CIPHER_LIST)) { @@ -1728,7 +1728,7 @@ tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out, else return -1; } -#endif +#endif /* defined(TLS1_3_VERSION) */ return (r == 1) ? 0 : -1; } diff --git a/src/lib/tls/tortls_st.h b/src/lib/tls/tortls_st.h index 3f7ea8ac6a..73f6e6ecca 100644 --- a/src/lib/tls/tortls_st.h +++ b/src/lib/tls/tortls_st.h @@ -64,7 +64,7 @@ struct tor_tls_t { void (*negotiated_callback)(tor_tls_t *tls, void *arg); /** Argument to pass to negotiated_callback. */ void *callback_arg; -#endif +#endif /* defined(ENABLE_OPENSSL) */ #ifdef ENABLE_NSS /** Last values retried from tor_get_prfiledesc_byte_counts(). */ uint64_t last_write_count; @@ -72,4 +72,4 @@ struct tor_tls_t { #endif }; -#endif +#endif /* !defined(TOR_TORTLS_ST_H) */ diff --git a/src/lib/tls/x509.h b/src/lib/tls/x509.h index 5e6660de5c..0390a5464d 100644 --- a/src/lib/tls/x509.h +++ b/src/lib/tls/x509.h @@ -35,7 +35,7 @@ struct tor_x509_cert_t { common_digests_t cert_digests; common_digests_t pkey_digests; }; -#endif +#endif /* defined(TOR_X509_PRIVATE) */ void tor_tls_pick_certificate_lifetime(time_t now, unsigned cert_lifetime, @@ -47,7 +47,7 @@ tor_x509_cert_t *tor_x509_cert_replace_expiration( const tor_x509_cert_t *inp, time_t new_expiration_time, crypto_pk_t *signing_key); -#endif +#endif /* defined(TOR_UNIT_TESTS) */ tor_x509_cert_t *tor_x509_cert_dup(const tor_x509_cert_t *cert); @@ -72,4 +72,4 @@ int tor_tls_cert_is_valid(int severity, time_t now, int check_rsa_1024); -#endif +#endif /* !defined(TOR_X509_H) */ diff --git a/src/lib/tls/x509_internal.h b/src/lib/tls/x509_internal.h index bf2bec9689..f858baae98 100644 --- a/src/lib/tls/x509_internal.h +++ b/src/lib/tls/x509_internal.h @@ -50,4 +50,4 @@ int tor_x509_cert_set_cached_der_encoding(tor_x509_cert_t *cert); #define tor_x509_cert_set_cached_der_encoding(cert) (0) #endif -#endif +#endif /* !defined(TOR_X509_INTERNAL_H) */ diff --git a/src/lib/tls/x509_nss.c b/src/lib/tls/x509_nss.c index fb4af54c52..e04afaf07b 100644 --- a/src/lib/tls/x509_nss.c +++ b/src/lib/tls/x509_nss.c @@ -120,13 +120,13 @@ tor_tls_create_certificate_internal(crypto_pk_t *rsa, der.data, der.len, (SECKEYPrivateKey *)signing_key,//const &cert->signature); -#else +#else /* !(0) */ s = SEC_DerSignData(cert->arena, &signed_der, der.data, der.len, (SECKEYPrivateKey *)signing_key,//const SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION); -#endif +#endif /* 0 */ if (s != SECSuccess) goto err; @@ -145,7 +145,7 @@ tor_tls_create_certificate_internal(crypto_pk_t *rsa, &result_cert->signatureWrap, issuer_pk, NULL); tor_assert(cert_ok == SECSuccess); } -#endif +#endif /* 1 */ err: if (subject_spki) @@ -455,4 +455,4 @@ tor_x509_cert_replace_expiration(const tor_x509_cert_t *inp, return newcert ? tor_x509_cert_new(newcert) : NULL; } -#endif +#endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/lib/tls/x509_openssl.c b/src/lib/tls/x509_openssl.c index a344279c22..03f65049cf 100644 --- a/src/lib/tls/x509_openssl.c +++ b/src/lib/tls/x509_openssl.c @@ -59,12 +59,12 @@ ENABLE_GCC_WARNING(redundant-decls) #define X509_get_notAfter(cert) \ X509_getm_notAfter(cert) #endif -#else /* ! OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */ +#else /* !(defined(OPENSSL_1_1_API)) */ #define X509_get_notBefore_const(cert) \ ((const ASN1_TIME*) X509_get_notBefore((X509 *)cert)) #define X509_get_notAfter_const(cert) \ ((const ASN1_TIME*) X509_get_notAfter((X509 *)cert)) -#endif +#endif /* defined(OPENSSL_1_1_API) */ /** Return a newly allocated X509 name with commonName cname. */ static X509_NAME * diff --git a/src/lib/trace/debug.h b/src/lib/trace/debug.h index e35616cf50..92bb95c883 100644 --- a/src/lib/trace/debug.h +++ b/src/lib/trace/debug.h @@ -27,4 +27,4 @@ "\"" XSTR(subsystem) "\" hit. " \ "(line "XSTR(__LINE__) ")") -#endif /* TOR_TRACE_LOG_DEBUG_H */ +#endif /* !defined(TOR_TRACE_LOG_DEBUG_H) */ diff --git a/src/lib/trace/events.h b/src/lib/trace/events.h index 1e1e7b9d16..0674f7d501 100644 --- a/src/lib/trace/events.h +++ b/src/lib/trace/events.h @@ -34,12 +34,12 @@ #include "lib/trace/debug.h" #endif -#else /* TOR_EVENT_TRACING_ENABLED */ +#else /* !(defined(TOR_EVENT_TRACING_ENABLED)) */ /* Reaching this point, we NOP every event declaration because event tracing * is not been enabled at compile time. */ #define tor_trace(subsystem, name, args...) -#endif /* TOR_EVENT_TRACING_ENABLED */ +#endif /* defined(TOR_EVENT_TRACING_ENABLED) */ -#endif /* TOR_TRACE_EVENTS_H */ +#endif /* !defined(TOR_TRACE_EVENTS_H) */ diff --git a/src/lib/trace/include.am b/src/lib/trace/include.am index 6f10c98744..98098c87f4 100644 --- a/src/lib/trace/include.am +++ b/src/lib/trace/include.am @@ -2,6 +2,7 @@ noinst_LIBRARIES += \ src/lib/libtor-trace.a +# ADD_C_FILE: INSERT HEADERS HERE. TRACEHEADERS = \ src/lib/trace/trace.h \ src/lib/trace/events.h @@ -11,7 +12,7 @@ TRACEHEADERS += \ src/lib/trace/debug.h endif -# Library source files. +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_trace_a_SOURCES = \ src/lib/trace/trace.c diff --git a/src/lib/trace/trace.h b/src/lib/trace/trace.h index 606d435568..5001b28a1d 100644 --- a/src/lib/trace/trace.h +++ b/src/lib/trace/trace.h @@ -11,4 +11,4 @@ void tor_trace_init(void); -#endif // TOR_TRACE_TRACE_H +#endif /* !defined(TOR_TRACE_TRACE_H) */ diff --git a/src/lib/version/include.am b/src/lib/version/include.am index 6944eb05e3..0ae31be1b2 100644 --- a/src/lib/version/include.am +++ b/src/lib/version/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-version-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_version_a_SOURCES = \ src/lib/version/git_revision.c \ src/lib/version/version.c @@ -20,6 +21,7 @@ src/lib/version/git_revision.$(OBJEXT) \ src/lib/version/src_lib_libtor_version_testing_a-git_revision.$(OBJEXT): \ micro-revision.i +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/version/git_revision.h \ src/lib/version/torversion.h diff --git a/src/lib/wallclock/approx_time.h b/src/lib/wallclock/approx_time.h index e6b53f2c27..e7da160122 100644 --- a/src/lib/wallclock/approx_time.h +++ b/src/lib/wallclock/approx_time.h @@ -22,4 +22,4 @@ time_t approx_time(void); void update_approx_time(time_t now); #endif /* defined(TIME_IS_FAST) */ -#endif +#endif /* !defined(TOR_APPROX_TIME_H) */ diff --git a/src/lib/wallclock/include.am b/src/lib/wallclock/include.am index 2351252e0c..2b50d6ccbb 100644 --- a/src/lib/wallclock/include.am +++ b/src/lib/wallclock/include.am @@ -5,6 +5,7 @@ if UNITTESTS_ENABLED noinst_LIBRARIES += src/lib/libtor-wallclock-testing.a endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_wallclock_a_SOURCES = \ src/lib/wallclock/approx_time.c \ src/lib/wallclock/time_to_tm.c \ @@ -15,6 +16,7 @@ src_lib_libtor_wallclock_testing_a_SOURCES = \ src_lib_libtor_wallclock_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_lib_libtor_wallclock_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/wallclock/approx_time.h \ src/lib/wallclock/timeval.h \ diff --git a/src/lib/wallclock/time_to_tm.h b/src/lib/wallclock/time_to_tm.h index abe78c0efe..da27fcaba1 100644 --- a/src/lib/wallclock/time_to_tm.h +++ b/src/lib/wallclock/time_to_tm.h @@ -19,4 +19,4 @@ struct tm *tor_localtime_r_msg(const time_t *timep, struct tm *result, struct tm *tor_gmtime_r_msg(const time_t *timep, struct tm *result, char **err_out); -#endif +#endif /* !defined(TOR_WALLCLOCK_TIME_TO_TM_H) */ diff --git a/src/lib/wallclock/timeval.h b/src/lib/wallclock/timeval.h index 4967e939bf..e632d04a04 100644 --- a/src/lib/wallclock/timeval.h +++ b/src/lib/wallclock/timeval.h @@ -20,6 +20,27 @@ #include #endif +#ifdef TOR_COVERAGE +/* For coverage builds, we use a slower definition of these macros without + * branches, to make coverage consistent. */ +#undef timeradd +#undef timersub +#define timeradd(tv1,tv2,tvout) \ + do { \ + (tvout)->tv_sec = (tv1)->tv_sec + (tv2)->tv_sec; \ + (tvout)->tv_usec = (tv1)->tv_usec + (tv2)->tv_usec; \ + (tvout)->tv_sec += (tvout)->tv_usec / 1000000; \ + (tvout)->tv_usec %= 1000000; \ + } while (0) +#define timersub(tv1,tv2,tvout) \ + do { \ + (tvout)->tv_sec = (tv1)->tv_sec - (tv2)->tv_sec - 1; \ + (tvout)->tv_usec = (tv1)->tv_usec - (tv2)->tv_usec + 1000000; \ + (tvout)->tv_sec += (tvout)->tv_usec / 1000000; \ + (tvout)->tv_usec %= 1000000; \ + } while (0) +#endif /* defined(TOR_COVERAGE) */ + #ifndef timeradd /** Replacement for timeradd on platforms that do not have it: sets tvout to * the sum of tv1 and tv2. */ @@ -62,4 +83,4 @@ ((tv1)->tv_sec op (tv2)->tv_sec)) #endif /* !defined(timercmp) */ -#endif +#endif /* !defined(TOR_TIMEVAL_H) */ diff --git a/src/lib/wallclock/tor_gettimeofday.h b/src/lib/wallclock/tor_gettimeofday.h index c7fff9747a..6fec2fc893 100644 --- a/src/lib/wallclock/tor_gettimeofday.h +++ b/src/lib/wallclock/tor_gettimeofday.h @@ -17,4 +17,4 @@ struct timeval; MOCK_DECL(void, tor_gettimeofday, (struct timeval *timeval)); -#endif +#endif /* !defined(TOR_GETTIMEOFDAY_H) */ diff --git a/src/rust/protover/ffi.rs b/src/rust/protover/ffi.rs index 066b08eddb..14170d0353 100644 --- a/src/rust/protover/ffi.rs +++ b/src/rust/protover/ffi.rs @@ -31,6 +31,7 @@ fn translate_to_rust(c_proto: uint32_t) -> Result { 8 => Ok(Protocol::Microdesc), 9 => Ok(Protocol::Cons), 10 => Ok(Protocol::Padding), + 11 => Ok(Protocol::FlowCtrl), _ => Err(ProtoverError::UnknownProtocol), } } diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs index 74158d9f6d..7a76fcdd94 100644 --- a/src/rust/protover/protover.rs +++ b/src/rust/protover/protover.rs @@ -47,6 +47,7 @@ pub enum Protocol { Microdesc, Relay, Padding, + FlowCtrl, } impl fmt::Display for Protocol { @@ -75,6 +76,7 @@ impl FromStr for Protocol { "Microdesc" => Ok(Protocol::Microdesc), "Relay" => Ok(Protocol::Relay), "Padding" => Ok(Protocol::Padding), + "FlowCtrl" => Ok(Protocol::FlowCtrl), _ => Err(ProtoverError::UnknownProtocol), } } @@ -166,7 +168,8 @@ pub(crate) fn get_supported_protocols_cstr() -> &'static CStr { LinkAuth=3 \ Microdesc=1-2 \ Relay=1-2 \ - Padding=1" + Padding=2 \ + FlowCtrl=1" ) } else { cstr!( @@ -180,7 +183,8 @@ pub(crate) fn get_supported_protocols_cstr() -> &'static CStr { LinkAuth=1,3 \ Microdesc=1-2 \ Relay=1-2 \ - Padding=1" + Padding=2 \ + FlowCtrl=1" ) } } diff --git a/src/rust/tor_log/tor_log.rs b/src/rust/tor_log/tor_log.rs index 98fccba5a9..bbaf97129c 100644 --- a/src/rust/tor_log/tor_log.rs +++ b/src/rust/tor_log/tor_log.rs @@ -99,14 +99,14 @@ pub mod log { /// Domain log types. These mirror definitions in src/lib/log/log.h /// C_RUST_COUPLED: src/lib/log/log.c, log severity types extern "C" { - static LD_NET_: u32; - static LD_GENERAL_: u32; + static LD_NET_: u64; + static LD_GENERAL_: u64; } /// Translate Rust defintions of log domain levels to C. This exposes a 1:1 /// mapping between types. #[inline] - pub unsafe fn translate_domain(domain: LogDomain) -> u32 { + pub unsafe fn translate_domain(domain: LogDomain) -> u64 { match domain { LogDomain::Net => LD_NET_, LogDomain::General => LD_GENERAL_, @@ -128,7 +128,7 @@ pub mod log { extern "C" { pub fn tor_log_string( severity: c_int, - domain: u32, + domain: u64, function: *const c_char, string: *const c_char, ); diff --git a/src/test/bench.c b/src/test/bench.c index 65fa617cbd..cf732df593 100644 --- a/src/test/bench.c +++ b/src/test/bench.c @@ -22,7 +22,7 @@ #include #include #include -#endif +#endif /* defined(ENABLE_OPENSSL) */ #include "core/or/circuitlist.h" #include "app/config/config.h" @@ -701,7 +701,7 @@ bench_ecdh_p224(void) { bench_ecdh_impl(NID_secp224r1, "P-224"); } -#endif +#endif /* defined(ENABLE_OPENSSL) */ static void bench_md_parse(void) diff --git a/src/test/fuzz/fixup_filenames.sh b/src/test/fuzz/fixup_filenames.sh index 68efc1abc5..f730d532a5 100755 --- a/src/test/fuzz/fixup_filenames.sh +++ b/src/test/fuzz/fixup_filenames.sh @@ -8,9 +8,9 @@ if [ ! -d "$1" ] ; then fi for fn in "$1"/* ; do - prev=`basename "$fn"` - post=`sha256sum "$fn" | sed -e 's/ .*//;'` - if [ "$prev" == "$post" ] ; then + prev=$(basename "$fn") + post=$(sha256sum "$fn" | sed -e 's/ .*//;') + if [ "$prev" = "$post" ] ; then echo "OK $prev" else echo "mv $prev $post" diff --git a/src/test/fuzz/fuzz_multi.sh b/src/test/fuzz/fuzz_multi.sh index b4a17ed8cb..406ab498d9 100755 --- a/src/test/fuzz/fuzz_multi.sh +++ b/src/test/fuzz/fuzz_multi.sh @@ -1,3 +1,5 @@ +#!/bin/sh + MEMLIMIT_BYTES=21990500990976 N_CPUS=1 @@ -6,9 +8,9 @@ if [ $# -ge 1 ]; then shift fi -FILTER=echo +FILTER="echo" -for i in `seq -w "$N_CPUS"`; do +for i in $(seq -w "$N_CPUS"); do if [ "$i" -eq 1 ]; then if [ "$N_CPUS" -eq 1 ]; then INSTANCE="" diff --git a/src/test/fuzz/fuzz_strops.c b/src/test/fuzz/fuzz_strops.c index 64a6453050..459b4e21aa 100644 --- a/src/test/fuzz/fuzz_strops.c +++ b/src/test/fuzz/fuzz_strops.c @@ -86,15 +86,13 @@ b16_enc(const chunk_t *inp) return ch; } -#if 0 static chunk_t * b32_dec(const chunk_t *inp) { chunk_t *ch = chunk_new(inp->len);//XXXX int r = base32_decode((char *)ch->buf, ch->len, (char *)inp->buf, inp->len); if (r >= 0) { - ch->len = r; // XXXX we need some way to get the actual length of - // XXXX the output here. + ch->len = r; } else { chunk_free(ch); } @@ -108,7 +106,6 @@ b32_enc(const chunk_t *inp) ch->len = strlen((char *) ch->buf); return ch; } -#endif static chunk_t * b64_dec(const chunk_t *inp) @@ -222,10 +219,7 @@ fuzz_main(const uint8_t *stdin_buf, size_t data_size) ENCODE_ROUNDTRIP(b16_enc, b16_dec, chunk_free_); break; case 1: - /* - XXXX see notes above about our base-32 functions. ENCODE_ROUNDTRIP(b32_enc, b32_dec, chunk_free_); - */ break; case 2: ENCODE_ROUNDTRIP(b64_enc, b64_dec, chunk_free_); @@ -241,6 +235,18 @@ fuzz_main(const uint8_t *stdin_buf, size_t data_size) kv_flags = 0; ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_); break; + case 7: + kv_flags = KV_OMIT_VALS; + ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_); + break; + case 8: + kv_flags = KV_QUOTED; + ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_); + break; + case 9: + kv_flags = KV_QUOTED|KV_OMIT_VALS; + ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_); + break; } return 0; diff --git a/src/test/fuzz/fuzzing.h b/src/test/fuzz/fuzzing.h index 150ac4aa7d..2d278825ec 100644 --- a/src/test/fuzz/fuzzing.h +++ b/src/test/fuzz/fuzzing.h @@ -9,5 +9,5 @@ int fuzz_main(const uint8_t *data, size_t sz); void disable_signature_checking(void); -#endif /* FUZZING_H */ +#endif /* !defined(FUZZING_H) */ diff --git a/src/test/fuzz/fuzzing_common.c b/src/test/fuzz/fuzzing_common.c index 387c865a9b..6d0f9d7d60 100644 --- a/src/test/fuzz/fuzzing_common.c +++ b/src/test/fuzz/fuzzing_common.c @@ -137,7 +137,7 @@ LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) return fuzz_main(Data, Size); } -#else /* Not LLVM_FUZZ, so AFL. */ +#else /* !(defined(LLVM_FUZZ)) */ int main(int argc, char **argv) @@ -194,4 +194,4 @@ main(int argc, char **argv) return 0; } -#endif +#endif /* defined(LLVM_FUZZ) */ diff --git a/src/test/fuzz/minimize.sh b/src/test/fuzz/minimize.sh index 87d3dda13c..ce43812bb8 100755 --- a/src/test/fuzz/minimize.sh +++ b/src/test/fuzz/minimize.sh @@ -7,7 +7,7 @@ if [ ! -d "$1" ] ; then exit 1 fi -which=`basename "$1"` +which=$(basename "$1") mkdir "$1.out" afl-cmin -i "$1" -o "$1.out" -m none "./src/test/fuzz/fuzz-${which}" diff --git a/src/test/fuzz_static_testcases.sh b/src/test/fuzz_static_testcases.sh index f7b3adffb1..b883352402 100755 --- a/src/test/fuzz_static_testcases.sh +++ b/src/test/fuzz_static_testcases.sh @@ -14,7 +14,7 @@ fi for fuzzer in "${builddir:-.}"/src/test/fuzz/fuzz-* ; do - f=`basename $fuzzer` + f=$(basename "$fuzzer") case="${f#fuzz-}" if [ -d "${TOR_FUZZ_CORPORA}/${case}" ]; then echo "Running tests for ${case}" diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c index f2ae8398df..0a21fe576b 100644 --- a/src/test/hs_test_helpers.c +++ b/src/test/hs_test_helpers.c @@ -21,26 +21,35 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now, /* For a usable intro point we need at least two link specifiers: One legacy * keyid and one ipv4 */ { - hs_desc_link_specifier_t *ls_legacy = tor_malloc_zero(sizeof(*ls_legacy)); - hs_desc_link_specifier_t *ls_v4 = tor_malloc_zero(sizeof(*ls_v4)); - ls_legacy->type = LS_LEGACY_ID; - memcpy(ls_legacy->u.legacy_id, "0299F268FCA9D55CD157976D39AE92B4B455B3A8", - DIGEST_LEN); - ls_v4->u.ap.port = 9001; - int family = tor_addr_parse(&ls_v4->u.ap.addr, addr); + tor_addr_t a; + tor_addr_make_unspec(&a); + link_specifier_t *ls_legacy = link_specifier_new(); + link_specifier_t *ls_ip = link_specifier_new(); + link_specifier_set_ls_type(ls_legacy, LS_LEGACY_ID); + memset(link_specifier_getarray_un_legacy_id(ls_legacy), 'C', + link_specifier_getlen_un_legacy_id(ls_legacy)); + int family = tor_addr_parse(&a, addr); switch (family) { case AF_INET: - ls_v4->type = LS_IPV4; + link_specifier_set_ls_type(ls_ip, LS_IPV4); + link_specifier_set_un_ipv4_addr(ls_ip, tor_addr_to_ipv4h(&a)); + link_specifier_set_un_ipv4_port(ls_ip, 9001); break; case AF_INET6: - ls_v4->type = LS_IPV6; + link_specifier_set_ls_type(ls_ip, LS_IPV6); + memcpy(link_specifier_getarray_un_ipv6_addr(ls_ip), + tor_addr_to_in6_addr8(&a), + link_specifier_getlen_un_ipv6_addr(ls_ip)); + link_specifier_set_un_ipv6_port(ls_ip, 9001); break; default: - /* Stop the test, not suppose to have an error. */ - tt_int_op(family, OP_EQ, AF_INET); + /* Stop the test, not supposed to have an error. + * Compare with -1 to show the actual family. + */ + tt_int_op(family, OP_EQ, -1); } smartlist_add(ip->link_specifiers, ls_legacy); - smartlist_add(ip->link_specifiers, ls_v4); + smartlist_add(ip->link_specifiers, ls_ip); } ret = ed25519_keypair_generate(&auth_kp, 0); @@ -202,7 +211,6 @@ void hs_helper_desc_equal(const hs_descriptor_t *desc1, const hs_descriptor_t *desc2) { - char *addr1 = NULL, *addr2 = NULL; /* Plaintext data section. */ tt_int_op(desc1->plaintext_data.version, OP_EQ, desc2->plaintext_data.version); @@ -291,35 +299,57 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1, tt_int_op(smartlist_len(ip1->link_specifiers), ==, smartlist_len(ip2->link_specifiers)); for (int j = 0; j < smartlist_len(ip1->link_specifiers); j++) { - hs_desc_link_specifier_t *ls1 = smartlist_get(ip1->link_specifiers, j), - *ls2 = smartlist_get(ip2->link_specifiers, j); - tt_int_op(ls1->type, ==, ls2->type); - switch (ls1->type) { + link_specifier_t *ls1 = smartlist_get(ip1->link_specifiers, j), + *ls2 = smartlist_get(ip2->link_specifiers, j); + tt_int_op(link_specifier_get_ls_type(ls1), ==, + link_specifier_get_ls_type(ls2)); + switch (link_specifier_get_ls_type(ls1)) { case LS_IPV4: + { + uint32_t addr1 = link_specifier_get_un_ipv4_addr(ls1); + uint32_t addr2 = link_specifier_get_un_ipv4_addr(ls2); + tt_int_op(addr1, OP_EQ, addr2); + uint16_t port1 = link_specifier_get_un_ipv4_port(ls1); + uint16_t port2 = link_specifier_get_un_ipv4_port(ls2); + tt_int_op(port1, ==, port2); + } + break; case LS_IPV6: { - addr1 = tor_addr_to_str_dup(&ls1->u.ap.addr); - addr2 = tor_addr_to_str_dup(&ls2->u.ap.addr); - tt_str_op(addr1, OP_EQ, addr2); - tor_free(addr1); - tor_free(addr2); - tt_int_op(ls1->u.ap.port, ==, ls2->u.ap.port); + const uint8_t *addr1 = + link_specifier_getconstarray_un_ipv6_addr(ls1); + const uint8_t *addr2 = + link_specifier_getconstarray_un_ipv6_addr(ls2); + tt_int_op(link_specifier_getlen_un_ipv6_addr(ls1), OP_EQ, + link_specifier_getlen_un_ipv6_addr(ls2)); + tt_mem_op(addr1, OP_EQ, addr2, + link_specifier_getlen_un_ipv6_addr(ls1)); + uint16_t port1 = link_specifier_get_un_ipv6_port(ls1); + uint16_t port2 = link_specifier_get_un_ipv6_port(ls2); + tt_int_op(port1, ==, port2); } break; case LS_LEGACY_ID: - tt_mem_op(ls1->u.legacy_id, OP_EQ, ls2->u.legacy_id, - sizeof(ls1->u.legacy_id)); + { + const uint8_t *id1 = + link_specifier_getconstarray_un_legacy_id(ls1); + const uint8_t *id2 = + link_specifier_getconstarray_un_legacy_id(ls2); + tt_int_op(link_specifier_getlen_un_legacy_id(ls1), OP_EQ, + link_specifier_getlen_un_legacy_id(ls2)); + tt_mem_op(id1, OP_EQ, id2, + link_specifier_getlen_un_legacy_id(ls1)); + } break; default: /* Unknown type, caught it and print its value. */ - tt_int_op(ls1->type, OP_EQ, -1); + tt_int_op(link_specifier_get_ls_type(ls1), OP_EQ, -1); } } } } done: - tor_free(addr1); - tor_free(addr2); + ; } diff --git a/src/test/include.am b/src/test/include.am index d585c2a38a..85f9c9f880 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -32,8 +32,15 @@ endif if USEPYTHON TESTSCRIPTS += src/test/test_ntor.sh src/test/test_hs_ntor.sh src/test/test_bt.sh + +if COVERAGE_ENABLED +# ... +else +# Only do this when coverage is not on, since it invokes lots of code +# in a kind of unpredictable way. TESTSCRIPTS += src/test/test_rebind.sh endif +endif TESTS += src/test/test src/test/test-slow src/test/test-memwipe \ src/test/test_workqueue \ @@ -46,10 +53,8 @@ TESTS += src/test/test src/test/test-slow src/test/test-memwipe \ TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v2-min hs-v3-min \ single-onion-v23 # only run if we can ping6 ::1 (localhost) -# IPv6-only v3 single onion services don't work yet, so we don't test the -# single-onion-v23-ipv6-md flavor TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-v23-ipv6-md \ - single-onion-ipv6-md + single-onion-v23-ipv6-md # only run if we can find a stable (or simply another) version of tor TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v2 @@ -85,10 +90,13 @@ src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \ src_test_test_SOURCES = if UNITTESTS_ENABLED + +# ADD_C_FILE: INSERT SOURCES HERE. src_test_test_SOURCES += \ src/test/log_test_helpers.c \ src/test/hs_test_helpers.c \ src/test/rend_test_helpers.c \ + src/test/rng_test_helpers.c \ src/test/test.c \ src/test/test_accounting.c \ src/test/test_addr.c \ @@ -126,6 +134,7 @@ src_test_test_SOURCES += \ src/test/test_dir.c \ src/test/test_dir_common.c \ src/test/test_dir_handle_get.c \ + src/test/test_dispatch.c \ src/test/test_dos.c \ src/test/test_entryconn.c \ src/test/test_entrynodes.c \ @@ -150,6 +159,7 @@ src_test_test_SOURCES += \ src/test/test_logging.c \ src/test/test_mainloop.c \ src/test/test_microdesc.c \ + src/test/test_namemap.c \ src/test/test_netinfo.c \ src/test/test_nodelist.c \ src/test/test_oom.c \ @@ -165,6 +175,8 @@ src_test_test_SOURCES += \ src/test/test_proto_misc.c \ src/test/test_protover.c \ src/test/test_pt.c \ + src/test/test_pubsub_build.c \ + src/test/test_pubsub_msg.c \ src/test/test_relay.c \ src/test/test_relaycell.c \ src/test/test_relaycrypt.c \ @@ -175,6 +187,7 @@ src_test_test_SOURCES += \ src/test/test_routerlist.c \ src/test/test_routerset.c \ src/test/test_scheduler.c \ + src/test/test_sendme.c \ src/test/test_shared_random.c \ src/test/test_socks.c \ src/test/test_status.c \ @@ -207,10 +220,13 @@ endif src_test_test_slow_SOURCES = if UNITTESTS_ENABLED src_test_test_slow_SOURCES += \ + src/test/rng_test_helpers.c \ src/test/test_slow.c \ src/test/test_crypto_slow.c \ src/test/test_process_slow.c \ src/test/test_prob_distr.c \ + src/test/ptr_helpers.c \ + src/test/test_ptr_slow.c \ src/test/testing_common.c \ src/test/testing_rsakeys.c \ src/ext/tinytest.c @@ -308,12 +324,15 @@ src_test_test_timers_LDADD = \ @TOR_LZMA_LIBS@ src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS+= \ src/test/fakechans.h \ src/test/hs_test_helpers.h \ src/test/log_test_helpers.h \ src/test/rend_test_helpers.h \ + src/test/rng_test_helpers.h \ src/test/test.h \ + src/test/ptr_helpers.h \ src/test/test_helpers.h \ src/test/test_dir_common.h \ src/test/test_connection.h \ diff --git a/src/test/ope_ref.py b/src/test/ope_ref.py index f9bd97c546..b2f7012563 100644 --- a/src/test/ope_ref.py +++ b/src/test/ope_ref.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # Copyright 2018-2019, The Tor Project, Inc. See LICENSE for licensing info. # Reference implementation for our rudimentary OPE code, used to diff --git a/src/test/ptr_helpers.c b/src/test/ptr_helpers.c new file mode 100644 index 0000000000..a55ab437fa --- /dev/null +++ b/src/test/ptr_helpers.c @@ -0,0 +1,50 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "test/ptr_helpers.h" + +/** + * Cast (inptr_t value) to a void pointer. + */ +void * +cast_intptr_to_voidstar(intptr_t x) +{ + void *r = (void *)x; + + return r; +} + +/** + * Cast x (void pointer) to inptr_t value. + */ +intptr_t +cast_voidstar_to_intptr(void *x) +{ + intptr_t r = (intptr_t)x; + + return r; +} + +/** + * Cast x (uinptr_t value) to void pointer. + */ +void * +cast_uintptr_to_voidstar(uintptr_t x) +{ + void *r = (void *)x; + + return r; +} + +/** + * Cast x (void pointer) to uinptr_t value. + */ +uintptr_t +cast_voidstar_to_uintptr(void *x) +{ + uintptr_t r = (uintptr_t)x; + + return r; +} diff --git a/src/test/ptr_helpers.h b/src/test/ptr_helpers.h new file mode 100644 index 0000000000..7349bddd51 --- /dev/null +++ b/src/test/ptr_helpers.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_PTR_HELPERS_H +#define TOR_PTR_HELPERS_H + +#include + +void * +cast_intptr_to_voidstar(intptr_t x); + +intptr_t +cast_voidstar_to_intptr(void *x); + +void * +cast_uintptr_to_voidstar(uintptr_t x); + +uintptr_t +cast_voidstar_to_uintptr(void *x); + +#endif /* !defined(TOR_PTR_HELPERS_H) */ diff --git a/src/test/rng_test_helpers.c b/src/test/rng_test_helpers.c new file mode 100644 index 0000000000..7024fb5793 --- /dev/null +++ b/src/test/rng_test_helpers.c @@ -0,0 +1,259 @@ +/* Copyright (c) 2018-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file rng_test_helpers.c + * \brief Helpers for overriding PRNGs during unit tests. + * + * We define two PRNG overrides: a "reproducible PRNG" where the seed is + * chosen randomly but the stream can be replayed later on in case a bug is + * found, and a "deterministic PRNG" where the seed is fixed in the unit + * tests. + * + * Obviously, this code is testing-only. + */ + +#include "orconfig.h" +#include "core/or/or.h" + +#include "lib/crypt_ops/crypto_rand.h" +#include "ext/tinytest.h" + +#include "test/rng_test_helpers.h" + +#ifndef TOR_UNIT_TESTS +#error "No. Never link this code into Tor proper." +#endif + +/** + * True iff the RNG is currently replaced. Prevents double-replacement. + **/ +static bool rng_is_replaced = false; + +/** + * Mutex to protect deterministic prng. + * + * Note that if you actually _use_ the prng from two threads at the same time, + * the results will probably be nondeterministic anyway. + */ +static tor_mutex_t *rng_mutex = NULL; + +/** + * Cached old value for the thread prng. + **/ +static crypto_fast_rng_t *stored_fast_rng = NULL; + +/** replacement for crypto_strongest_rand that delegates to crypto_rand. */ +static void +mock_crypto_strongest_rand(uint8_t *out, size_t len) +{ + crypto_rand((char *)out, len); +} + +/* This is the seed of the deterministic randomness. */ +static uint8_t rng_seed[16]; +static crypto_xof_t *rng_xof = NULL; + +/** + * Print the seed for our PRNG to stdout. We use this when we're failed + * test that had a reproducible RNG set. + **/ +void +testing_dump_reproducible_rng_seed(void) +{ + printf("\n" + "Seed: %s\n", + hex_str((const char*)rng_seed, sizeof(rng_seed))); +} + +/** Produce deterministic randomness for the stochastic tests using the global + * rng_xof output. + * + * This function produces deterministic data over multiple calls iff it's + * called in the same call order with the same 'n' parameter. + * If not, outputs will deviate. */ +static void +crypto_rand_deterministic(char *out, size_t n) +{ + tor_assert(rng_xof); + tor_mutex_acquire(rng_mutex); + crypto_xof_squeeze_bytes(rng_xof, (uint8_t*)out, n); + tor_mutex_release(rng_mutex); +} + +/** + * Implementation helper: override our crypto_rand() PRNG with a given seed of + * length seed_len. Overlong seeds are truncated; short ones are + * padded. + **/ +static void +enable_deterministic_rng_impl(const uint8_t *seed, size_t seed_len) +{ + tor_assert(!rng_is_replaced); + tor_assert(crypto_rand == crypto_rand__real); + + memset(rng_seed, 0, sizeof(rng_seed)); + memcpy(rng_seed, seed, MIN(seed_len, sizeof(rng_seed))); + + rng_mutex = tor_mutex_new(); + + crypto_xof_free(rng_xof); + rng_xof = crypto_xof_new(); + crypto_xof_add_bytes(rng_xof, rng_seed, sizeof(rng_seed)); + MOCK(crypto_rand, crypto_rand_deterministic); + MOCK(crypto_strongest_rand_, mock_crypto_strongest_rand); + + uint8_t fast_rng_seed[CRYPTO_FAST_RNG_SEED_LEN]; + memset(fast_rng_seed, 0xff, sizeof(fast_rng_seed)); + memcpy(fast_rng_seed, rng_seed, MIN(sizeof(rng_seed), + sizeof(fast_rng_seed))); + crypto_fast_rng_t *fast_rng = crypto_fast_rng_new_from_seed(fast_rng_seed); + crypto_fast_rng_disable_reseed(fast_rng); + stored_fast_rng = crypto_replace_thread_fast_rng(fast_rng); + + rng_is_replaced = true; +} + +/** + * Replace our get_thread_fast_rng(), crypto_rand() and + * crypto_strongest_rand() prngs with a variant that generates all of its + * output deterministically from a randomly chosen seed. In the event of an + * error, you can log the seed later on with + * testing_dump_reproducible_rng_seed. + **/ +void +testing_enable_reproducible_rng(void) +{ + const char *provided_seed = getenv("TOR_TEST_RNG_SEED"); + if (provided_seed) { + size_t hexlen = strlen(provided_seed); + size_t seedlen = hexlen / 2; + uint8_t *seed = tor_malloc(hexlen / 2); + if (base16_decode((char*)seed, seedlen, provided_seed, hexlen) < 0) { + puts("Cannot decode value in TOR_TEST_RNG_SEED"); + exit(1); + } + enable_deterministic_rng_impl(seed, seedlen); + tor_free(seed); + } else { + uint8_t seed[16]; + crypto_rand((char*)seed, sizeof(seed)); + enable_deterministic_rng_impl(seed, sizeof(seed)); + } +} + +/** + * Replace our get_thread_fast_rng(), crypto_rand() and + * crypto_strongest_rand() prngs with a variant that generates all of its + * output deterministically from a fixed seed. This variant is mainly useful + * for cases when we don't want coverage to change between runs. + * + * USAGE NOTE: Test correctness SHOULD NOT depend on the specific output of + * this "rng". If you need a specific output, use + * testing_enable_prefilled_rng() instead. + **/ +void +testing_enable_deterministic_rng(void) +{ + static const uint8_t quotation[] = + "What will it be? A tree? A weed? " + "Each one is started from a seed."; // -- Mary Ann Hoberman + enable_deterministic_rng_impl(quotation, sizeof(quotation)); +} + +static uint8_t *prefilled_rng_buffer = NULL; +static size_t prefilled_rng_buflen; +static size_t prefilled_rng_idx; + +/** + * crypto_rand() replacement that returns canned data. + **/ +static void +crypto_rand_prefilled(char *out, size_t n) +{ + tor_mutex_acquire(rng_mutex); + while (n) { + size_t n_to_copy = MIN(prefilled_rng_buflen - prefilled_rng_idx, n); + memcpy(out, prefilled_rng_buffer + prefilled_rng_idx, n_to_copy); + out += n_to_copy; + n -= n_to_copy; + prefilled_rng_idx += n_to_copy; + + if (prefilled_rng_idx == prefilled_rng_buflen) { + prefilled_rng_idx = 0; + } + } + tor_mutex_release(rng_mutex); +} + +/** + * Replace our crypto_rand() and crypto_strongest_rand() prngs with a variant + * that yields output from a buffer. If it reaches the end of the buffer, it + * starts over. + * + * Note: the get_thread_fast_rng() prng is not replaced by this; we'll need + * more code to support that. + **/ +void +testing_enable_prefilled_rng(const void *buffer, size_t buflen) +{ + tor_assert(buflen > 0); + tor_assert(!rng_mutex); + rng_mutex = tor_mutex_new(); + + tor_mutex_acquire(rng_mutex); + + prefilled_rng_buffer = tor_memdup(buffer, buflen); + prefilled_rng_buflen = buflen; + prefilled_rng_idx = 0; + + tor_mutex_release(rng_mutex); + + MOCK(crypto_rand, crypto_rand_prefilled); + MOCK(crypto_strongest_rand_, mock_crypto_strongest_rand); +} + +/** + * Reset the position in the prefilled RNG buffer to the start. + */ +void +testing_prefilled_rng_reset(void) +{ + tor_mutex_acquire(rng_mutex); + prefilled_rng_idx = 0; + tor_mutex_release(rng_mutex); +} + +/** + * Undo the overrides for our PRNG. To be used at the end of testing. + * + * Note that this function should be safe to call even if the rng has not + * yet been replaced. + **/ +void +testing_disable_rng_override(void) +{ + crypto_xof_free(rng_xof); + tor_free(prefilled_rng_buffer); + UNMOCK(crypto_rand); + UNMOCK(crypto_strongest_rand_); + tor_mutex_free(rng_mutex); + + crypto_fast_rng_t *rng = crypto_replace_thread_fast_rng(stored_fast_rng); + crypto_fast_rng_free(rng); + + rng_is_replaced = false; +} + +/** + * As testing_disable_rng_override(), but dump the seed if the current + * test has failed. + */ +void +testing_disable_reproducible_rng(void) +{ + if (tinytest_cur_test_has_failed()) { + testing_dump_reproducible_rng_seed(); + } + testing_disable_rng_override(); +} diff --git a/src/test/rng_test_helpers.h b/src/test/rng_test_helpers.h new file mode 100644 index 0000000000..d7925148ae --- /dev/null +++ b/src/test/rng_test_helpers.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2017-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_RNG_TEST_HELPERS_H +#define TOR_RNG_TEST_HELPERS_H + +#include "core/or/or.h" + +void testing_enable_deterministic_rng(void); +void testing_enable_reproducible_rng(void); +void testing_enable_prefilled_rng(const void *buffer, size_t buflen); + +void testing_prefilled_rng_reset(void); + +void testing_disable_rng_override(void); + +void testing_disable_reproducible_rng(void); +#define testing_disable_deterministic_rng() \ + testing_disable_rng_override() +#define testing_disable_prefilled_rng() \ + testing_disable_rng_override() + +void testing_dump_reproducible_rng_seed(void); + +#endif /* !defined(TOR_RNG_TEST_HELPERS_H) */ diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c index 43754ed1c2..3f952e484f 100644 --- a/src/test/test-memwipe.c +++ b/src/test/test-memwipe.c @@ -49,7 +49,7 @@ const char *s = NULL; * us do bad things, such as access freed buffers, without crashing. */ extern const char *malloc_options; const char *malloc_options = "sufjj"; -#endif +#endif /* defined(OpenBSD) */ static unsigned fill_a_buffer_memset(void) diff --git a/src/test/test-network.sh b/src/test/test-network.sh index b7a9f1b3c0..5ef995f1a4 100755 --- a/src/test/test-network.sh +++ b/src/test/test-network.sh @@ -5,7 +5,7 @@ # If we already know CHUTNEY_PATH, don't bother with argument parsing TEST_NETWORK="$CHUTNEY_PATH/tools/test-network.sh" # Call the chutney version of this script, if it exists, and we can find it -if [ -d "$CHUTNEY_PATH" -a -x "$TEST_NETWORK" ]; then +if [ -d "$CHUTNEY_PATH" ] && [ -x "$TEST_NETWORK" ]; then # we can't produce any output, because we might be --quiet # this preserves arguments with spaces correctly exec "$TEST_NETWORK" "$@" @@ -16,34 +16,16 @@ fi # Do we output anything at all? ECHO="${ECHO:-echo}" # Output is prefixed with the name of the script -myname=$(basename $0) - -# Save the arguments before we destroy them -# This might not preserve arguments with spaces in them -ORIGINAL_ARGS="$@" +myname=$(basename "$0") # We need to find CHUTNEY_PATH, so that we can call the version of this script # in chutney/tools with the same arguments. We also need to respect --quiet. -until [ -z "$1" ] -do - case "$1" in - --chutney-path) - CHUTNEY_PATH="$2" - shift - ;; - --tor-path) - TOR_DIR="$2" - shift - ;; - --quiet) - ECHO=true - ;; - *) - # maybe chutney's test-network.sh can handle it - ;; - esac - shift -done +CHUTNEY_PATH=$(echo "$@" | awk -F '--chutney-path ' '{sub(" .*","",$2); print $2}') +TOR_DIR=$(echo "$@" | awk -F '--tor-dir ' '{sub(" .*","",$2); print $2}') + +if echo "$@" | grep -e "--quiet" > /dev/null; then + ECHO=true +fi # optional: $TOR_DIR is the tor build directory # it's used to find the location of tor binaries @@ -52,12 +34,12 @@ done # - if $PWD looks like a tor build directory, set it to $PWD, or # - unset $TOR_DIR, and let chutney fall back to finding tor binaries in $PATH if [ ! -d "$TOR_DIR" ]; then - if [ -d "$BUILDDIR/src/core/or" -a -d "$BUILDDIR/src/tools" ]; then + if [ -d "$BUILDDIR/src/core/or" ] && [ -d "$BUILDDIR/src/tools" ]; then # Choose the build directory # But only if it looks like one $ECHO "$myname: \$TOR_DIR not set, trying \$BUILDDIR" TOR_DIR="$BUILDDIR" - elif [ -d "$PWD/src/core/or" -a -d "$PWD/src/tools" ]; then + elif [ -d "$PWD/src/core/or" ] && [ -d "$PWD/src/tools" ]; then # Guess the tor directory is the current directory # But only if it looks like one $ECHO "$myname: \$TOR_DIR not set, trying \$PWD" @@ -73,12 +55,12 @@ fi # - if $PWD looks like a chutney directory, set it to $PWD, or # - set it based on $TOR_DIR, expecting chutney to be next to tor, or # - fail and tell the user how to clone the chutney repository -if [ ! -d "$CHUTNEY_PATH" -o ! -x "$CHUTNEY_PATH/chutney" ]; then +if [ ! -d "$CHUTNEY_PATH" ] || [ ! -x "$CHUTNEY_PATH/chutney" ]; then if [ -x "$PWD/chutney" ]; then $ECHO "$myname: \$CHUTNEY_PATH not valid, trying \$PWD" CHUTNEY_PATH="$PWD" - elif [ -d "$TOR_DIR" -a -d "$TOR_DIR/../chutney" -a \ - -x "$TOR_DIR/../chutney/chutney" ]; then + elif [ -d "$TOR_DIR" ] && [ -d "$TOR_DIR/../chutney" ] && \ + [ -x "$TOR_DIR/../chutney/chutney" ]; then $ECHO "$myname: \$CHUTNEY_PATH not valid, trying \$TOR_DIR/../chutney" CHUTNEY_PATH="$TOR_DIR/../chutney" else @@ -94,12 +76,12 @@ fi TEST_NETWORK="$CHUTNEY_PATH/tools/test-network.sh" # Call the chutney version of this script, if it exists, and we can find it -if [ -d "$CHUTNEY_PATH" -a -x "$TEST_NETWORK" ]; then +if [ -d "$CHUTNEY_PATH" ] && [ -x "$TEST_NETWORK" ]; then $ECHO "$myname: Calling newer chutney script $TEST_NETWORK" # this may fail if some arguments have spaces in them # if so, set CHUTNEY_PATH before calling test-network.sh, and spaces # will be handled correctly - exec "$TEST_NETWORK" $ORIGINAL_ARGS + exec "$TEST_NETWORK" "$@" else $ECHO "$myname: Could not find tools/test-network.sh in CHUTNEY_PATH." $ECHO "$myname: Please update your chutney using 'git pull'." diff --git a/src/test/test.c b/src/test/test.c index 25e9da5591..cac98dd839 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -12,6 +12,7 @@ #include "lib/crypt_ops/crypto_dh.h" #include "lib/crypt_ops/crypto_rand.h" #include "app/config/or_state_st.h" +#include "test/rng_test_helpers.h" #include #ifdef HAVE_FCNTL_H @@ -283,7 +284,7 @@ test_fast_handshake(void *arg) /* First, test an entire handshake. */ memset(client_handshake, 0, sizeof(client_handshake)); tt_int_op(0, OP_EQ, fast_onionskin_create(&state, client_handshake)); - tt_assert(! tor_mem_is_zero((char*)client_handshake, + tt_assert(! fast_mem_is_zero((char*)client_handshake, sizeof(client_handshake))); tt_int_op(0, OP_EQ, @@ -354,18 +355,6 @@ test_onion_queues(void *arg) tor_free(onionskin); } -static crypto_cipher_t *crypto_rand_aes_cipher = NULL; - -// Mock replacement for crypto_rand: Generates bytes from a provided AES_CTR -// cipher in crypto_rand_aes_cipher. -static void -crypto_rand_deterministic_aes(char *out, size_t n) -{ - tor_assert(crypto_rand_aes_cipher); - memset(out, 0, n); - crypto_cipher_crypt_inplace(crypto_rand_aes_cipher, out, n); -} - static void test_circuit_timeout(void *arg) { @@ -397,8 +386,7 @@ test_circuit_timeout(void *arg) // Use a deterministic RNG here, or else we'll get nondeterministic // coverage in some of the circuitstats functions. - MOCK(crypto_rand, crypto_rand_deterministic_aes); - crypto_rand_aes_cipher = crypto_cipher_new("xyzzyplughplover"); + testing_enable_deterministic_rng(); circuitbuild_running_unit_tests(); #define timeout0 (build_time_t)(30*1000.0) @@ -534,8 +522,8 @@ test_circuit_timeout(void *arg) circuit_build_times_free_timeouts(&final); or_state_free(state); teardown_periodic_events(); - UNMOCK(crypto_rand); - crypto_cipher_free(crypto_rand_aes_cipher); + + testing_disable_deterministic_rng(); } /** Test encoding and parsing of rendezvous service descriptors. */ @@ -857,6 +845,7 @@ struct testgroup_t testgroups[] = { { "consdiff/", consdiff_tests }, { "consdiffmgr/", consdiffmgr_tests }, { "container/", container_tests }, + { "container/namemap/", namemap_tests }, { "control/", controller_tests }, { "control/btrack/", btrack_tests }, { "control/event/", controller_event_tests }, @@ -872,6 +861,7 @@ struct testgroup_t testgroups[] = { { "dir/voting/flags/", voting_flags_tests }, { "dir/voting/schedule/", voting_schedule_tests }, { "dir_handle_get/", dir_handle_get_tests }, + { "dispatch/", dispatch_tests, }, { "dns/", dns_tests }, { "dos/", dos_tests }, { "entryconn/", entryconn_tests }, @@ -909,6 +899,8 @@ struct testgroup_t testgroups[] = { { "proto/misc/", proto_misc_tests }, { "protover/", protover_tests }, { "pt/", pt_tests }, + { "pubsub/build/", pubsub_build_tests }, + { "pubsub/msg/", pubsub_msg_tests }, { "relay/" , relay_tests }, { "relaycell/", relaycell_tests }, { "relaycrypt/", relaycrypt_tests }, @@ -919,6 +911,7 @@ struct testgroup_t testgroups[] = { { "routerlist/", routerlist_tests }, { "routerset/" , routerset_tests }, { "scheduler/", scheduler_tests }, + { "sendme/", sendme_tests }, { "shared-random/", sr_tests }, { "socks/", socks_tests }, { "status/" , status_tests }, diff --git a/src/test/test.h b/src/test/test.h index 2564432985..167fd090ac 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -210,6 +210,7 @@ extern struct testcase_t crypto_rng_tests[]; extern struct testcase_t crypto_tests[]; extern struct testcase_t dir_handle_get_tests[]; extern struct testcase_t dir_tests[]; +extern struct testcase_t dispatch_tests[]; extern struct testcase_t dns_tests[]; extern struct testcase_t dos_tests[]; extern struct testcase_t entryconn_tests[]; @@ -235,6 +236,7 @@ extern struct testcase_t link_handshake_tests[]; extern struct testcase_t logging_tests[]; extern struct testcase_t mainloop_tests[]; extern struct testcase_t microdesc_tests[]; +extern struct testcase_t namemap_tests[]; extern struct testcase_t netinfo_tests[]; extern struct testcase_t nodelist_tests[]; extern struct testcase_t oom_tests[]; @@ -252,6 +254,8 @@ extern struct testcase_t proto_http_tests[]; extern struct testcase_t proto_misc_tests[]; extern struct testcase_t protover_tests[]; extern struct testcase_t pt_tests[]; +extern struct testcase_t pubsub_build_tests[]; +extern struct testcase_t pubsub_msg_tests[]; extern struct testcase_t relay_tests[]; extern struct testcase_t relaycell_tests[]; extern struct testcase_t relaycrypt_tests[]; @@ -262,6 +266,7 @@ extern struct testcase_t routerkeys_tests[]; extern struct testcase_t routerlist_tests[]; extern struct testcase_t routerset_tests[]; extern struct testcase_t scheduler_tests[]; +extern struct testcase_t sendme_tests[]; extern struct testcase_t socks_tests[]; extern struct testcase_t sr_tests[]; extern struct testcase_t status_tests[]; @@ -278,6 +283,7 @@ extern struct testcase_t x509_tests[]; extern struct testcase_t slow_crypto_tests[]; extern struct testcase_t slow_process_tests[]; +extern struct testcase_t slow_ptr_tests[]; extern struct testgroup_t testgroups[]; diff --git a/src/test/test_addr.c b/src/test/test_addr.c index fb8df5f0fb..05d8bf6c7b 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -11,6 +11,7 @@ #include "feature/client/addressmap.h" #include "test/log_test_helpers.h" #include "lib/net/resolve.h" +#include "test/rng_test_helpers.h" #ifdef HAVE_SYS_UN_H #include @@ -239,7 +240,7 @@ test_addr_ip6_helpers(void *arg) tt_int_op(0,OP_EQ, tor_addr_lookup("9000::5", AF_UNSPEC, &t1)); tt_int_op(AF_INET6,OP_EQ, tor_addr_family(&t1)); tt_int_op(0x90,OP_EQ, tor_addr_to_in6_addr8(&t1)[0]); - tt_assert(tor_mem_is_zero((char*)tor_addr_to_in6_addr8(&t1)+1, 14)); + tt_assert(fast_mem_is_zero((char*)tor_addr_to_in6_addr8(&t1)+1, 14)); tt_int_op(0x05,OP_EQ, tor_addr_to_in6_addr8(&t1)[15]); /* === Test pton: valid af_inet6 */ @@ -696,7 +697,7 @@ test_addr_ip6_helpers(void *arg) &t1,&mask,&port1,&port2); tt_int_op(r,OP_EQ,AF_INET6); tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET6); - tt_assert(tor_mem_is_zero((const char*)tor_addr_to_in6_addr32(&t1), 16)); + tt_assert(fast_mem_is_zero((const char*)tor_addr_to_in6_addr32(&t1), 16)); tt_int_op(mask,OP_EQ,0); tt_int_op(port1,OP_EQ,1); tt_int_op(port2,OP_EQ,65535); @@ -945,27 +946,6 @@ test_virtaddrmap(void *data) ; } -static const char *canned_data = NULL; -static size_t canned_data_len = 0; - -/* Mock replacement for crypto_rand() that returns canned data from - * canned_data above. */ -static void -crypto_canned(char *ptr, size_t n) -{ - if (canned_data_len) { - size_t to_copy = MIN(n, canned_data_len); - memcpy(ptr, canned_data, to_copy); - canned_data += to_copy; - canned_data_len -= to_copy; - n -= to_copy; - ptr += to_copy; - } - if (n) { - crypto_rand_unmocked(ptr, n); - } -} - static void test_virtaddrmap_persist(void *data) { @@ -973,6 +953,8 @@ test_virtaddrmap_persist(void *data) const char *a, *b, *c; tor_addr_t addr; char *ones = NULL; + const char *canned_data; + size_t canned_data_len; addressmap_init(); @@ -991,7 +973,7 @@ test_virtaddrmap_persist(void *data) "1234567890" // the second call returns this. "abcdefghij"; // the third call returns this. canned_data_len = 30; - MOCK(crypto_rand, crypto_canned); + testing_enable_prefilled_rng(canned_data, canned_data_len); a = addressmap_register_virtual_address(RESOLVED_TYPE_HOSTNAME, tor_strdup("quuxit.baz")); @@ -1001,9 +983,9 @@ test_virtaddrmap_persist(void *data) tt_assert(b); tt_str_op(a, OP_EQ, "gezdgnbvgy3tqojq.virtual"); tt_str_op(b, OP_EQ, "mfrggzdfmztwq2lk.virtual"); + testing_disable_prefilled_rng(); // Now try something to get us an ipv4 address - UNMOCK(crypto_rand); tt_int_op(0,OP_EQ, parse_virtual_addr_network("192.168.0.0/16", AF_INET, 0, NULL)); a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4, @@ -1020,22 +1002,23 @@ test_virtaddrmap_persist(void *data) // Try some canned entropy and verify all the we discard duplicates, // addresses that end with 0, and addresses that end with 255. - MOCK(crypto_rand, crypto_canned); canned_data = "\x01\x02\x03\x04" // okay "\x01\x02\x03\x04" // duplicate "\x03\x04\x00\x00" // bad ending 1 "\x05\x05\x00\xff" // bad ending 2 "\x05\x06\x07\xf0"; // okay canned_data_len = 20; + testing_enable_prefilled_rng(canned_data, canned_data_len); + a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4, tor_strdup("wumble.onion")); b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4, tor_strdup("wumpus.onion")); tt_str_op(a, OP_EQ, "192.168.3.4"); tt_str_op(b, OP_EQ, "192.168.7.240"); + testing_disable_prefilled_rng(); // Now try IPv6! - UNMOCK(crypto_rand); tt_int_op(0,OP_EQ, parse_virtual_addr_network("1010:F000::/20", AF_INET6, 0, NULL)); a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6, @@ -1051,7 +1034,7 @@ test_virtaddrmap_persist(void *data) tt_assert(!strcmpstart(b, "[1010:f")); // Try IPv6 with canned entropy, to make sure we detect duplicates. - MOCK(crypto_rand, crypto_canned); + canned_data = "acanthopterygian" // okay "cinematographist" // okay "acanthopterygian" // duplicate @@ -1060,6 +1043,8 @@ test_virtaddrmap_persist(void *data) "cinematographist" // duplicate "coadministration"; // okay canned_data_len = 16 * 7; + testing_enable_prefilled_rng(canned_data, canned_data_len); + a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6, tor_strdup("wuffle.baz")); b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6, @@ -1072,9 +1057,11 @@ test_virtaddrmap_persist(void *data) // Try address exhaustion: make sure we can actually fail if we // get too many already-existing addresses. + testing_disable_prefilled_rng(); canned_data_len = 128*1024; canned_data = ones = tor_malloc(canned_data_len); memset(ones, 1, canned_data_len); + testing_enable_prefilled_rng(canned_data, canned_data_len); // There is some chance this one will fail if a previous random // allocation gave out the address already. a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4, @@ -1091,7 +1078,7 @@ test_virtaddrmap_persist(void *data) expect_single_log_msg_containing("Ran out of virtual addresses!"); done: - UNMOCK(crypto_rand); + testing_disable_prefilled_rng(); tor_free(ones); addressmap_free_all(); teardown_capture_of_logs(); diff --git a/src/test/test_bt.sh b/src/test/test_bt.sh index df8bcb8eda..312905a4e2 100755 --- a/src/test/test_bt.sh +++ b/src/test/test_bt.sh @@ -3,8 +3,6 @@ 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_bt_cl.c b/src/test/test_bt_cl.c index 0c15a02ee4..b29c2c6cbc 100644 --- a/src/test/test_bt_cl.c +++ b/src/test/test_bt_cl.c @@ -4,6 +4,9 @@ #include "orconfig.h" #include #include +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif /* To prevent 'assert' from going away. */ #undef TOR_COVERAGE @@ -43,7 +46,7 @@ crash(int x) *(volatile int *)0 = 0; #endif /* defined(__clang_analyzer__) || defined(__COVERITY__) */ } else if (crashtype == 1) { - tor_assert(1 == 0); + tor_assertf(1 == 0, "%d != %d", 1, 0); } else if (crashtype == -1) { ; } @@ -88,6 +91,11 @@ main(int argc, char **argv) return 1; } +#ifdef HAVE_SYS_RESOURCE_H + struct rlimit rlim = { .rlim_cur = 0, .rlim_max = 0 }; + setrlimit(RLIMIT_CORE, &rlim); +#endif + #if !(defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)) puts("Backtrace reporting is not supported on this platform"); diff --git a/src/test/test_channel.c b/src/test/test_channel.c index e55b9b0750..6a6bc9d810 100644 --- a/src/test/test_channel.c +++ b/src/test/test_channel.c @@ -598,7 +598,6 @@ test_channel_outbound_cell(void *arg) circuit_set_n_circid_chan(TO_CIRCUIT(circ), 42, chan); tt_int_op(channel_num_circuits(chan), OP_EQ, 1); /* Test the cmux state. */ - tt_ptr_op(TO_CIRCUIT(circ)->n_mux, OP_EQ, chan->cmux); tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)), OP_EQ, 1); @@ -1541,6 +1540,10 @@ test_channel_listener(void *arg) channel_listener_dump_statistics(chan, LOG_INFO); done: + if (chan) { + channel_listener_unregister(chan); + tor_free(chan); + } channel_free_all(); } @@ -1567,4 +1570,3 @@ struct testcase_t channel_tests[] = { NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c index 27f2cd1ca5..0c23091594 100644 --- a/src/test/test_circuitbuild.c +++ b/src/test/test_circuitbuild.c @@ -4,6 +4,8 @@ /* See LICENSE for licensing information */ #define CIRCUITBUILD_PRIVATE +#define CIRCUITLIST_PRIVATE +#define ENTRYNODES_PRIVATE #include "core/or/or.h" #include "test/test.h" @@ -13,7 +15,11 @@ #include "core/or/circuitbuild.h" #include "core/or/circuitlist.h" +#include "core/or/cpath_build_state_st.h" #include "core/or/extend_info_st.h" +#include "core/or/origin_circuit_st.h" + +#include "feature/client/entrynodes.h" /* Dummy nodes smartlist for testing */ static smartlist_t dummy_nodes; @@ -21,7 +27,7 @@ static smartlist_t dummy_nodes; static extend_info_t dummy_ei; static int -mock_count_acceptable_nodes(smartlist_t *nodes, int direct) +mock_count_acceptable_nodes(const smartlist_t *nodes, int direct) { (void)nodes; @@ -126,10 +132,51 @@ test_new_route_len_unhandled_exit(void *arg) UNMOCK(count_acceptable_nodes); } +static void +test_upgrade_from_guard_wait(void *arg) +{ + circuit_t *circ = NULL; + origin_circuit_t *orig_circ = NULL; + entry_guard_t *guard = NULL; + smartlist_t *list = NULL; + + (void) arg; + + circ = dummy_origin_circuit_new(0); + orig_circ = TO_ORIGIN_CIRCUIT(circ); + tt_assert(orig_circ); + + orig_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); + + circuit_set_state(circ, CIRCUIT_STATE_GUARD_WAIT); + + /* Put it in guard wait state. */ + guard = tor_malloc_zero(sizeof(*guard)); + guard->in_selection = get_guard_selection_info(); + + orig_circ->guard_state = + circuit_guard_state_new(guard, GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD, + NULL); + + /* Mark the circuit for close. */ + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + tt_int_op(circ->marked_for_close, OP_NE, 0); + + /* We shouldn't pick the mark for close circuit. */ + list = circuit_find_circuits_to_upgrade_from_guard_wait(); + tt_assert(!list); + + done: + circuit_free(circ); + entry_guard_free_(guard); +} + struct testcase_t circuitbuild_tests[] = { { "noexit", test_new_route_len_noexit, 0, NULL, NULL }, { "safe_exit", test_new_route_len_safe_exit, 0, NULL, NULL }, { "unsafe_exit", test_new_route_len_unsafe_exit, 0, NULL, NULL }, { "unhandled_exit", test_new_route_len_unhandled_exit, 0, NULL, NULL }, + { "upgrade_from_guard_wait", test_upgrade_from_guard_wait, TT_FORK, + NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c index 09a4c9a0ca..25f8fd311b 100644 --- a/src/test/test_circuitpadding.c +++ b/src/test/test_circuitpadding.c @@ -1,14 +1,17 @@ #define TOR_CHANNEL_INTERNAL_ #define TOR_TIMERS_PRIVATE #define CIRCUITPADDING_PRIVATE +#define CIRCUITPADDING_MACHINES_PRIVATE #define NETWORKSTATUS_PRIVATE +#define CRYPT_PATH_PRIVATE #include "core/or/or.h" -#include "test.h" +#include "test/test.h" #include "lib/testsupport/testsupport.h" #include "core/or/connection_or.h" #include "core/or/channel.h" #include "core/or/channeltls.h" +#include "core/or/crypt_path.h" #include #include "lib/evloop/compat_libevent.h" #include "lib/time/compat_time.h" @@ -17,6 +20,8 @@ #include "core/or/circuitlist.h" #include "core/or/circuitbuild.h" #include "core/or/circuitpadding.h" +#include "core/or/circuitpadding_machines.h" +#include "core/mainloop/netstatus.h" #include "core/crypto/relay_crypto.h" #include "core/or/protover.h" #include "feature/nodelist/nodelist.h" @@ -31,6 +36,8 @@ #include "core/or/or_circuit_st.h" #include "core/or/origin_circuit_st.h" +#include "test/rng_test_helpers.h" + /* Start our monotime mocking at 1 second past whatever monotime_init() * thought the actual wall clock time was, for platforms with bad resolution * and weird timevalues during monotime_init() before mocking. */ @@ -38,6 +45,7 @@ TOR_NSEC_PER_USEC*TOR_USEC_PER_SEC) extern smartlist_t *connection_array; +void circuit_expire_old_circuits_clientside(void); circid_t get_unique_circ_id_by_chan(channel_t *chan); void helper_create_basic_machine(void); @@ -52,6 +60,7 @@ void test_circuitpadding_conditions(void *arg); void test_circuitpadding_serialize(void *arg); void test_circuitpadding_rtt(void *arg); void test_circuitpadding_tokens(void *arg); +void test_circuitpadding_state_length(void *arg); static void simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay, @@ -81,10 +90,10 @@ static void nodes_init(void) { padding_node.rs = tor_malloc_zero(sizeof(routerstatus_t)); - padding_node.rs->pv.supports_padding = 1; + padding_node.rs->pv.supports_hs_setup_padding = 1; non_padding_node.rs = tor_malloc_zero(sizeof(routerstatus_t)); - non_padding_node.rs->pv.supports_padding = 0; + non_padding_node.rs->pv.supports_hs_setup_padding = 0; } static void @@ -107,6 +116,15 @@ node_get_by_id_mock(const char *identity_digest) return NULL; } +static const node_t * +circuit_get_nth_node_mock(origin_circuit_t *circ, int hop) +{ + (void) circ; + (void) hop; + + return &padding_node; +} + static or_circuit_t * new_fake_orcirc(channel_t *nchan, channel_t *pchan) { @@ -121,7 +139,6 @@ new_fake_orcirc(channel_t *nchan, channel_t *pchan) //circ->n_chan = nchan; circ->n_circ_id = get_unique_circ_id_by_chan(nchan); - circ->n_mux = NULL; /* ?? */ cell_queue_init(&(circ->n_chan_cells)); circ->n_hop = NULL; circ->streams_blocked_on_n_chan = 0; @@ -143,12 +160,12 @@ new_fake_orcirc(channel_t *nchan, channel_t *pchan) circuit_set_n_circid_chan(circ, circ->n_circ_id, nchan); memset(&tmp_cpath, 0, sizeof(tmp_cpath)); - if (circuit_init_cpath_crypto(&tmp_cpath, whatevs_key, + if (cpath_init_circuit_crypto(&tmp_cpath, whatevs_key, sizeof(whatevs_key), 0, 0)<0) { log_warn(LD_BUG,"Circuit initialization failed"); return NULL; } - orcirc->crypto = tmp_cpath.crypto; + orcirc->crypto = tmp_cpath.pvt_crypto; return orcirc; } @@ -298,6 +315,7 @@ test_circuitpadding_rtt(void *arg) MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock); + testing_enable_reproducible_rng(); dummy_channel.cmux = circuitmux_alloc(); relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel)); @@ -327,12 +345,12 @@ test_circuitpadding_rtt(void *arg) relay_side->padding_info[0] = circpad_circuit_machineinfo_new(client_side,0); /* Test 1: Test measuring RTT */ - circpad_cell_event_nonpadding_received((circuit_t*)relay_side); + circpad_cell_event_nonpadding_received(relay_side); tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_NE, 0); timers_advance_and_run(20); - circpad_cell_event_nonpadding_sent((circuit_t*)relay_side); + circpad_cell_event_nonpadding_sent(relay_side); tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_GE, 19000); @@ -341,14 +359,14 @@ test_circuitpadding_rtt(void *arg) OP_EQ, relay_side->padding_info[0]->rtt_estimate_usec+ circpad_machine_current_state( - relay_side->padding_info[0])->start_usec); + relay_side->padding_info[0])->histogram_edges[0]); - circpad_cell_event_nonpadding_received((circuit_t*)relay_side); - circpad_cell_event_nonpadding_received((circuit_t*)relay_side); + circpad_cell_event_nonpadding_received(relay_side); + circpad_cell_event_nonpadding_received(relay_side); tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_NE, 0); timers_advance_and_run(20); - circpad_cell_event_nonpadding_sent((circuit_t*)relay_side); - circpad_cell_event_nonpadding_sent((circuit_t*)relay_side); + circpad_cell_event_nonpadding_sent(relay_side); + circpad_cell_event_nonpadding_sent(relay_side); tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_GE, 20000); @@ -357,15 +375,15 @@ test_circuitpadding_rtt(void *arg) OP_EQ, relay_side->padding_info[0]->rtt_estimate_usec+ circpad_machine_current_state( - relay_side->padding_info[0])->start_usec); + relay_side->padding_info[0])->histogram_edges[0]); /* Test 2: Termination of RTT measurement (from the previous test) */ tt_int_op(relay_side->padding_info[0]->stop_rtt_update, OP_EQ, 1); rtt_estimate = relay_side->padding_info[0]->rtt_estimate_usec; - circpad_cell_event_nonpadding_received((circuit_t*)relay_side); + circpad_cell_event_nonpadding_received(relay_side); timers_advance_and_run(4); - circpad_cell_event_nonpadding_sent((circuit_t*)relay_side); + circpad_cell_event_nonpadding_sent(relay_side); tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_EQ, rtt_estimate); @@ -375,14 +393,14 @@ test_circuitpadding_rtt(void *arg) OP_EQ, relay_side->padding_info[0]->rtt_estimate_usec+ circpad_machine_current_state( - relay_side->padding_info[0])->start_usec); + relay_side->padding_info[0])->histogram_edges[0]); /* Test 3: Make sure client side machine properly ignores RTT */ - circpad_cell_event_nonpadding_received((circuit_t*)client_side); + circpad_cell_event_nonpadding_received(client_side); tt_u64_op(client_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); timers_advance_and_run(20); - circpad_cell_event_nonpadding_sent((circuit_t*)client_side); + circpad_cell_event_nonpadding_sent(client_side); tt_u64_op(client_side->padding_info[0]->last_received_time_usec, OP_EQ, 0); tt_int_op(client_side->padding_info[0]->rtt_estimate_usec, OP_EQ, 0); @@ -391,7 +409,7 @@ test_circuitpadding_rtt(void *arg) tt_int_op(circpad_histogram_bin_to_usec(client_side->padding_info[0], 0), OP_EQ, circpad_machine_current_state( - client_side->padding_info[0])->start_usec); + client_side->padding_info[0])->histogram_edges[0]); done: free_fake_orcirc(relay_side); circuitmux_detach_all_circuits(dummy_channel.cmux, NULL); @@ -401,6 +419,7 @@ test_circuitpadding_rtt(void *arg) UNMOCK(circuit_package_relay_cell); UNMOCK(circuitmux_attach_circuit); tor_free(circ_client_machine.states); + testing_disable_reproducible_rng(); return; } @@ -411,8 +430,11 @@ helper_create_basic_machine(void) /* Start, burst */ circpad_machine_states_init(&circ_client_machine, 2); + circ_client_machine.name = "basic"; + circ_client_machine.states[CIRCPAD_STATE_START]. next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_BURST; + circ_client_machine.states[CIRCPAD_STATE_START].use_rtt_estimate = 1; circ_client_machine.states[CIRCPAD_STATE_BURST]. next_state[CIRCPAD_EVENT_PADDING_RECV] = CIRCPAD_STATE_BURST; @@ -422,19 +444,23 @@ helper_create_basic_machine(void) circ_client_machine.states[CIRCPAD_STATE_BURST]. next_state[CIRCPAD_EVENT_NONPADDING_SENT] = CIRCPAD_STATE_CANCEL; - // FIXME: Is this what we want? circ_client_machine.states[CIRCPAD_STATE_BURST].token_removal = CIRCPAD_TOKEN_REMOVAL_HIGHER; - // FIXME: Tune this histogram circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_len = 5; - circ_client_machine.states[CIRCPAD_STATE_BURST].start_usec = 500; - circ_client_machine.states[CIRCPAD_STATE_BURST].range_usec = 1000000; + + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 500; + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[1] = 2500; + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[2] = 5000; + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[3] = 10000; + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[4] = 20000; + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[0] = 1; circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[1] = 0; circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[2] = 2; circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[3] = 2; circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[4] = 2; + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_total_tokens = 7; circ_client_machine.states[CIRCPAD_STATE_BURST].use_rtt_estimate = 1; @@ -466,15 +492,25 @@ helper_create_machine_with_big_histogram(circpad_removal_t removal_strategy) burst_state->token_removal = CIRCPAD_TOKEN_REMOVAL_HIGHER; burst_state->histogram_len = BIG_HISTOGRAM_LEN; - burst_state->start_usec = 0; - burst_state->range_usec = 1000; int n_tokens = 0; - for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) { + int i; + for (i = 0; i < BIG_HISTOGRAM_LEN ; i++) { burst_state->histogram[i] = tokens_per_bin; n_tokens += tokens_per_bin; } + burst_state->histogram_edges[0] = 0; + burst_state->histogram_edges[1] = 1; + burst_state->histogram_edges[2] = 7; + burst_state->histogram_edges[3] = 15; + burst_state->histogram_edges[4] = 31; + burst_state->histogram_edges[5] = 62; + burst_state->histogram_edges[6] = 125; + burst_state->histogram_edges[7] = 250; + burst_state->histogram_edges[8] = 500; + burst_state->histogram_edges[9] = 1000; + burst_state->histogram_total_tokens = n_tokens; burst_state->length_dist.type = CIRCPAD_DIST_UNIFORM; burst_state->length_dist.param1 = n_tokens; @@ -486,7 +522,7 @@ helper_create_machine_with_big_histogram(circpad_removal_t removal_strategy) } static circpad_decision_t -circpad_machine_schedule_padding_mock(circpad_machine_state_t *mi) +circpad_machine_schedule_padding_mock(circpad_machine_runtime_t *mi) { (void)mi; return 0; @@ -502,15 +538,16 @@ mock_monotime_absolute_usec(void) static void test_circuitpadding_token_removal_higher(void *arg) { - circpad_machine_state_t *mi; + circpad_machine_runtime_t *mi; (void)arg; /* Mock it up */ MOCK(monotime_absolute_usec, mock_monotime_absolute_usec); MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); + testing_enable_reproducible_rng(); /* Setup test environment (time etc.) */ - client_side = (circuit_t *)origin_circuit_new(); + client_side = TO_CIRCUIT(origin_circuit_new()); client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; monotime_enable_test_mocking(); @@ -521,7 +558,7 @@ test_circuitpadding_token_removal_higher(void *arg) circpad_circuit_machineinfo_new(client_side, 0); /* move the machine to the right state */ - circpad_cell_event_nonpadding_received((circuit_t*)client_side); + circpad_cell_event_nonpadding_received(client_side); tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_BURST); @@ -535,12 +572,20 @@ test_circuitpadding_token_removal_higher(void *arg) /* Test left boundaries of each histogram bin: */ const circpad_delay_t bin_left_bounds[] = - {0, 1, 7, 15, 31, 62, 125, 250, 500, CIRCPAD_DELAY_INFINITE}; - for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) { + {0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE}; + for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) { tt_uint_op(bin_left_bounds[i], OP_EQ, circpad_histogram_bin_to_usec(mi, i)); } + /* Test right boundaries of each histogram bin: */ + const circpad_delay_t bin_right_bounds[] = + {0, 6, 14, 30, 61, 124, 249, 499, 999, CIRCPAD_DELAY_INFINITE-1}; + for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) { + tt_uint_op(bin_right_bounds[i], OP_EQ, + histogram_get_bin_upper_bound(mi, i)); + } + /* Check that all bins have two tokens right now */ for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) { tt_int_op(mi->histogram[i], OP_EQ, 2); @@ -562,12 +607,12 @@ test_circuitpadding_token_removal_higher(void *arg) tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2); mi->padding_scheduled_at_usec = current_time - 57; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1); mi->padding_scheduled_at_usec = current_time - 57; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); /* Test that we cleaned out this bin. Don't do this in the case of the last bin since the tokens will get refilled */ @@ -584,30 +629,32 @@ test_circuitpadding_token_removal_higher(void *arg) /* Test below the lowest bin, for coverage */ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_BURST); - circ_client_machine.states[CIRCPAD_STATE_BURST].start_usec = 100; - mi->padding_scheduled_at_usec = current_time - 1; - circpad_machine_remove_token(mi); + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 100; + mi->padding_scheduled_at_usec = current_time; + circpad_cell_event_nonpadding_sent(client_side); tt_int_op(mi->histogram[0], OP_EQ, 1); done: free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); monotime_disable_test_mocking(); tor_free(circ_client_machine.states); + testing_disable_reproducible_rng(); } /** Test lower token removal strategy by bin */ static void test_circuitpadding_token_removal_lower(void *arg) { - circpad_machine_state_t *mi; + circpad_machine_runtime_t *mi; (void)arg; /* Mock it up */ MOCK(monotime_absolute_usec, mock_monotime_absolute_usec); MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); + testing_enable_reproducible_rng(); /* Setup test environment (time etc.) */ - client_side = (circuit_t *)origin_circuit_new(); + client_side = TO_CIRCUIT(origin_circuit_new()); client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; monotime_enable_test_mocking(); @@ -618,7 +665,7 @@ test_circuitpadding_token_removal_lower(void *arg) circpad_circuit_machineinfo_new(client_side, 0); /* move the machine to the right state */ - circpad_cell_event_nonpadding_received((circuit_t*)client_side); + circpad_cell_event_nonpadding_received(client_side); tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_BURST); @@ -632,8 +679,8 @@ test_circuitpadding_token_removal_lower(void *arg) /* Test left boundaries of each histogram bin: */ const circpad_delay_t bin_left_bounds[] = - {0, 1, 7, 15, 31, 62, 125, 250, 500, CIRCPAD_DELAY_INFINITE}; - for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) { + {0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE}; + for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) { tt_uint_op(bin_left_bounds[i], OP_EQ, circpad_histogram_bin_to_usec(mi, i)); } @@ -659,12 +706,12 @@ test_circuitpadding_token_removal_lower(void *arg) tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2); mi->padding_scheduled_at_usec = current_time - 57; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1); mi->padding_scheduled_at_usec = current_time - 57; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); /* Test that we cleaned out this bin. Don't do this in the case of the last bin since the tokens will get refilled */ @@ -681,30 +728,33 @@ test_circuitpadding_token_removal_lower(void *arg) /* Test above the highest bin, for coverage */ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_BURST); - circ_client_machine.states[CIRCPAD_STATE_BURST].start_usec = 100; + circ_client_machine.states[CIRCPAD_STATE_BURST]. + histogram_edges[BIG_HISTOGRAM_LEN-2] = 100; mi->padding_scheduled_at_usec = current_time - 29202; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); tt_int_op(mi->histogram[BIG_HISTOGRAM_LEN-2], OP_EQ, 1); done: free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); monotime_disable_test_mocking(); tor_free(circ_client_machine.states); + testing_disable_reproducible_rng(); } /** Test closest token removal strategy by bin */ static void test_circuitpadding_closest_token_removal(void *arg) { - circpad_machine_state_t *mi; + circpad_machine_runtime_t *mi; (void)arg; /* Mock it up */ MOCK(monotime_absolute_usec, mock_monotime_absolute_usec); MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); + testing_enable_reproducible_rng(); /* Setup test environment (time etc.) */ - client_side = (circuit_t *)origin_circuit_new(); + client_side = TO_CIRCUIT(origin_circuit_new()); client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; monotime_enable_test_mocking(); @@ -715,7 +765,7 @@ test_circuitpadding_closest_token_removal(void *arg) circpad_circuit_machineinfo_new(client_side, 0); /* move the machine to the right state */ - circpad_cell_event_nonpadding_received((circuit_t*)client_side); + circpad_cell_event_nonpadding_received(client_side); tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_BURST); @@ -729,8 +779,8 @@ test_circuitpadding_closest_token_removal(void *arg) /* Test left boundaries of each histogram bin: */ const circpad_delay_t bin_left_bounds[] = - {0, 1, 7, 15, 31, 62, 125, 250, 500, CIRCPAD_DELAY_INFINITE}; - for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) { + {0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE}; + for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) { tt_uint_op(bin_left_bounds[i], OP_EQ, circpad_histogram_bin_to_usec(mi, i)); } @@ -755,12 +805,12 @@ test_circuitpadding_closest_token_removal(void *arg) tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2); mi->padding_scheduled_at_usec = current_time - 57; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1); mi->padding_scheduled_at_usec = current_time - 57; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); /* Test that we cleaned out this bin. Don't do this in the case of the last bin since the tokens will get refilled */ @@ -777,39 +827,42 @@ test_circuitpadding_closest_token_removal(void *arg) /* Test below the lowest bin, for coverage */ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_BURST); - circ_client_machine.states[CIRCPAD_STATE_BURST].start_usec = 100; + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 100; + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[1] = 101; + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[2] = 120; mi->padding_scheduled_at_usec = current_time - 102; mi->histogram[0] = 0; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); tt_int_op(mi->histogram[1], OP_EQ, 1); /* Test above the highest bin, for coverage */ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_BURST); - circ_client_machine.states[CIRCPAD_STATE_BURST].start_usec = 100; mi->padding_scheduled_at_usec = current_time - 29202; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); tt_int_op(mi->histogram[BIG_HISTOGRAM_LEN-2], OP_EQ, 1); done: free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); monotime_disable_test_mocking(); tor_free(circ_client_machine.states); + testing_disable_reproducible_rng(); } /** Test closest token removal strategy with usec */ static void test_circuitpadding_closest_token_removal_usec(void *arg) { - circpad_machine_state_t *mi; + circpad_machine_runtime_t *mi; (void)arg; /* Mock it up */ MOCK(monotime_absolute_usec, mock_monotime_absolute_usec); MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); + testing_enable_reproducible_rng(); /* Setup test environment (time etc.) */ - client_side = (circuit_t *)origin_circuit_new(); + client_side = TO_CIRCUIT(origin_circuit_new()); client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; monotime_enable_test_mocking(); @@ -820,7 +873,7 @@ test_circuitpadding_closest_token_removal_usec(void *arg) circpad_circuit_machineinfo_new(client_side, 0); /* move the machine to the right state */ - circpad_cell_event_nonpadding_received((circuit_t*)client_side); + circpad_cell_event_nonpadding_received(client_side); tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_BURST); @@ -834,8 +887,8 @@ test_circuitpadding_closest_token_removal_usec(void *arg) /* Test left boundaries of each histogram bin: */ const circpad_delay_t bin_left_bounds[] = - {0, 1, 7, 15, 31, 62, 125, 250, 500, CIRCPAD_DELAY_INFINITE}; - for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) { + {0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE}; + for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) { tt_uint_op(bin_left_bounds[i], OP_EQ, circpad_histogram_bin_to_usec(mi, i)); } @@ -863,12 +916,12 @@ test_circuitpadding_closest_token_removal_usec(void *arg) tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2); mi->padding_scheduled_at_usec = current_time - 57; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1); mi->padding_scheduled_at_usec = current_time - 57; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); /* Test that we cleaned out this bin. Don't do this in the case of the last bin since the tokens will get refilled */ @@ -885,39 +938,44 @@ test_circuitpadding_closest_token_removal_usec(void *arg) /* Test below the lowest bin, for coverage */ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_BURST); - circ_client_machine.states[CIRCPAD_STATE_BURST].start_usec = 100; + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 100; + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[1] = 101; + circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[2] = 120; mi->padding_scheduled_at_usec = current_time - 102; mi->histogram[0] = 0; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); tt_int_op(mi->histogram[1], OP_EQ, 1); /* Test above the highest bin, for coverage */ tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_BURST); - circ_client_machine.states[CIRCPAD_STATE_BURST].start_usec = 100; + circ_client_machine.states[CIRCPAD_STATE_BURST]. + histogram_edges[BIG_HISTOGRAM_LEN-2] = 100; mi->padding_scheduled_at_usec = current_time - 29202; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); tt_int_op(mi->histogram[BIG_HISTOGRAM_LEN-2], OP_EQ, 1); done: free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); monotime_disable_test_mocking(); tor_free(circ_client_machine.states); + testing_disable_reproducible_rng(); } /** Test closest token removal strategy with usec */ static void test_circuitpadding_token_removal_exact(void *arg) { - circpad_machine_state_t *mi; + circpad_machine_runtime_t *mi; (void)arg; /* Mock it up */ MOCK(monotime_absolute_usec, mock_monotime_absolute_usec); MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); + testing_enable_reproducible_rng(); /* Setup test environment (time etc.) */ - client_side = (circuit_t *)origin_circuit_new(); + client_side = TO_CIRCUIT(origin_circuit_new()); client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; monotime_enable_test_mocking(); @@ -928,7 +986,7 @@ test_circuitpadding_token_removal_exact(void *arg) circpad_circuit_machineinfo_new(client_side, 0); /* move the machine to the right state */ - circpad_cell_event_nonpadding_received((circuit_t*)client_side); + circpad_cell_event_nonpadding_received(client_side); tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, CIRCPAD_STATE_BURST); @@ -942,16 +1000,16 @@ test_circuitpadding_token_removal_exact(void *arg) /* Ensure that we will clear out bin #4 with this usec */ mi->padding_scheduled_at_usec = current_time - 57; tt_int_op(mi->histogram[4], OP_EQ, 2); - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); mi->padding_scheduled_at_usec = current_time - 57; tt_int_op(mi->histogram[4], OP_EQ, 1); - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); tt_int_op(mi->histogram[4], OP_EQ, 0); /* Ensure that we will not remove any other tokens even tho we try to, since * this is what the exact strategy dictates */ mi->padding_scheduled_at_usec = current_time - 57; - circpad_machine_remove_token(mi); + circpad_cell_event_nonpadding_sent(client_side); for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) { if (i != 4) { tt_int_op(mi->histogram[i], OP_EQ, 2); @@ -962,6 +1020,7 @@ test_circuitpadding_token_removal_exact(void *arg) free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); monotime_disable_test_mocking(); tor_free(circ_client_machine.states); + testing_disable_reproducible_rng(); } #undef BIG_HISTOGRAM_LEN @@ -970,10 +1029,12 @@ void test_circuitpadding_tokens(void *arg) { const circpad_state_t *state; - circpad_machine_state_t *mi; + circpad_machine_runtime_t *mi; int64_t actual_mocked_monotime_start; (void)arg; + testing_enable_reproducible_rng(); + /** Test plan: * * 1. Test symmetry between bin_to_usec and usec_to_bin @@ -1004,6 +1065,9 @@ test_circuitpadding_tokens(void *arg) monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start); curr_mocked_time = actual_mocked_monotime_start; + /* This is needed so that we are not considered to be dormant */ + note_user_activity(20); + timers_initialize(); helper_create_basic_machine(); @@ -1014,8 +1078,8 @@ test_circuitpadding_tokens(void *arg) mi = client_side->padding_info[0]; // Pretend a non-padding cell was sent - circpad_cell_event_nonpadding_received((circuit_t*)client_side); - circpad_cell_event_nonpadding_sent((circuit_t*)client_side); + circpad_cell_event_nonpadding_received(client_side); + circpad_cell_event_nonpadding_sent(client_side); /* We have to save the infinity bin because one inf delay * could have been chosen when we transition to burst */ circpad_hist_token_t inf_bin = mi->histogram[4]; @@ -1052,7 +1116,7 @@ test_circuitpadding_tokens(void *arg) // Test 1: converting usec->bin->usec->bin // Bin 0+1 have different semantics. - for (circpad_delay_t i = 0; i <= state->start_usec+1; i++) { + for (circpad_delay_t i = 0; i <= state->histogram_edges[0]; i++) { int bin = circpad_histogram_usec_to_bin(client_side->padding_info[0], i); circpad_delay_t usec = @@ -1062,8 +1126,9 @@ test_circuitpadding_tokens(void *arg) tt_int_op(bin, OP_EQ, bin2); tt_int_op(i, OP_LE, usec); } - for (circpad_delay_t i = state->start_usec+1; - i <= state->start_usec + state->range_usec; i++) { + for (circpad_delay_t i = state->histogram_edges[0]+1; + i <= state->histogram_edges[0] + + state->histogram_edges[state->histogram_len-2]; i++) { int bin = circpad_histogram_usec_to_bin(client_side->padding_info[0], i); circpad_delay_t usec = @@ -1116,19 +1181,18 @@ test_circuitpadding_tokens(void *arg) { tt_int_op(mi->histogram[0], OP_EQ, 0); mi->histogram[0] = 1; - circpad_machine_remove_higher_token(mi, - state->start_usec/2); + circpad_machine_remove_higher_token(mi, state->histogram_edges[0]/2); tt_int_op(mi->histogram[0], OP_EQ, 0); } /* Drain the infinity bin and cause a refill */ while (inf_bin != 0) { tt_int_op(mi->histogram[4], OP_EQ, inf_bin); - circpad_cell_event_nonpadding_received((circuit_t*)client_side); + circpad_cell_event_nonpadding_received(client_side); inf_bin--; } - circpad_cell_event_nonpadding_sent((circuit_t*)client_side); + circpad_cell_event_nonpadding_sent(client_side); // We should have refilled here. tt_int_op(mi->histogram[4], OP_EQ, 2); @@ -1136,8 +1200,7 @@ test_circuitpadding_tokens(void *arg) /* 3.a. Bin 0 */ { tt_int_op(mi->histogram[0], OP_EQ, 1); - circpad_machine_remove_higher_token(mi, - state->start_usec/2); + circpad_machine_remove_higher_token(mi, state->histogram_edges[0]/2); tt_int_op(mi->histogram[0], OP_EQ, 0); } @@ -1225,6 +1288,7 @@ test_circuitpadding_tokens(void *arg) free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); monotime_disable_test_mocking(); tor_free(circ_client_machine.states); + testing_disable_reproducible_rng(); } void @@ -1252,11 +1316,12 @@ test_circuitpadding_wronghop(void *arg) /* Mock this function so that our cell counting tests don't get confused by * padding that gets sent by scheduled timers. */ MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); + testing_enable_reproducible_rng(); - client_side = (circuit_t *)origin_circuit_new(); + client_side = TO_CIRCUIT(origin_circuit_new()); dummy_channel.cmux = circuitmux_alloc(); - relay_side = (circuit_t *)new_fake_orcirc(&dummy_channel, - &dummy_channel); + relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, + &dummy_channel)); orig_client = TO_ORIGIN_CIRCUIT(client_side); relay_side->purpose = CIRCUIT_PURPOSE_OR; @@ -1374,9 +1439,9 @@ test_circuitpadding_wronghop(void *arg) free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); free_fake_orcirc(relay_side); - client_side = (circuit_t *)origin_circuit_new(); - relay_side = (circuit_t *)new_fake_orcirc(&dummy_channel, - &dummy_channel); + client_side = TO_CIRCUIT(origin_circuit_new()); + relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, + &dummy_channel)); relay_side->purpose = CIRCUIT_PURPOSE_OR; client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; @@ -1425,6 +1490,7 @@ test_circuitpadding_wronghop(void *arg) UNMOCK(circuit_package_relay_cell); UNMOCK(circuitmux_attach_circuit); nodes_free(); + testing_disable_reproducible_rng(); } void @@ -1570,10 +1636,10 @@ simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay, tor_addr_t addr; // Pretend a non-padding cell was sent - circpad_cell_event_nonpadding_sent((circuit_t*)client); + circpad_cell_event_nonpadding_sent(client); // Receive extend cell at middle - circpad_cell_event_nonpadding_received((circuit_t*)mid_relay); + circpad_cell_event_nonpadding_received(mid_relay); // Advance time a tiny bit so we can calculate an RTT curr_mocked_time += 10 * TOR_NSEC_PER_MSEC; @@ -1581,14 +1647,14 @@ simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay, monotime_set_mock_time_nsec(curr_mocked_time); // Receive extended cell at middle - circpad_cell_event_nonpadding_sent((circuit_t*)mid_relay); + circpad_cell_event_nonpadding_sent(mid_relay); // Receive extended cell at first hop - circpad_cell_event_nonpadding_received((circuit_t*)client); + circpad_cell_event_nonpadding_received(client); // Add a hop to cpath crypt_path_t *hop = tor_malloc_zero(sizeof(crypt_path_t)); - onion_append_to_cpath(&TO_ORIGIN_CIRCUIT(client)->cpath, hop); + cpath_extend_linked_list(&TO_ORIGIN_CIRCUIT(client)->cpath, hop); hop->magic = CRYPT_PATH_MAGIC; hop->state = CPATH_STATE_OPEN; @@ -1602,7 +1668,7 @@ simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay, digest, NULL, NULL, NULL, &addr, padding); - circuit_init_cpath_crypto(hop, whatevs_key, sizeof(whatevs_key), 0, 0); + cpath_init_circuit_crypto(hop, whatevs_key, sizeof(whatevs_key), 0, 0); hop->package_window = circuit_initial_package_window(); hop->deliver_window = CIRCWINDOW_START; @@ -1612,7 +1678,7 @@ simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay, } static circpad_machine_spec_t * -helper_create_conditional_machine(void) +helper_create_length_machine(void) { circpad_machine_spec_t *ret = tor_malloc_zero(sizeof(circpad_machine_spec_t)); @@ -1629,15 +1695,69 @@ helper_create_conditional_machine(void) ret->states[CIRCPAD_STATE_BURST]. next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END; + ret->states[CIRCPAD_STATE_BURST]. + next_state[CIRCPAD_EVENT_BINS_EMPTY] = CIRCPAD_STATE_END; + + /* No token removal.. end via state_length only */ ret->states[CIRCPAD_STATE_BURST].token_removal = CIRCPAD_TOKEN_REMOVAL_NONE; + /* Let's have this one end after 12 packets */ + ret->states[CIRCPAD_STATE_BURST].length_dist.type = CIRCPAD_DIST_UNIFORM; + ret->states[CIRCPAD_STATE_BURST].length_dist.param1 = 12; + ret->states[CIRCPAD_STATE_BURST].length_dist.param2 = 13; + ret->states[CIRCPAD_STATE_BURST].max_length = 12; + + ret->states[CIRCPAD_STATE_BURST].histogram_len = 4; + + ret->states[CIRCPAD_STATE_BURST].histogram_edges[0] = 0; + ret->states[CIRCPAD_STATE_BURST].histogram_edges[1] = 1; + ret->states[CIRCPAD_STATE_BURST].histogram_edges[2] = 1000000; + ret->states[CIRCPAD_STATE_BURST].histogram_edges[3] = 10000000; + + ret->states[CIRCPAD_STATE_BURST].histogram[0] = 0; + ret->states[CIRCPAD_STATE_BURST].histogram[1] = 0; + ret->states[CIRCPAD_STATE_BURST].histogram[2] = 6; + + ret->states[CIRCPAD_STATE_BURST].histogram_total_tokens = 6; + ret->states[CIRCPAD_STATE_BURST].use_rtt_estimate = 0; + ret->states[CIRCPAD_STATE_BURST].length_includes_nonpadding = 0; + + return ret; +} + +static circpad_machine_spec_t * +helper_create_conditional_machine(void) +{ + circpad_machine_spec_t *ret = + tor_malloc_zero(sizeof(circpad_machine_spec_t)); + + /* Start, burst */ + circpad_machine_states_init(ret, 2); + + ret->states[CIRCPAD_STATE_START]. + next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST; + + ret->states[CIRCPAD_STATE_BURST]. + next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST; + + ret->states[CIRCPAD_STATE_BURST]. + next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END; + + /* Use EXACT removal strategy, otherwise setup_tokens() does not work */ + ret->states[CIRCPAD_STATE_BURST].token_removal = + CIRCPAD_TOKEN_REMOVAL_EXACT; + ret->states[CIRCPAD_STATE_BURST].histogram_len = 3; - ret->states[CIRCPAD_STATE_BURST].start_usec = 0; - ret->states[CIRCPAD_STATE_BURST].range_usec = 1000000; + + ret->states[CIRCPAD_STATE_BURST].histogram_edges[0] = 0; + ret->states[CIRCPAD_STATE_BURST].histogram_edges[1] = 1; + ret->states[CIRCPAD_STATE_BURST].histogram_edges[2] = 1000000; + ret->states[CIRCPAD_STATE_BURST].histogram[0] = 6; ret->states[CIRCPAD_STATE_BURST].histogram[1] = 0; - ret->states[CIRCPAD_STATE_BURST].histogram[1] = 0; + ret->states[CIRCPAD_STATE_BURST].histogram[2] = 0; + ret->states[CIRCPAD_STATE_BURST].histogram_total_tokens = 6; ret->states[CIRCPAD_STATE_BURST].use_rtt_estimate = 0; ret->states[CIRCPAD_STATE_BURST].length_includes_nonpadding = 1; @@ -1649,8 +1769,11 @@ static void helper_create_conditional_machines(void) { circpad_machine_spec_t *add = helper_create_conditional_machine(); - origin_padding_machines = smartlist_new(); - relay_padding_machines = smartlist_new(); + + if (!origin_padding_machines) + origin_padding_machines = smartlist_new(); + if (!relay_padding_machines) + relay_padding_machines = smartlist_new(); add->machine_num = 2; add->is_origin_side = 1; @@ -1668,8 +1791,7 @@ helper_create_conditional_machines(void) add->conditions.state_mask = CIRCPAD_CIRC_BUILDING| CIRCPAD_CIRC_NO_STREAMS|CIRCPAD_CIRC_HAS_RELAY_EARLY; add->conditions.purpose_mask = CIRCPAD_PURPOSE_ALL; - - smartlist_add(origin_padding_machines, add); + circpad_register_padding_machine(add, origin_padding_machines); add = helper_create_conditional_machine(); add->machine_num = 3; @@ -1688,15 +1810,144 @@ helper_create_conditional_machines(void) add->conditions.state_mask = CIRCPAD_CIRC_OPENED| CIRCPAD_CIRC_STREAMS|CIRCPAD_CIRC_HAS_NO_RELAY_EARLY; add->conditions.purpose_mask = CIRCPAD_PURPOSE_ALL; - smartlist_add(origin_padding_machines, add); + circpad_register_padding_machine(add, origin_padding_machines); add = helper_create_conditional_machine(); add->machine_num = 2; - smartlist_add(relay_padding_machines, add); + circpad_register_padding_machine(add, relay_padding_machines); add = helper_create_conditional_machine(); add->machine_num = 3; - smartlist_add(relay_padding_machines, add); + circpad_register_padding_machine(add, relay_padding_machines); +} + +void +test_circuitpadding_state_length(void *arg) +{ + /** + * Test plan: + * * Explicitly test that with no token removal enabled, we hit + * the state length limit due to either padding, or non-padding. + * * Repeat test with an arbitrary token removal strategy, and + * verify that if we run out of tokens due to padding before we + * hit the state length, we still go to state end (all our + * token removal tests only test nonpadding token removal). + */ + int64_t actual_mocked_monotime_start; + (void)arg; + MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); + MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock); + + nodes_init(); + dummy_channel.cmux = circuitmux_alloc(); + relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, + &dummy_channel)); + client_side = TO_CIRCUIT(origin_circuit_new()); + relay_side->purpose = CIRCUIT_PURPOSE_OR; + client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; + + monotime_init(); + monotime_enable_test_mocking(); + actual_mocked_monotime_start = MONOTIME_MOCK_START; + monotime_set_mock_time_nsec(actual_mocked_monotime_start); + monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start); + curr_mocked_time = actual_mocked_monotime_start; + + /* This is needed so that we are not considered to be dormant */ + note_user_activity(20); + + timers_initialize(); + circpad_machine_spec_t *client_machine = + helper_create_length_machine(); + + MOCK(circuit_package_relay_cell, + circuit_package_relay_cell_mock); + MOCK(node_get_by_id, + node_get_by_id_mock); + + client_side->padding_machine[0] = client_machine; + client_side->padding_info[0] = + circpad_circuit_machineinfo_new(client_side, 0); + circpad_machine_runtime_t *mi = client_side->padding_info[0]; + + circpad_cell_event_padding_sent(client_side); + tt_i64_op(mi->state_length, OP_EQ, 12); + tt_ptr_op(mi->histogram, OP_EQ, NULL); + + /* Verify that non-padding does not change our state length */ + circpad_cell_event_nonpadding_sent(client_side); + tt_i64_op(mi->state_length, OP_EQ, 12); + + /* verify that sending padding changes our state length */ + for (uint64_t i = mi->state_length-1; i > 0; i--) { + circpad_send_padding_cell_for_callback(mi); + tt_i64_op(mi->state_length, OP_EQ, i); + } + circpad_send_padding_cell_for_callback(mi); + + tt_i64_op(mi->state_length, OP_EQ, -1); + tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END); + + /* Restart machine */ + mi->current_state = CIRCPAD_STATE_START; + + /* Now, count nonpadding as part of the state length */ + client_machine->states[CIRCPAD_STATE_BURST].length_includes_nonpadding = 1; + + circpad_cell_event_padding_sent(client_side); + tt_i64_op(mi->state_length, OP_EQ, 12); + + /* Verify that non-padding does change our state length now */ + for (uint64_t i = mi->state_length-1; i > 0; i--) { + circpad_cell_event_nonpadding_sent(client_side); + tt_i64_op(mi->state_length, OP_EQ, i); + } + + circpad_cell_event_nonpadding_sent(client_side); + tt_i64_op(mi->state_length, OP_EQ, -1); + tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END); + + /* Now, just test token removal when we send padding */ + client_machine->states[CIRCPAD_STATE_BURST].token_removal = + CIRCPAD_TOKEN_REMOVAL_EXACT; + + /* Restart machine */ + mi->current_state = CIRCPAD_STATE_START; + circpad_cell_event_padding_sent(client_side); + tt_i64_op(mi->state_length, OP_EQ, 12); + tt_ptr_op(mi->histogram, OP_NE, NULL); + tt_int_op(mi->chosen_bin, OP_EQ, 2); + + /* verify that sending padding changes our state length and + * our histogram now */ + for (uint32_t i = mi->histogram[2]-1; i > 0; i--) { + circpad_send_padding_cell_for_callback(mi); + tt_int_op(mi->chosen_bin, OP_EQ, 2); + tt_int_op(mi->histogram[2], OP_EQ, i); + } + + tt_i64_op(mi->state_length, OP_EQ, 7); + tt_int_op(mi->histogram[2], OP_EQ, 1); + + circpad_send_padding_cell_for_callback(mi); + tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END); + + done: + tor_free(client_machine->states); + tor_free(client_machine); + + free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); + free_fake_orcirc(relay_side); + + circuitmux_detach_all_circuits(dummy_channel.cmux, NULL); + circuitmux_free(dummy_channel.cmux); + timers_shutdown(); + monotime_disable_test_mocking(); + UNMOCK(circuit_package_relay_cell); + UNMOCK(circuitmux_attach_circuit); + UNMOCK(node_get_by_id); + + return; } void @@ -1720,12 +1971,13 @@ test_circuitpadding_conditions(void *arg) int64_t actual_mocked_monotime_start; (void)arg; MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); + testing_enable_reproducible_rng(); nodes_init(); dummy_channel.cmux = circuitmux_alloc(); - relay_side = (circuit_t *)new_fake_orcirc(&dummy_channel, - &dummy_channel); - client_side = (circuit_t *)origin_circuit_new(); + relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, + &dummy_channel)); + client_side = TO_CIRCUIT(origin_circuit_new()); relay_side->purpose = CIRCUIT_PURPOSE_OR; client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; @@ -1736,6 +1988,9 @@ test_circuitpadding_conditions(void *arg) monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start); curr_mocked_time = actual_mocked_monotime_start; + /* This is needed so that we are not considered to be dormant */ + note_user_activity(20); + timers_initialize(); helper_create_conditional_machines(); @@ -1821,91 +2076,346 @@ test_circuitpadding_conditions(void *arg) done: /* XXX: Free everything */ + testing_disable_reproducible_rng(); return; } -/** Helper function: Initializes a padding machine where every state uses the - * uniform probability distribution. */ -static void -helper_circpad_circ_distribution_machine_setup(int min, int max) +/** Disabled unstable test until #29298 is implemented (see #29122) */ +#if 0 +void +test_circuitpadding_circuitsetup_machine(void *arg) { - circpad_machine_states_init(&circ_client_machine, 7); + int64_t actual_mocked_monotime_start; + /** + * Test case plan: + * + * 1. Simulate a normal circuit setup pattern + * a. Application traffic + * + * FIXME: This should focus more on exercising the machine + * features rather than actual traffic patterns. For example, + * test cancellation and bins empty/refill + */ + (void)arg; - circpad_state_t *zero_st = &circ_client_machine.states[0]; - zero_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 1; - zero_st->iat_dist.type = CIRCPAD_DIST_UNIFORM; - zero_st->iat_dist.param1 = min; - zero_st->iat_dist.param2 = max; - zero_st->start_usec = min; - zero_st->range_usec = max; + MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); - circpad_state_t *first_st = &circ_client_machine.states[1]; - first_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 2; - first_st->iat_dist.type = CIRCPAD_DIST_LOGISTIC; - first_st->iat_dist.param1 = min; - first_st->iat_dist.param2 = max; - first_st->start_usec = min; - first_st->range_usec = max; + dummy_channel.cmux = circuitmux_alloc(); + client_side = TO_CIRCUIT(origin_circuit_new()); + relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel)); - circpad_state_t *second_st = &circ_client_machine.states[2]; - second_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 3; - second_st->iat_dist.type = CIRCPAD_DIST_LOG_LOGISTIC; - second_st->iat_dist.param1 = min; - second_st->iat_dist.param2 = max; - second_st->start_usec = min; - second_st->range_usec = max; + relay_side->purpose = CIRCUIT_PURPOSE_OR; + client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; - circpad_state_t *third_st = &circ_client_machine.states[3]; - third_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 4; - third_st->iat_dist.type = CIRCPAD_DIST_GEOMETRIC; - third_st->iat_dist.param1 = min; - third_st->iat_dist.param2 = max; - third_st->start_usec = min; - third_st->range_usec = max; + nodes_init(); - circpad_state_t *fourth_st = &circ_client_machine.states[4]; - fourth_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 5; - fourth_st->iat_dist.type = CIRCPAD_DIST_WEIBULL; - fourth_st->iat_dist.param1 = min; - fourth_st->iat_dist.param2 = max; - fourth_st->start_usec = min; - fourth_st->range_usec = max; + monotime_init(); + monotime_enable_test_mocking(); + actual_mocked_monotime_start = MONOTIME_MOCK_START; + monotime_set_mock_time_nsec(actual_mocked_monotime_start); + monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start); + curr_mocked_time = actual_mocked_monotime_start; - circpad_state_t *fifth_st = &circ_client_machine.states[5]; - fifth_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 6; - fifth_st->iat_dist.type = CIRCPAD_DIST_PARETO; - fifth_st->iat_dist.param1 = min; - fifth_st->iat_dist.param2 = max; - fifth_st->start_usec = min; - fifth_st->range_usec = max; -} + timers_initialize(); + circpad_machines_init(); -/** Simple test that the padding delays sampled from a uniform distribution - * actually faill within the uniform distribution range. */ -/* TODO: Upgrade this test so that each state tests a different prob - * distribution */ -static void -test_circuitpadding_sample_distribution(void *arg) -{ - circpad_machine_state_t *mi; - int n_samples; - int n_states; + MOCK(circuit_package_relay_cell, + circuit_package_relay_cell_mock); + MOCK(node_get_by_id, + node_get_by_id_mock); - (void) arg; + /* Test case #1: Build a 3 hop circuit, then wait and let pad */ + simulate_single_hop_extend(client_side, relay_side, 1); + simulate_single_hop_extend(client_side, relay_side, 1); + simulate_single_hop_extend(client_side, relay_side, 1); - /* mock this function so that we dont actually schedule any padding */ - MOCK(circpad_machine_schedule_padding, - circpad_machine_schedule_padding_mock); + tt_int_op(n_client_cells, OP_EQ, 1); + tt_int_op(n_relay_cells, OP_EQ, 1); + tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, + CIRCPAD_STATE_BURST); + tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ, + CIRCPAD_STATE_BURST); + + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + tt_int_op(relay_side->padding_info[0]->is_padding_timer_scheduled, + OP_EQ, 0); + timers_advance_and_run(2000); + tt_int_op(n_client_cells, OP_EQ, 2); + tt_int_op(n_relay_cells, OP_EQ, 1); - /* Initialize a machine with multiple probability distributions that should - * return values between 0 and 5 */ - circpad_machines_init(); - helper_circpad_circ_distribution_machine_setup(0, 10); + tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ, + CIRCPAD_STATE_GAP); - /* Initialize machine and circuits */ - client_side = TO_CIRCUIT(origin_circuit_new()); - client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; - client_side->padding_machine[0] = &circ_client_machine; + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_EQ, 0); + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + timers_advance_and_run(5000); + tt_int_op(n_client_cells, OP_EQ, 2); + tt_int_op(n_relay_cells, OP_EQ, 2); + + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + OP_EQ, 0); + timers_advance_and_run(2000); + tt_int_op(n_client_cells, OP_EQ, 3); + tt_int_op(n_relay_cells, OP_EQ, 2); + + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_EQ, 0); + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + timers_advance_and_run(5000); + tt_int_op(n_client_cells, OP_EQ, 3); + tt_int_op(n_relay_cells, OP_EQ, 3); + + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + OP_EQ, 0); + timers_advance_and_run(2000); + tt_int_op(n_client_cells, OP_EQ, 4); + tt_int_op(n_relay_cells, OP_EQ, 3); + + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_EQ, 0); + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + timers_advance_and_run(5000); + tt_int_op(n_client_cells, OP_EQ, 4); + tt_int_op(n_relay_cells, OP_EQ, 4); + + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + OP_EQ, 0); + timers_advance_and_run(2000); + tt_int_op(n_client_cells, OP_EQ, 5); + tt_int_op(n_relay_cells, OP_EQ, 4); + + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_EQ, 0); + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + timers_advance_and_run(5000); + tt_int_op(n_client_cells, OP_EQ, 5); + tt_int_op(n_relay_cells, OP_EQ, 5); + + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + OP_EQ, 0); + timers_advance_and_run(2000); + tt_int_op(n_client_cells, OP_EQ, 6); + tt_int_op(n_relay_cells, OP_EQ, 5); + + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_EQ, 0); + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + timers_advance_and_run(5000); + tt_int_op(n_client_cells, OP_EQ, 6); + tt_int_op(n_relay_cells, OP_EQ, 6); + + tt_int_op(client_side->padding_info[0]->current_state, + OP_EQ, CIRCPAD_STATE_END); + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_EQ, 0); + tt_int_op(relay_side->padding_info[0]->current_state, + OP_EQ, CIRCPAD_STATE_GAP); + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + OP_EQ, 0); + + /* Verify we can't schedule padding in END state */ + circpad_decision_t ret = + circpad_machine_schedule_padding(client_side->padding_info[0]); + tt_int_op(ret, OP_EQ, CIRCPAD_STATE_UNCHANGED); + + /* Simulate application traffic */ + circpad_cell_event_nonpadding_sent(client_side); + circpad_deliver_unrecognized_cell_events(relay_side, CELL_DIRECTION_OUT); + circpad_deliver_unrecognized_cell_events(relay_side, CELL_DIRECTION_IN); + circpad_deliver_recognized_relay_cell_events(client_side, RELAY_COMMAND_DATA, + TO_ORIGIN_CIRCUIT(client_side)->cpath->next); + + tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL); + + tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL); + tt_int_op(n_client_cells, OP_EQ, 6); + tt_int_op(n_relay_cells, OP_EQ, 7); + + // Test timer cancellation + simulate_single_hop_extend(client_side, relay_side, 1); + simulate_single_hop_extend(client_side, relay_side, 1); + timers_advance_and_run(5000); + circpad_cell_event_padding_received(client_side); + + tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, + CIRCPAD_STATE_BURST); + tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ, + CIRCPAD_STATE_GAP); + + tt_int_op(n_client_cells, OP_EQ, 8); + tt_int_op(n_relay_cells, OP_EQ, 8); + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + + /* Test timer cancel due to state rules */ + circpad_cell_event_nonpadding_sent(client_side); + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_EQ, 0); + circpad_cell_event_padding_received(client_side); + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + + /* Simulate application traffic to cancel timer */ + circpad_cell_event_nonpadding_sent(client_side); + circpad_deliver_unrecognized_cell_events(relay_side, CELL_DIRECTION_OUT); + circpad_deliver_unrecognized_cell_events(relay_side, CELL_DIRECTION_IN); + circpad_deliver_recognized_relay_cell_events(client_side, RELAY_COMMAND_DATA, + TO_ORIGIN_CIRCUIT(client_side)->cpath->next); + + tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL); + + tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL); + + /* No cells sent, except negotiate end from relay */ + tt_int_op(n_client_cells, OP_EQ, 8); + tt_int_op(n_relay_cells, OP_EQ, 9); + + /* Test mark for close and free */ + simulate_single_hop_extend(client_side, relay_side, 1); + simulate_single_hop_extend(client_side, relay_side, 1); + timers_advance_and_run(5000); + circpad_cell_event_padding_received(client_side); + + tt_int_op(n_client_cells, OP_EQ, 10); + tt_int_op(n_relay_cells, OP_EQ, 10); + + tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, + CIRCPAD_STATE_BURST); + tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ, + CIRCPAD_STATE_GAP); + + tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec, + OP_NE, 0); + circuit_mark_for_close(client_side, END_CIRC_REASON_FLAG_REMOTE); + free_fake_orcirc(relay_side); + timers_advance_and_run(5000); + + /* No cells sent */ + tt_int_op(n_client_cells, OP_EQ, 10); + tt_int_op(n_relay_cells, OP_EQ, 10); + + done: + free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); + + circuitmux_detach_all_circuits(dummy_channel.cmux, NULL); + circuitmux_free(dummy_channel.cmux); + timers_shutdown(); + monotime_disable_test_mocking(); + UNMOCK(circuit_package_relay_cell); + UNMOCK(circuitmux_attach_circuit); + + return; +} +#endif /* 0 */ + +/** Helper function: Initializes a padding machine where every state uses the + * uniform probability distribution. */ +static void +helper_circpad_circ_distribution_machine_setup(int min, int max) +{ + circpad_machine_states_init(&circ_client_machine, 7); + + circpad_state_t *zero_st = &circ_client_machine.states[0]; + zero_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 1; + zero_st->iat_dist.type = CIRCPAD_DIST_UNIFORM; + /* param2 is upper bound, param1 is lower */ + zero_st->iat_dist.param1 = min; + zero_st->iat_dist.param2 = max; + zero_st->dist_added_shift_usec = min; + zero_st->dist_max_sample_usec = max; + + circpad_state_t *first_st = &circ_client_machine.states[1]; + first_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 2; + first_st->iat_dist.type = CIRCPAD_DIST_LOGISTIC; + /* param1 is Mu, param2 is sigma. */ + first_st->iat_dist.param1 = 9; + first_st->iat_dist.param2 = 3; + first_st->dist_added_shift_usec = min; + first_st->dist_max_sample_usec = max; + + circpad_state_t *second_st = &circ_client_machine.states[2]; + second_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 3; + second_st->iat_dist.type = CIRCPAD_DIST_LOG_LOGISTIC; + /* param1 is Alpha, param2 is 1.0/Beta */ + second_st->iat_dist.param1 = 1; + second_st->iat_dist.param2 = 0.5; + second_st->dist_added_shift_usec = min; + second_st->dist_max_sample_usec = max; + + circpad_state_t *third_st = &circ_client_machine.states[3]; + third_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 4; + third_st->iat_dist.type = CIRCPAD_DIST_GEOMETRIC; + /* param1 is 'p' (success probability) */ + third_st->iat_dist.param1 = 0.2; + third_st->dist_added_shift_usec = min; + third_st->dist_max_sample_usec = max; + + circpad_state_t *fourth_st = &circ_client_machine.states[4]; + fourth_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 5; + fourth_st->iat_dist.type = CIRCPAD_DIST_WEIBULL; + /* param1 is k, param2 is Lambda */ + fourth_st->iat_dist.param1 = 1.5; + fourth_st->iat_dist.param2 = 1; + fourth_st->dist_added_shift_usec = min; + fourth_st->dist_max_sample_usec = max; + + circpad_state_t *fifth_st = &circ_client_machine.states[5]; + fifth_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 6; + fifth_st->iat_dist.type = CIRCPAD_DIST_PARETO; + /* param1 is sigma, param2 is xi */ + fifth_st->iat_dist.param1 = 1; + fifth_st->iat_dist.param2 = 5; + fifth_st->dist_added_shift_usec = min; + fifth_st->dist_max_sample_usec = max; +} + +/** Simple test that the padding delays sampled from a uniform distribution + * actually faill within the uniform distribution range. */ +static void +test_circuitpadding_sample_distribution(void *arg) +{ + circpad_machine_runtime_t *mi; + int n_samples; + int n_states; + + (void) arg; + + /* mock this function so that we dont actually schedule any padding */ + MOCK(circpad_machine_schedule_padding, + circpad_machine_schedule_padding_mock); + testing_enable_reproducible_rng(); + + /* Initialize a machine with multiple probability distributions */ + circpad_machines_init(); + helper_circpad_circ_distribution_machine_setup(0, 10); + + /* Initialize machine and circuits */ + client_side = TO_CIRCUIT(origin_circuit_new()); + client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; + client_side->padding_machine[0] = &circ_client_machine; client_side->padding_info[0] = circpad_circuit_machineinfo_new(client_side, 0); mi = client_side->padding_info[0]; @@ -1923,16 +2433,17 @@ test_circuitpadding_sample_distribution(void *arg) } /* send a non-padding cell to move to the next machine state */ - circpad_cell_event_nonpadding_received((circuit_t*)client_side); + circpad_cell_event_nonpadding_received(client_side); } done: free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); UNMOCK(circpad_machine_schedule_padding); + testing_disable_reproducible_rng(); } static circpad_decision_t -circpad_machine_spec_transition_mock(circpad_machine_state_t *mi, +circpad_machine_spec_transition_mock(circpad_machine_runtime_t *mi, circpad_event_t event) { (void) mi; @@ -1947,13 +2458,14 @@ test_circuitpadding_machine_rate_limiting(void *arg) { (void) arg; bool retval; - circpad_machine_state_t *mi; + circpad_machine_runtime_t *mi; int i; /* Ignore machine transitions for the purposes of this function, we only * really care about padding counts */ MOCK(circpad_machine_spec_transition, circpad_machine_spec_transition_mock); MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock); + testing_enable_reproducible_rng(); /* Setup machine and circuits */ client_side = TO_CIRCUIT(origin_circuit_new()); @@ -2007,6 +2519,7 @@ test_circuitpadding_machine_rate_limiting(void *arg) done: free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); + testing_disable_reproducible_rng(); } /* Test global padding rate limits */ @@ -2015,7 +2528,7 @@ test_circuitpadding_global_rate_limiting(void *arg) { (void) arg; bool retval; - circpad_machine_state_t *mi; + circpad_machine_runtime_t *mi; int i; int64_t actual_mocked_monotime_start; @@ -2026,6 +2539,7 @@ test_circuitpadding_global_rate_limiting(void *arg) MOCK(circuit_package_relay_cell, circuit_package_relay_cell_mock); MOCK(monotime_absolute_usec, mock_monotime_absolute_usec); + testing_enable_reproducible_rng(); monotime_init(); monotime_enable_test_mocking(); @@ -2035,12 +2549,12 @@ test_circuitpadding_global_rate_limiting(void *arg) curr_mocked_time = actual_mocked_monotime_start; timers_initialize(); - client_side = (circuit_t *)origin_circuit_new(); + client_side = TO_CIRCUIT(origin_circuit_new()); client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; dummy_channel.cmux = circuitmux_alloc(); /* Setup machine and circuits */ - relay_side = (circuit_t *)new_fake_orcirc(&dummy_channel, &dummy_channel); + relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel)); relay_side->purpose = CIRCUIT_PURPOSE_OR; helper_create_basic_machine(); relay_side->padding_machine[0] = &circ_client_machine; @@ -2105,6 +2619,537 @@ test_circuitpadding_global_rate_limiting(void *arg) circuitmux_free(dummy_channel.cmux); SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp)); smartlist_free(vote1.net_params); + testing_disable_reproducible_rng(); +} + +/* Test reduced and disabled padding */ +static void +test_circuitpadding_reduce_disable(void *arg) +{ + (void) arg; + int64_t actual_mocked_monotime_start; + + MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); + testing_enable_reproducible_rng(); + + nodes_init(); + dummy_channel.cmux = circuitmux_alloc(); + relay_side = (circuit_t *)new_fake_orcirc(&dummy_channel, + &dummy_channel); + client_side = (circuit_t *)origin_circuit_new(); + relay_side->purpose = CIRCUIT_PURPOSE_OR; + client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; + + circpad_machines_init(); + helper_create_conditional_machines(); + + monotime_init(); + monotime_enable_test_mocking(); + actual_mocked_monotime_start = MONOTIME_MOCK_START; + monotime_set_mock_time_nsec(actual_mocked_monotime_start); + monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start); + curr_mocked_time = actual_mocked_monotime_start; + timers_initialize(); + + /* This is needed so that we are not considered to be dormant */ + note_user_activity(20); + + MOCK(circuit_package_relay_cell, + circuit_package_relay_cell_mock); + MOCK(node_get_by_id, + node_get_by_id_mock); + + /* Simulate extend. This should result in the original machine getting + * added, since the circuit is not built */ + simulate_single_hop_extend(client_side, relay_side, 1); + simulate_single_hop_extend(client_side, relay_side, 1); + + /* Verify that machine #2 is added */ + tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2); + tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2); + + /* Deliver a padding cell to the client, to trigger burst state */ + circpad_cell_event_padding_sent(client_side); + + /* This should have trigger length shutdown condition on client.. */ + tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL); + + /* Verify machine is gone from both sides */ + tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL); + + /* Now test the reduced padding machine by setting up the consensus */ + networkstatus_t vote1; + vote1.net_params = smartlist_new(); + smartlist_split_string(vote1.net_params, + "circpad_padding_reduced=1", NULL, 0, 0); + + /* Register reduced padding machine with the padding subsystem */ + circpad_new_consensus_params(&vote1); + + simulate_single_hop_extend(client_side, relay_side, 1); + + /* Verify that machine #0 is added */ + tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2); + tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2); + + tt_int_op( + circpad_machine_reached_padding_limit(client_side->padding_info[0]), + OP_EQ, 0); + tt_int_op( + circpad_machine_reached_padding_limit(relay_side->padding_info[0]), + OP_EQ, 0); + + /* Test that machines get torn down when padding is disabled */ + SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp)); + smartlist_free(vote1.net_params); + vote1.net_params = smartlist_new(); + smartlist_split_string(vote1.net_params, + "circpad_padding_disabled=1", NULL, 0, 0); + + /* Register reduced padding machine with the padding subsystem */ + circpad_new_consensus_params(&vote1); + + tt_int_op( + circpad_machine_schedule_padding(client_side->padding_info[0]), + OP_EQ, CIRCPAD_STATE_UNCHANGED); + tt_int_op( + circpad_machine_schedule_padding(relay_side->padding_info[0]), + OP_EQ, CIRCPAD_STATE_UNCHANGED); + + /* Signal that circuit is built: this event causes us to re-evaluate + * machine conditions (which don't apply because padding is disabled). */ + circpad_machine_event_circ_built(TO_ORIGIN_CIRCUIT(client_side)); + + tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL); + tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL); + + SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp)); + smartlist_free(vote1.net_params); + vote1.net_params = NULL; + circpad_new_consensus_params(&vote1); + + get_options_mutable()->ReducedCircuitPadding = 1; + + simulate_single_hop_extend(client_side, relay_side, 1); + + /* Verify that machine #0 is added */ + tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2); + tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2); + + tt_int_op( + circpad_machine_reached_padding_limit(client_side->padding_info[0]), + OP_EQ, 0); + tt_int_op( + circpad_machine_reached_padding_limit(relay_side->padding_info[0]), + OP_EQ, 0); + + get_options_mutable()->CircuitPadding = 0; + + tt_int_op( + circpad_machine_schedule_padding(client_side->padding_info[0]), + OP_EQ, CIRCPAD_STATE_UNCHANGED); + tt_int_op( + circpad_machine_schedule_padding(relay_side->padding_info[0]), + OP_EQ, CIRCPAD_STATE_UNCHANGED); + + /* Signal that circuit is built: this event causes us to re-evaluate + * machine conditions (which don't apply because padding is disabled). */ + + circpad_machine_event_circ_built(TO_ORIGIN_CIRCUIT(client_side)); + + tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL); + tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL); + + done: + free_fake_orcirc(relay_side); + circuitmux_detach_all_circuits(dummy_channel.cmux, NULL); + circuitmux_free(dummy_channel.cmux); + testing_disable_reproducible_rng(); +} + +/** Just a basic machine whose whole purpose is to reach the END state */ +static void +helper_create_ender_machine(void) +{ + /* Start, burst */ + circpad_machine_states_init(&circ_client_machine, 2); + + circ_client_machine.states[CIRCPAD_STATE_START]. + next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_END; + + circ_client_machine.conditions.state_mask = CIRCPAD_STATE_ALL; + circ_client_machine.conditions.purpose_mask = CIRCPAD_PURPOSE_ALL; +} + +static time_t mocked_timeofday; +/** Set timeval to a mock date and time. This is necessary + * to make tor_gettimeofday() mockable. */ +static void +mock_tor_gettimeofday(struct timeval *timeval) +{ + timeval->tv_sec = mocked_timeofday; + timeval->tv_usec = 0; +} + +/** Test manual managing of circuit lifetimes by the circuitpadding + * subsystem. In particular this test goes through all the cases of the + * circpad_marked_circuit_for_padding() function, via + * circuit_mark_for_close() as well as + * circuit_expire_old_circuits_clientside(). */ +static void +test_circuitpadding_manage_circuit_lifetime(void *arg) +{ + circpad_machine_runtime_t *mi; + + (void) arg; + + client_side = (circuit_t *)origin_circuit_new(); + client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; + monotime_enable_test_mocking(); + MOCK(tor_gettimeofday, mock_tor_gettimeofday); + mocked_timeofday = 23; + + helper_create_ender_machine(); + + /* Enable manual circuit lifetime manage for this test */ + circ_client_machine.manage_circ_lifetime = 1; + + /* Test setup */ + client_side->padding_machine[0] = &circ_client_machine; + client_side->padding_info[0] = + circpad_circuit_machineinfo_new(client_side, 0); + mi = client_side->padding_info[0]; + + tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_START); + + /* Check that the circuit is not marked for close */ + tt_int_op(client_side->marked_for_close, OP_EQ, 0); + tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL); + + /* Mark this circuit for close due to a remote reason */ + circuit_mark_for_close(client_side, + END_CIRC_REASON_FLAG_REMOTE|END_CIRC_REASON_NONE); + tt_ptr_op(client_side->padding_info[0], OP_NE, NULL); + tt_int_op(client_side->marked_for_close, OP_NE, 0); + tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL); + client_side->marked_for_close = 0; + + /* Mark this circuit for close due to a protocol issue */ + circuit_mark_for_close(client_side, END_CIRC_REASON_TORPROTOCOL); + tt_int_op(client_side->marked_for_close, OP_NE, 0); + tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL); + client_side->marked_for_close = 0; + + /* Mark a measurement circuit for close */ + client_side->purpose = CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT; + circuit_mark_for_close(client_side, END_CIRC_REASON_NONE); + tt_int_op(client_side->marked_for_close, OP_NE, 0); + tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT); + client_side->marked_for_close = 0; + + /* Mark a general circuit for close */ + client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; + circuit_mark_for_close(client_side, END_CIRC_REASON_NONE); + + /* Check that this circuit is still not marked for close since we are + * managing the lifetime manually, but the circuit was tagged as such by the + * circpadding subsystem */ + tt_int_op(client_side->marked_for_close, OP_EQ, 0); + tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_CIRCUIT_PADDING); + + /* We just tested case (1) from the comments of + * circpad_circuit_should_be_marked_for_close() */ + + /* Transition the machine to the END state but did not delete its machine */ + tt_ptr_op(client_side->padding_info[0], OP_NE, NULL); + circpad_cell_event_nonpadding_received(client_side); + tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END); + + /* We just tested case (3) from the comments of + * circpad_circuit_should_be_marked_for_close(). + * Now let's go for case (2). */ + + /* Reset the close mark */ + client_side->marked_for_close = 0; + + /* Mark this circuit for close */ + circuit_mark_for_close(client_side, 0); + + /* See that the circ got closed since we are already in END state */ + tt_int_op(client_side->marked_for_close, OP_NE, 0); + + /* We just tested case (2). Now let's see that case (4) is unreachable as + that comment claims */ + + /* First, reset all close marks and tags */ + client_side->marked_for_close = 0; + client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; + + /* Now re-create the ender machine so that we can transition to END again */ + /* Free up some stuff first */ + circpad_circuit_free_all_machineinfos(client_side); + tor_free(circ_client_machine.states); + helper_create_ender_machine(); + + client_side->padding_machine[0] = &circ_client_machine; + client_side->padding_info[0] = + circpad_circuit_machineinfo_new(client_side, 0); + mi = client_side->padding_info[0]; + + /* Check we are in START. */ + tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_START); + + /* Test that we don't expire this circuit yet */ + client_side->timestamp_dirty = 0; + client_side->state = CIRCUIT_STATE_OPEN; + tor_gettimeofday(&client_side->timestamp_began); + TO_ORIGIN_CIRCUIT(client_side)->circuit_idle_timeout = 23; + mocked_timeofday += 24; + circuit_expire_old_circuits_clientside(); + circuit_expire_old_circuits_clientside(); + circuit_expire_old_circuits_clientside(); + tt_int_op(client_side->timestamp_dirty, OP_NE, 0); + tt_int_op(client_side->marked_for_close, OP_EQ, 0); + tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_CIRCUIT_PADDING); + + /* Runaway circpad test: if the machine does not transition to end, + * test that after CIRCPAD_DELAY_MAX_SECS, we get marked anyway */ + mocked_timeofday = client_side->timestamp_dirty + + get_options()->MaxCircuitDirtiness + 2; + client_side->padding_info[0]->last_cell_time_sec = + approx_time()-(CIRCPAD_DELAY_MAX_SECS+10); + circuit_expire_old_circuits_clientside(); + tt_int_op(client_side->marked_for_close, OP_NE, 0); + + /* Test back to normal: if we had activity, we won't close */ + client_side->padding_info[0]->last_cell_time_sec = approx_time(); + client_side->marked_for_close = 0; + circuit_expire_old_circuits_clientside(); + tt_int_op(client_side->marked_for_close, OP_EQ, 0); + + /* Transition to END, but before we're past the dirty timer */ + mocked_timeofday = client_side->timestamp_dirty; + circpad_cell_event_nonpadding_received(client_side); + tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END); + + /* Verify that the circuit was not closed. */ + tt_int_op(client_side->marked_for_close, OP_EQ, 0); + + /* Now that we are in END state, we can be closed by expiry, but via + * the timestamp_dirty path, not the idle path. So first test not dirty + * enough. */ + mocked_timeofday = client_side->timestamp_dirty; + circuit_expire_old_circuits_clientside(); + tt_int_op(client_side->marked_for_close, OP_EQ, 0); + mocked_timeofday = client_side->timestamp_dirty + + get_options()->MaxCircuitDirtiness + 2; + circuit_expire_old_circuits_clientside(); + tt_int_op(client_side->marked_for_close, OP_NE, 0); + + done: + free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); + tor_free(circ_client_machine.states); + monotime_disable_test_mocking(); + UNMOCK(tor_gettimeofday); +} + +/** Helper for the test_circuitpadding_hs_machines test: + * + * - Create a client and relay circuit. + * - Setup right circuit purpose and attach a machine to the client circuit. + * - Verify that state transitions work as intended and state length gets + * enforced. + * + * This function is able to do this test both for intro and rend circuits + * depending on the value of test_intro_circs. + */ +static void +helper_test_hs_machines(bool test_intro_circs) +{ + /* Setup the circuits */ + origin_circuit_t *origin_client_side = origin_circuit_new(); + client_side = TO_CIRCUIT(origin_client_side); + client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; + + dummy_channel.cmux = circuitmux_alloc(); + relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel)); + relay_side->purpose = CIRCUIT_PURPOSE_OR; + + /* extend the client circ to two hops */ + simulate_single_hop_extend(client_side, relay_side, 1); + simulate_single_hop_extend(client_side, relay_side, 1); + + /* machines only apply on opened circuits */ + origin_client_side->has_opened = 1; + + /************************************/ + + /* Attaching the client machine now won't work here because of a wrong + * purpose */ + tt_assert(!client_side->padding_machine[0]); + circpad_add_matching_machines(origin_client_side, origin_padding_machines); + tt_assert(!client_side->padding_machine[0]); + + /* Change the purpose, see the machine getting attached */ + client_side->purpose = test_intro_circs ? + CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT : CIRCUIT_PURPOSE_C_REND_JOINED; + circpad_add_matching_machines(origin_client_side, origin_padding_machines); + tt_ptr_op(client_side->padding_info[0], OP_NE, NULL); + tt_ptr_op(client_side->padding_machine[0], OP_NE, NULL); + + tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL); + tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL); + + /* Verify that the right machine is attached */ + tt_str_op(client_side->padding_machine[0]->name, OP_EQ, + test_intro_circs ? "client_ip_circ" : "client_rp_circ"); + tt_str_op(relay_side->padding_machine[0]->name, OP_EQ, + test_intro_circs ? "relay_ip_circ": "relay_rp_circ"); + + /***********************************/ + + /* Intro machines are at START state, but rend machines have already skipped + * to OBFUSCATE_CIRC_SETUP because of the sent PADDING_NEGOTIATE. */ + tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, + CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP); + tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ, + CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP); + + /*Send non-padding to move the machines from START to OBFUSCATE_CIRC_SETUP */ + circpad_cell_event_nonpadding_received(client_side); + circpad_cell_event_nonpadding_received(relay_side); + tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, + CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP); + tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ, + CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP); + + /* Check that the state lengths have been sampled and are within range */ + circpad_machine_runtime_t *client_machine_runtime = + client_side->padding_info[0]; + circpad_machine_runtime_t *relay_machine_runtime = + relay_side->padding_info[0]; + + if (test_intro_circs) { + /* on the client side, we don't send any padding so + * state length is not set */ + tt_i64_op(client_machine_runtime->state_length, OP_EQ, -1); + /* relay side has state limits. check them */ + tt_i64_op(relay_machine_runtime->state_length, OP_GE, + INTRO_MACHINE_MINIMUM_PADDING); + tt_i64_op(relay_machine_runtime->state_length, OP_LT, + INTRO_MACHINE_MAXIMUM_PADDING); + } else { + tt_i64_op(client_machine_runtime->state_length, OP_EQ, 1); + tt_i64_op(relay_machine_runtime->state_length, OP_EQ, 1); + } + + if (test_intro_circs) { + int i; + /* Send state_length worth of padding from the relay and see that the + * client state goes to END */ + for (i = (int) relay_machine_runtime->state_length ; i > 0 ; i--) { + circpad_send_padding_cell_for_callback(relay_machine_runtime); + } + /* See that the machine has been teared down after all the length has been + * exhausted (the padding info should now be null on both sides) */ + tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL); + } else { + int i; + /* Send state_length worth of padding and see that the state goes to END */ + for (i = (int) client_machine_runtime->state_length ; i > 0 ; i--) { + circpad_send_padding_cell_for_callback(client_machine_runtime); + } + /* See that the machine has been teared down after all the length has been + * exhausted. */ + tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, + CIRCPAD_STATE_END); + } + + done: + free_fake_orcirc(relay_side); + circuitmux_detach_all_circuits(dummy_channel.cmux, NULL); + circuitmux_free(dummy_channel.cmux); + free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); +} + +/** Test that the HS circuit padding machines work as intended. */ +static void +test_circuitpadding_hs_machines(void *arg) +{ + (void)arg; + + /* Test logic: + * + * 1) Register the HS machines, which aim to hide the presense of + * onion service traffic on the client-side + * + * 2) Call helper_test_hs_machines() to perform tests for the intro circuit + * machines and for the rend circuit machines. + */ + + MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); + MOCK(circuit_package_relay_cell, circuit_package_relay_cell_mock); + MOCK(circuit_get_nth_node, circuit_get_nth_node_mock); + MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); + + origin_padding_machines = smartlist_new(); + relay_padding_machines = smartlist_new(); + + nodes_init(); + + monotime_init(); + monotime_enable_test_mocking(); + monotime_set_mock_time_nsec(1*TOR_NSEC_PER_USEC); + monotime_coarse_set_mock_time_nsec(1*TOR_NSEC_PER_USEC); + curr_mocked_time = 1*TOR_NSEC_PER_USEC; + + timers_initialize(); + + /* This is needed so that we are not considered to be dormant */ + note_user_activity(20); + + /************************************/ + + /* Register the HS machines */ + circpad_machine_client_hide_intro_circuits(origin_padding_machines); + circpad_machine_client_hide_rend_circuits(origin_padding_machines); + circpad_machine_relay_hide_intro_circuits(relay_padding_machines); + circpad_machine_relay_hide_rend_circuits(relay_padding_machines); + + /***********************************/ + + /* Do the tests for the intro circuit machines */ + helper_test_hs_machines(true); + /* Do the tests for the rend circuit machines */ + helper_test_hs_machines(false); + + timers_shutdown(); + monotime_disable_test_mocking(); + + SMARTLIST_FOREACH_BEGIN(origin_padding_machines, + circpad_machine_spec_t *, m) { + machine_spec_free(m); + } SMARTLIST_FOREACH_END(m); + + SMARTLIST_FOREACH_BEGIN(relay_padding_machines, + circpad_machine_spec_t *, m) { + machine_spec_free(m); + } SMARTLIST_FOREACH_END(m); + + smartlist_free(origin_padding_machines); + smartlist_free(relay_padding_machines); + + UNMOCK(circuitmux_attach_circuit); + UNMOCK(circuit_package_relay_cell); + UNMOCK(circuit_get_nth_node); + UNMOCK(circpad_machine_schedule_padding); } #define TEST_CIRCUITPADDING(name, flags) \ @@ -2112,17 +3157,23 @@ test_circuitpadding_global_rate_limiting(void *arg) struct testcase_t circuitpadding_tests[] = { TEST_CIRCUITPADDING(circuitpadding_tokens, TT_FORK), + TEST_CIRCUITPADDING(circuitpadding_state_length, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_negotiation, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_wronghop, TT_FORK), + /** Disabled unstable test until #29298 is implemented (see #29122) */ + // TEST_CIRCUITPADDING(circuitpadding_circuitsetup_machine, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_conditions, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_rtt, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_sample_distribution, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_machine_rate_limiting, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_global_rate_limiting, TT_FORK), + TEST_CIRCUITPADDING(circuitpadding_reduce_disable, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_token_removal_lower, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_token_removal_higher, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_closest_token_removal, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_closest_token_removal_usec, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_token_removal_exact, TT_FORK), + TEST_CIRCUITPADDING(circuitpadding_manage_circuit_lifetime, TT_FORK), + TEST_CIRCUITPADDING(circuitpadding_hs_machines, TT_FORK), END_OF_TESTCASES }; diff --git a/src/test/test_circuitstats.c b/src/test/test_circuitstats.c index 1cbcb14f2b..2a09622f09 100644 --- a/src/test/test_circuitstats.c +++ b/src/test/test_circuitstats.c @@ -28,7 +28,7 @@ origin_circuit_t *subtest_fourhop_circuit(struct timeval, int); origin_circuit_t *add_opened_threehop(void); origin_circuit_t *build_unopened_fourhop(struct timeval); -int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); +int cpath_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); static int marked_for_close; /* Mock function because we are not trying to test the close circuit that does @@ -57,9 +57,9 @@ add_opened_threehop(void) or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); or_circ->build_state->desired_path_len = DEFAULT_ROUTE_LEN; - onion_append_hop(&or_circ->cpath, &fakehop); - onion_append_hop(&or_circ->cpath, &fakehop); - onion_append_hop(&or_circ->cpath, &fakehop); + cpath_append_hop(&or_circ->cpath, &fakehop); + cpath_append_hop(&or_circ->cpath, &fakehop); + cpath_append_hop(&or_circ->cpath, &fakehop); or_circ->has_opened = 1; TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN; @@ -82,10 +82,10 @@ build_unopened_fourhop(struct timeval circ_start_time) or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); or_circ->build_state->desired_path_len = 4; - onion_append_hop(&or_circ->cpath, fakehop); - onion_append_hop(&or_circ->cpath, fakehop); - onion_append_hop(&or_circ->cpath, fakehop); - onion_append_hop(&or_circ->cpath, fakehop); + cpath_append_hop(&or_circ->cpath, fakehop); + cpath_append_hop(&or_circ->cpath, fakehop); + cpath_append_hop(&or_circ->cpath, fakehop); + cpath_append_hop(&or_circ->cpath, fakehop); tor_free(fakehop); diff --git a/src/test/test_config.c b/src/test/test_config.c index 72649dd9b1..a415ca4480 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -4569,16 +4569,14 @@ test_config_parse_port_config__ports__ports_given(void *data) "127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS); tt_int_op(ret, OP_EQ, -1); - // TODO: this seems wrong. Shouldn't it be the other way around? - // Potential bug. - // Test failure for a SessionGroup argument with valid value but with stream - // options allowed + // Test failure for a SessionGroup argument with valid value but with no + // stream options allowed config_free_lines(config_port_invalid); config_port_invalid = NULL; SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf)); smartlist_clear(slout); config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=123"); ret = parse_port_config(slout, config_port_invalid, "DNS", 0, - "127.0.0.44", 0, 0); + "127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS); tt_int_op(ret, OP_EQ, -1); // Test failure for more than one SessionGroup argument @@ -4588,7 +4586,7 @@ test_config_parse_port_config__ports__ports_given(void *data) config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=123 " "SessionGroup=321"); ret = parse_port_config(slout, config_port_invalid, "DNS", 0, - "127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS); + "127.0.0.44", 0, 0); tt_int_op(ret, OP_EQ, -1); // Test success with a sessiongroup options @@ -4597,7 +4595,7 @@ test_config_parse_port_config__ports__ports_given(void *data) smartlist_clear(slout); config_port_valid = mock_config_line("DNSPort", "42 SessionGroup=1111122"); ret = parse_port_config(slout, config_port_valid, "DNS", 0, - "127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS); + "127.0.0.44", 0, 0); tt_int_op(ret, OP_EQ, 0); tt_int_op(smartlist_len(slout), OP_EQ, 1); port_cfg = (port_cfg_t *)smartlist_get(slout, 0); @@ -5066,7 +5064,7 @@ test_config_include_no_permission(void *data) chmod(dir, 0700); tor_free(dir); } -#endif +#endif /* !defined(_WIN32) */ static void test_config_include_recursion_before_after(void *data) @@ -5698,7 +5696,7 @@ test_config_compute_max_mem_in_queues(void *data) #else /* We are on a 32-bit system. */ tt_u64_op(compute_real_max_mem_in_queues(0, 0), OP_EQ, GIGABYTE(1)); -#endif +#endif /* SIZEOF_VOID_P >= 8 */ /* We are able to detect the amount of RAM on the system. */ total_system_memory_return = 0; @@ -5739,7 +5737,7 @@ test_config_compute_max_mem_in_queues(void *data) /* We will at maximum get MAX_DEFAULT_MEMORY_QUEUE_SIZE here. */ tt_u64_op(compute_real_max_mem_in_queues(0, 0), OP_EQ, MAX_DEFAULT_MEMORY_QUEUE_SIZE); -#endif +#endif /* SIZEOF_SIZE_T > 4 */ done: UNMOCK(get_total_system_memory); @@ -5886,6 +5884,61 @@ test_config_kvline_parse(void *arg) tt_assert(lines); tt_str_op(lines->key, OP_EQ, "AB"); tt_str_op(lines->value, OP_EQ, ""); + config_free_lines(lines); + + lines = kvline_parse("AB=", KV_OMIT_VALS); + tt_assert(lines); + tt_str_op(lines->key, OP_EQ, "AB"); + tt_str_op(lines->value, OP_EQ, ""); + config_free_lines(lines); + + lines = kvline_parse(" AB ", KV_OMIT_VALS); + tt_assert(lines); + tt_str_op(lines->key, OP_EQ, "AB"); + tt_str_op(lines->value, OP_EQ, ""); + config_free_lines(lines); + + lines = kvline_parse("AB", KV_OMIT_VALS); + tt_assert(lines); + tt_str_op(lines->key, OP_EQ, "AB"); + tt_str_op(lines->value, OP_EQ, ""); + enc = kvline_encode(lines, KV_OMIT_VALS); + tt_str_op(enc, OP_EQ, "AB"); + tor_free(enc); + config_free_lines(lines); + + lines = kvline_parse("AB=CD", KV_OMIT_VALS); + tt_assert(lines); + tt_str_op(lines->key, OP_EQ, "AB"); + tt_str_op(lines->value, OP_EQ, "CD"); + enc = kvline_encode(lines, KV_OMIT_VALS); + tt_str_op(enc, OP_EQ, "AB=CD"); + tor_free(enc); + config_free_lines(lines); + + lines = kvline_parse("AB=CD DE FGH=I", KV_OMIT_VALS); + 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, "DE"); + tt_str_op(lines->next->value, OP_EQ, ""); + tt_str_op(lines->next->next->key, OP_EQ, "FGH"); + tt_str_op(lines->next->next->value, OP_EQ, "I"); + enc = kvline_encode(lines, KV_OMIT_VALS); + tt_str_op(enc, OP_EQ, "AB=CD DE FGH=I"); + tor_free(enc); + config_free_lines(lines); + + lines = kvline_parse("AB=\"CD E\" DE FGH=\"I\"", KV_OMIT_VALS|KV_QUOTED); + tt_assert(lines); + tt_str_op(lines->key, OP_EQ, "AB"); + tt_str_op(lines->value, OP_EQ, "CD E"); + tt_str_op(lines->next->key, OP_EQ, "DE"); + tt_str_op(lines->next->value, OP_EQ, ""); + tt_str_op(lines->next->next->key, OP_EQ, "FGH"); + 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"); done: config_free_lines(lines); diff --git a/src/test/test_connection.h b/src/test/test_connection.h index 47a5599e5f..40121e6d38 100644 --- a/src/test/test_connection.h +++ b/src/test/test_connection.h @@ -1,6 +1,9 @@ /* Copyright (c) 2014-2019, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +#ifndef TOR_TEST_CONNECTION_H +#define TOR_TEST_CONNECTION_H + /** Some constants used by test_connection and helpers */ #define TEST_CONN_FAMILY (AF_INET) #define TEST_CONN_ADDRESS "127.0.0.1" @@ -11,3 +14,4 @@ void test_conn_lookup_addr_helper(const char *address, int family, tor_addr_t *addr); +#endif /* !defined(TOR_TEST_CONNECTION_H) */ diff --git a/src/test/test_containers.c b/src/test/test_containers.c index a0832f868e..67ba457975 100644 --- a/src/test/test_containers.c +++ b/src/test/test_containers.c @@ -606,6 +606,66 @@ test_container_smartlist_ints_eq(void *arg) smartlist_free(sl2); } +static void +test_container_smartlist_grow(void *arg) +{ + (void)arg; + smartlist_t *sl = smartlist_new(); + int i; + const char *s[] = { "first", "2nd", "3rd" }; + + /* case 1: starting from empty. */ + smartlist_grow(sl, 10); + tt_int_op(10, OP_EQ, smartlist_len(sl)); + for (i = 0; i < 10; ++i) { + tt_ptr_op(smartlist_get(sl, i), OP_EQ, NULL); + } + + /* case 2: starting with a few elements, probably not reallocating. */ + smartlist_free(sl); + sl = smartlist_new(); + smartlist_add(sl, (char*)s[0]); + smartlist_add(sl, (char*)s[1]); + smartlist_add(sl, (char*)s[2]); + smartlist_grow(sl, 5); + tt_int_op(5, OP_EQ, smartlist_len(sl)); + for (i = 0; i < 3; ++i) { + tt_ptr_op(smartlist_get(sl, i), OP_EQ, s[i]); + } + tt_ptr_op(smartlist_get(sl, 3), OP_EQ, NULL); + tt_ptr_op(smartlist_get(sl, 4), OP_EQ, NULL); + + /* case 3: starting with a few elements, but reallocating. */ + smartlist_free(sl); + sl = smartlist_new(); + smartlist_add(sl, (char*)s[0]); + smartlist_add(sl, (char*)s[1]); + smartlist_add(sl, (char*)s[2]); + smartlist_grow(sl, 100); + tt_int_op(100, OP_EQ, smartlist_len(sl)); + for (i = 0; i < 3; ++i) { + tt_ptr_op(smartlist_get(sl, i), OP_EQ, s[i]); + } + for (i = 3; i < 100; ++i) { + tt_ptr_op(smartlist_get(sl, i), OP_EQ, NULL); + } + + /* case 4: shrinking doesn't happen. */ + smartlist_free(sl); + sl = smartlist_new(); + smartlist_add(sl, (char*)s[0]); + smartlist_add(sl, (char*)s[1]); + smartlist_add(sl, (char*)s[2]); + smartlist_grow(sl, 1); + tt_int_op(3, OP_EQ, smartlist_len(sl)); + for (i = 0; i < 3; ++i) { + tt_ptr_op(smartlist_get(sl, i), OP_EQ, s[i]); + } + + done: + smartlist_free(sl); +} + /** Run unit tests for bitarray code */ static void test_container_bitarray(void *arg) @@ -946,6 +1006,10 @@ test_container_smartlist_remove(void *arg) tt_ptr_op(smartlist_get(sl, 1), OP_EQ, &array[2]); tt_ptr_op(smartlist_get(sl, 2), OP_EQ, &array[1]); tt_ptr_op(smartlist_get(sl, 3), OP_EQ, &array[2]); + /* Ordinary code should never look at this pointer; we're doing it here + * to make sure that we really cleared the pointer we removed. + */ + tt_ptr_op(sl->list[4], OP_EQ, NULL); done: smartlist_free(sl); @@ -1312,6 +1376,7 @@ struct testcase_t container_tests[] = { CONTAINER_LEGACY(smartlist_pos), CONTAINER(smartlist_remove, 0), CONTAINER(smartlist_ints_eq, 0), + CONTAINER(smartlist_grow, 0), CONTAINER_LEGACY(bitarray), CONTAINER_LEGACY(digestset), CONTAINER_LEGACY(strmap), diff --git a/src/test/test_controller.c b/src/test/test_controller.c index 5b406e159b..ee48d656bd 100644 --- a/src/test/test_controller.c +++ b/src/test/test_controller.c @@ -1,11 +1,14 @@ /* Copyright (c) 2015-2019, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#define CONTROL_PRIVATE +#define CONTROL_CMD_PRIVATE +#define CONTROL_GETINFO_PRIVATE #include "core/or/or.h" #include "lib/crypt_ops/crypto_ed25519.h" #include "feature/client/bridges.h" #include "feature/control/control.h" +#include "feature/control/control_cmd.h" +#include "feature/control/control_getinfo.h" #include "feature/client/entrynodes.h" #include "feature/hs/hs_common.h" #include "feature/nodelist/networkstatus.h" @@ -15,12 +18,189 @@ #include "test/test.h" #include "test/test_helpers.h" #include "lib/net/resolve.h" +#include "lib/encoding/confline.h" +#include "lib/encoding/kvline.h" #include "feature/control/control_connection_st.h" +#include "feature/control/control_cmd_args_st.h" #include "feature/dirclient/download_status_st.h" #include "feature/nodelist/microdesc_st.h" #include "feature/nodelist/node_st.h" +typedef struct { + const char *input; + const char *expected_parse; + const char *expected_error; +} parser_testcase_t; + +typedef struct { + const control_cmd_syntax_t *syntax; + size_t n_testcases; + const parser_testcase_t *testcases; +} parse_test_params_t; + +static char * +control_cmd_dump_args(const control_cmd_args_t *result) +{ + buf_t *buf = buf_new(); + buf_add_string(buf, "{ args=["); + if (result->args) { + if (smartlist_len(result->args)) { + buf_add_string(buf, " "); + } + SMARTLIST_FOREACH_BEGIN(result->args, const char *, s) { + const bool last = (s_sl_idx == smartlist_len(result->args)-1); + buf_add_printf(buf, "%s%s ", + escaped(s), + last ? "" : ","); + } SMARTLIST_FOREACH_END(s); + } + buf_add_string(buf, "]"); + if (result->cmddata) { + buf_add_string(buf, ", obj="); + buf_add_string(buf, escaped(result->cmddata)); + } + if (result->kwargs) { + buf_add_string(buf, ", { "); + const config_line_t *line; + for (line = result->kwargs; line; line = line->next) { + const bool last = (line->next == NULL); + buf_add_printf(buf, "%s=%s%s ", line->key, escaped(line->value), + last ? "" : ","); + } + buf_add_string(buf, "}"); + } + buf_add_string(buf, " }"); + + char *encoded = buf_extract(buf, NULL); + buf_free(buf); + return encoded; +} + +static void +test_controller_parse_cmd(void *arg) +{ + const parse_test_params_t *params = arg; + control_cmd_args_t *result = NULL; + char *error = NULL; + char *encoded = NULL; + + for (size_t i = 0; i < params->n_testcases; ++i) { + const parser_testcase_t *t = ¶ms->testcases[i]; + result = control_cmd_parse_args("EXAMPLE", + params->syntax, + strlen(t->input), + t->input, + &error); + // A valid test should expect exactly one parse or error. + tt_int_op((t->expected_parse == NULL), OP_NE, + (t->expected_error == NULL)); + // We get a result or an error, not both. + tt_int_op((result == NULL), OP_EQ, (error != NULL)); + // We got the one we expected. + tt_int_op((result == NULL), OP_EQ, (t->expected_parse == NULL)); + + if (result) { + encoded = control_cmd_dump_args(result); + tt_str_op(encoded, OP_EQ, t->expected_parse); + } else { + tt_str_op(error, OP_EQ, t->expected_error); + } + + tor_free(error); + tor_free(encoded); + control_cmd_args_free(result); + } + + done: + tor_free(error); + tor_free(encoded); + control_cmd_args_free(result); +} + +#define OK(inp, out) \ + { inp "\r\n", out, NULL } +#define ERR(inp, err) \ + { inp "\r\n", NULL, err } + +#define TESTPARAMS(syntax, array) \ + { &syntax, \ + ARRAY_LENGTH(array), \ + array } + +static const parser_testcase_t one_to_three_tests[] = { + ERR("", "Need at least 1 argument(s)"), + ERR(" \t", "Need at least 1 argument(s)"), + OK("hello", "{ args=[ \"hello\" ] }"), + OK("hello world", "{ args=[ \"hello\", \"world\" ] }"), + OK("hello world", "{ args=[ \"hello\", \"world\" ] }"), + OK(" hello world", "{ args=[ \"hello\", \"world\" ] }"), + OK(" hello world ", "{ args=[ \"hello\", \"world\" ] }"), + OK("hello there world", "{ args=[ \"hello\", \"there\", \"world\" ] }"), + ERR("why hello there world", "Cannot accept more than 3 argument(s)"), + ERR("hello\r\nworld.\r\n.", "Unexpected body"), +}; + +static const control_cmd_syntax_t one_to_three_syntax = { + .min_args=1, .max_args=3 +}; + +static const parse_test_params_t parse_one_to_three_params = + TESTPARAMS( one_to_three_syntax, one_to_three_tests ); + +// = +static const parser_testcase_t no_args_one_obj_tests[] = { + ERR("Hi there!\r\n.", "Cannot accept more than 0 argument(s)"), + ERR("", "Empty body"), + OK("\r\n", "{ args=[], obj=\"\\n\" }"), + OK("\r\nHello world\r\n", "{ args=[], obj=\"Hello world\\n\\n\" }"), + OK("\r\nHello\r\nworld\r\n", "{ args=[], obj=\"Hello\\nworld\\n\\n\" }"), + OK("\r\nHello\r\n..\r\nworld\r\n", + "{ args=[], obj=\"Hello\\n.\\nworld\\n\\n\" }"), +}; +static const control_cmd_syntax_t no_args_one_obj_syntax = { + .min_args=0, .max_args=0, + .want_cmddata=true, +}; +static const parse_test_params_t parse_no_args_one_obj_params = + TESTPARAMS( no_args_one_obj_syntax, no_args_one_obj_tests ); + +static const parser_testcase_t no_args_kwargs_tests[] = { + OK("", "{ args=[] }"), + OK(" ", "{ args=[] }"), + OK("hello there=world", "{ args=[], { hello=\"\", there=\"world\" } }"), + OK("hello there=world today", + "{ args=[], { hello=\"\", there=\"world\", today=\"\" } }"), + ERR("=Foo", "Cannot parse keyword argument(s)"), +}; +static const control_cmd_syntax_t no_args_kwargs_syntax = { + .min_args=0, .max_args=0, + .accept_keywords=true, + .kvline_flags=KV_OMIT_VALS +}; +static const parse_test_params_t parse_no_args_kwargs_params = + TESTPARAMS( no_args_kwargs_syntax, no_args_kwargs_tests ); + +static const char *one_arg_kwargs_allow_keywords[] = { + "Hello", "world", NULL +}; +static const parser_testcase_t one_arg_kwargs_tests[] = { + ERR("", "Need at least 1 argument(s)"), + OK("Hi", "{ args=[ \"Hi\" ] }"), + ERR("hello there=world", "Unrecognized keyword argument \"there\""), + OK("Hi HELLO=foo", "{ args=[ \"Hi\" ], { HELLO=\"foo\" } }"), + OK("Hi world=\"bar baz\" hello ", + "{ args=[ \"Hi\" ], { world=\"bar baz\", hello=\"\" } }"), +}; +static const control_cmd_syntax_t one_arg_kwargs_syntax = { + .min_args=1, .max_args=1, + .accept_keywords=true, + .allowed_keywords=one_arg_kwargs_allow_keywords, + .kvline_flags=KV_OMIT_VALS|KV_QUOTED, +}; +static const parse_test_params_t parse_one_arg_kwargs_params = + TESTPARAMS( one_arg_kwargs_syntax, one_arg_kwargs_tests ); + static void test_add_onion_helper_keyarg_v3(void *arg) { @@ -1543,7 +1723,7 @@ test_current_time(void *arg) static size_t n_nodelist_get_list = 0; static smartlist_t *nodes = NULL; -static smartlist_t * +static const smartlist_t * mock_nodelist_get_list(void) { n_nodelist_get_list++; @@ -1614,7 +1794,15 @@ test_getinfo_md_all(void *arg) return; } +#define PARSER_TEST(type) \ + { "parse/" #type, test_controller_parse_cmd, 0, &passthrough_setup, \ + (void*)&parse_ ## type ## _params } + struct testcase_t controller_tests[] = { + PARSER_TEST(one_to_three), + PARSER_TEST(no_args_one_obj), + PARSER_TEST(no_args_kwargs), + PARSER_TEST(one_arg_kwargs), { "add_onion_helper_keyarg_v2", test_add_onion_helper_keyarg_v2, 0, NULL, NULL }, { "add_onion_helper_keyarg_v3", test_add_onion_helper_keyarg_v3, 0, diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c index 647eac43c7..910aacace3 100644 --- a/src/test/test_controller_events.c +++ b/src/test/test_controller_events.c @@ -4,6 +4,7 @@ #define CONNECTION_PRIVATE #define TOR_CHANNEL_INTERNAL_ #define CONTROL_PRIVATE +#define CONTROL_EVENTS_PRIVATE #define OCIRC_EVENT_PRIVATE #define ORCONN_EVENT_PRIVATE #include "core/or/or.h" @@ -13,7 +14,7 @@ #include "core/or/ocirc_event.h" #include "core/or/orconn_event.h" #include "core/mainloop/connection.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "test/test.h" #include "core/or/or_circuit_st.h" diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index 0b57448bcf..178a9a5097 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -32,7 +32,7 @@ DISABLE_GCC_WARNING(redundant-decls) #include ENABLE_GCC_WARNING(redundant-decls) -#endif +#endif /* defined(ENABLE_OPENSSL) */ /** Run unit tests for Diffie-Hellman functionality. */ static void @@ -190,7 +190,7 @@ test_crypto_dh(void *arg) DH_get0_key(dh4, &pk, &sk); #else pk = dh4->pub_key; -#endif +#endif /* defined(OPENSSL_1_1_API) */ tt_assert(pk); tt_int_op(BN_num_bytes(pk), OP_LE, DH1024_KEY_LEN); tt_int_op(BN_num_bytes(pk), OP_GT, 0); @@ -207,7 +207,7 @@ test_crypto_dh(void *arg) tt_int_op(s1len, OP_GT, 0); tt_mem_op(s1, OP_EQ, s2, s1len); } -#endif +#endif /* defined(ENABLE_OPENSSL) */ done: crypto_dh_free(dh1); @@ -219,7 +219,7 @@ test_crypto_dh(void *arg) DH_free(dh4); if (pubkey_tmp) BN_free(pubkey_tmp); -#endif +#endif /* defined(ENABLE_OPENSSL) */ } static void @@ -248,7 +248,7 @@ test_crypto_openssl_version(void *arg) tt_int_op(a, OP_GE, 0); tt_int_op(b, OP_GE, 0); tt_int_op(c, OP_GE, 0); -#endif +#endif /* defined(ENABLE_NSS) */ done: ; @@ -389,7 +389,7 @@ test_crypto_aes128(void *arg) "\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff"); crypto_cipher_crypt_inplace(env1, data2, 64); - tt_assert(tor_mem_is_zero(data2, 64)); + tt_assert(fast_mem_is_zero(data2, 64)); done: tor_free(mem_op_hex_tmp); @@ -1011,13 +1011,19 @@ test_crypto_sha3_xof(void *arg) crypto_xof_free(xof); memset(out, 0, sizeof(out)); + /* Test one-function absorb/squeeze. */ + crypto_xof(out, sizeof(out), msg, sizeof(msg)); + test_memeq_hex(out, squeezed_hex); + memset(out, 0, sizeof(out)); + /* Test incremental absorb/squeeze. */ xof = crypto_xof_new(); tt_assert(xof); for (size_t i = 0; i < sizeof(msg); i++) crypto_xof_add_bytes(xof, msg + i, 1); - for (size_t i = 0; i < sizeof(out); i++) + for (size_t i = 0; i < sizeof(out); i++) { crypto_xof_squeeze_bytes(xof, out + i, 1); + } test_memeq_hex(out, squeezed_hex); done: @@ -1703,13 +1709,13 @@ test_crypto_base32_decode(void *arg) /* Encode and decode a random string. */ base32_encode(encoded, 96 + 1, plain, 60); res = base32_decode(decoded, 60, encoded, 96); - tt_int_op(res,OP_EQ, 0); + tt_int_op(res, OP_EQ, 60); tt_mem_op(plain,OP_EQ, decoded, 60); /* Encode, uppercase, and decode a random string. */ base32_encode(encoded, 96 + 1, plain, 60); tor_strupper(encoded); res = base32_decode(decoded, 60, encoded, 96); - tt_int_op(res,OP_EQ, 0); + tt_int_op(res, OP_EQ, 60); tt_mem_op(plain,OP_EQ, decoded, 60); /* Change encoded string and decode. */ if (encoded[0] == 'A' || encoded[0] == 'a') @@ -1717,12 +1723,12 @@ test_crypto_base32_decode(void *arg) else encoded[0] = 'A'; res = base32_decode(decoded, 60, encoded, 96); - tt_int_op(res,OP_EQ, 0); + tt_int_op(res, OP_EQ, 60); tt_mem_op(plain,OP_NE, decoded, 60); /* Bad encodings. */ encoded[0] = '!'; res = base32_decode(decoded, 60, encoded, 96); - tt_int_op(0, OP_GT, res); + tt_int_op(res, OP_LT, 0); done: ; @@ -2069,7 +2075,7 @@ test_crypto_curve25519_encode(void *arg) curve25519_secret_key_generate(&seckey, 0); curve25519_public_key_generate(&key1, &seckey); - tt_int_op(0, OP_EQ, curve25519_public_to_base64(buf, &key1)); + curve25519_public_to_base64(buf, &key1); tt_int_op(CURVE25519_BASE64_PADDED_LEN, OP_EQ, strlen(buf)); tt_int_op(0, OP_EQ, curve25519_public_from_base64(&key2, buf)); @@ -2128,7 +2134,7 @@ test_crypto_curve25519_persist(void *arg) tt_u64_op((uint64_t)st.st_size, OP_EQ, 32+CURVE25519_PUBKEY_LEN+CURVE25519_SECKEY_LEN); tt_assert(fast_memeq(content, "== c25519v1: testing ==", taglen)); - tt_assert(tor_mem_is_zero(content+taglen, 32-taglen)); + tt_assert(fast_mem_is_zero(content+taglen, 32-taglen)); cp = content + 32; tt_mem_op(keypair.seckey.secret_key,OP_EQ, cp, @@ -2449,13 +2455,13 @@ test_crypto_ed25519_encode(void *arg) /* Test roundtrip. */ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&kp, 0)); - tt_int_op(0, OP_EQ, ed25519_public_to_base64(buf, &kp.pubkey)); + ed25519_public_to_base64(buf, &kp.pubkey); tt_int_op(ED25519_BASE64_LEN, OP_EQ, strlen(buf)); tt_int_op(0, OP_EQ, ed25519_public_from_base64(&pk, buf)); tt_mem_op(kp.pubkey.pubkey, OP_EQ, pk.pubkey, ED25519_PUBKEY_LEN); tt_int_op(0, OP_EQ, ed25519_sign(&sig1, (const uint8_t*)"ABC", 3, &kp)); - tt_int_op(0, OP_EQ, ed25519_signature_to_base64(buf, &sig1)); + ed25519_signature_to_base64(buf, &sig1); tt_int_op(0, OP_EQ, ed25519_signature_from_base64(&sig2, buf)); tt_mem_op(sig1.sig, OP_EQ, sig2.sig, ED25519_SIG_LEN); diff --git a/src/test/test_crypto_rng.c b/src/test/test_crypto_rng.c index 23b0c66514..6b7749a889 100644 --- a/src/test/test_crypto_rng.c +++ b/src/test/test_crypto_rng.c @@ -218,6 +218,14 @@ test_crypto_rng_fast(void *arg) tt_int_op(counts[i], OP_GT, 0); } + /* per-thread rand_fast shouldn't crash or leak. */ + crypto_fast_rng_t *t_rng = get_thread_fast_rng(); + for (int i = 0; i < N; ++i) { + uint64_t u64 = crypto_fast_rng_get_uint64(t_rng, UINT64_C(1)<<40); + tt_u64_op(u64, OP_GE, 0); + tt_u64_op(u64, OP_LT, UINT64_C(1)<<40); + } + done: crypto_fast_rng_free(rng); } diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c index e24aee8930..3b20dfa587 100644 --- a/src/test/test_crypto_slow.c +++ b/src/test/test_crypto_slow.c @@ -109,7 +109,7 @@ run_s2k_tests(const unsigned flags, const unsigned type, secret_to_key_derivekey(buf3, sizeof(buf3), buf, speclen, pw1, strlen(pw1))); tt_mem_op(buf2, OP_EQ, buf3, sizeof(buf3)); - tt_assert(!tor_mem_is_zero((char*)buf2+keylen, sizeof(buf2)-keylen)); + tt_assert(!fast_mem_is_zero((char*)buf2+keylen, sizeof(buf2)-keylen)); done: ; diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 07a2641c9f..17d6db1e4d 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -8,7 +8,7 @@ #define BWAUTH_PRIVATE #define CONFIG_PRIVATE -#define CONTROL_PRIVATE +#define CONTROL_GETINFO_PRIVATE #define DIRCACHE_PRIVATE #define DIRCLIENT_PRIVATE #define DIRSERV_PRIVATE @@ -32,7 +32,7 @@ #include "core/or/versions.h" #include "feature/client/bridges.h" #include "feature/client/entrynodes.h" -#include "feature/control/control.h" +#include "feature/control/control_getinfo.h" #include "feature/dirauth/bwauth.h" #include "feature/dirauth/dirvote.h" #include "feature/dirauth/dsigs_parse.h" @@ -162,6 +162,269 @@ test_dir_nicknames(void *arg) ; } +/* Allocate and return a new routerinfo, with the fields set from the + * arguments to this function. + * + * Also sets: + * - random RSA identity and onion keys, + * - the platform field using get_platform_str(), and + * - supports_tunnelled_dir_requests to 1. + * + * If rsa_onion_keypair_out is not NULL, it is set to the onion keypair. + * The caller must free this keypair. + */ +static routerinfo_t * +basic_routerinfo_new(const char *nickname, uint32_t ipv4_addr, + uint16_t or_port, uint16_t dir_port, + uint32_t bandwidthrate, uint32_t bandwidthburst, + uint32_t bandwidthcapacity, + time_t published_on, + crypto_pk_t **rsa_onion_keypair_out) +{ + char platform[256]; + + tor_assert(nickname); + + crypto_pk_t *pk1 = NULL, *pk2 = NULL; + /* These keys are random: idx is ignored. */ + pk1 = pk_generate(0); + pk2 = pk_generate(1); + + tor_assert(pk1); + tor_assert(pk2); + + get_platform_str(platform, sizeof(platform)); + + routerinfo_t *r1 = tor_malloc_zero(sizeof(routerinfo_t)); + + r1->nickname = tor_strdup(nickname); + r1->platform = tor_strdup(platform); + + r1->addr = ipv4_addr; + r1->or_port = or_port; + r1->dir_port = dir_port; + r1->supports_tunnelled_dir_requests = 1; + + router_set_rsa_onion_pkey(pk1, &r1->onion_pkey, &r1->onion_pkey_len); + r1->identity_pkey = pk2; + + r1->bandwidthrate = bandwidthrate; + r1->bandwidthburst = bandwidthburst; + r1->bandwidthcapacity = bandwidthcapacity; + + r1->cache_info.published_on = published_on; + + if (rsa_onion_keypair_out) { + *rsa_onion_keypair_out = pk1; + } else { + crypto_pk_free(pk1); + } + + return r1; +} + +/* Allocate and return a new string containing a "router" line for r1. */ +static char * +get_new_router_line(const routerinfo_t *r1) +{ + char *line = NULL; + + tor_assert(r1); + + tor_asprintf(&line, + "router %s %s %d 0 %d\n", + r1->nickname, fmt_addr32(r1->addr), + r1->or_port, r1->dir_port); + tor_assert(line); + + return line; +} + +/* Allocate and return a new string containing a "platform" line for the + * current Tor version and OS. */ +static char * +get_new_platform_line(void) +{ + char *line = NULL; + + tor_asprintf(&line, + "platform Tor %s on %s\n", + VERSION, get_uname()); + tor_assert(line); + + return line; +} + +/* Allocate and return a new string containing a "published" line for r1. + * r1->cache_info.published_on must be between 0 and 59 seconds. */ +static char * +get_new_published_line(const routerinfo_t *r1) +{ + char *line = NULL; + + tor_assert(r1); + + tor_assert(r1->cache_info.published_on >= 0); + tor_assert(r1->cache_info.published_on <= 59); + + tor_asprintf(&line, + "published 1970-01-01 00:00:%02u\n", + (unsigned)r1->cache_info.published_on); + tor_assert(line); + + return line; +} + +/* Allocate and return a new string containing a "fingerprint" line for r1. */ +static char * +get_new_fingerprint_line(const routerinfo_t *r1) +{ + char *line = NULL; + char fingerprint[FINGERPRINT_LEN+1]; + + tor_assert(r1); + + tor_assert(!crypto_pk_get_fingerprint(r1->identity_pkey, fingerprint, 1)); + tor_assert(strlen(fingerprint) > 0); + + tor_asprintf(&line, + "fingerprint %s\n", + fingerprint); + tor_assert(line); + + return line; +} + +/* Allocate and return a new string containing an "uptime" line with uptime t. + * + * You should pass a hard-coded value to this function, because even if we made + * it reflect uptime, that still wouldn't make it right, because the two + * descriptors might be made on different seconds. + */ +static char * +get_new_uptime_line(time_t t) +{ + char *line = NULL; + + tor_asprintf(&line, + "uptime %u\n", + (unsigned)t); + tor_assert(line); + + return line; +} + +/* Allocate and return a new string containing an "bandwidth" line for r1. + */ +static char * +get_new_bandwidth_line(const routerinfo_t *r1) +{ + char *line = NULL; + + tor_assert(r1); + + tor_asprintf(&line, + "bandwidth %u %u %u\n", + r1->bandwidthrate, + r1->bandwidthburst, + r1->bandwidthcapacity); + tor_assert(line); + + return line; +} + +/* Allocate and return a new string containing a key_name block for the + * RSA key pk1. + */ +static char * +get_new_rsa_key_block(const char *key_name, crypto_pk_t *pk1) +{ + char *block = NULL; + char *pk1_str = NULL; + size_t pk1_str_len = 0; + + tor_assert(key_name); + tor_assert(pk1); + + tor_assert(!crypto_pk_write_public_key_to_string(pk1, &pk1_str, + &pk1_str_len)); + tor_assert(pk1_str); + tor_assert(pk1_str_len); + + tor_asprintf(&block, + "%s\n%s", + key_name, + pk1_str); + tor_free(pk1_str); + + tor_assert(block); + return block; +} + +/* Allocate and return a new string containing an "onion-key" block for the + * router r1. + */ +static char * +get_new_onion_key_block(const routerinfo_t *r1) +{ + char *block = NULL; + tor_assert(r1); + crypto_pk_t *pk_tmp = router_get_rsa_onion_pkey(r1->onion_pkey, + r1->onion_pkey_len); + block = get_new_rsa_key_block("onion-key", pk_tmp); + crypto_pk_free(pk_tmp); + return block; +} + +/* Allocate and return a new string containing an "signing-key" block for the + * router r1. + */ +static char * +get_new_signing_key_block(const routerinfo_t *r1) +{ + tor_assert(r1); + return get_new_rsa_key_block("signing-key", r1->identity_pkey); +} + +/* Allocate and return a new string containing an "ntor-onion-key" line for + * the curve25519 public key ntor_onion_pubkey. + */ +static char * +get_new_ntor_onion_key_line(const curve25519_public_key_t *ntor_onion_pubkey) +{ + char *line = NULL; + char cert_buf[256]; + int rv = 0; + + tor_assert(ntor_onion_pubkey); + + rv = base64_encode(cert_buf, sizeof(cert_buf), + (const char*)ntor_onion_pubkey->public_key, 32, + BASE64_ENCODE_MULTILINE); + tor_assert(rv > 0); + tor_assert(strlen(cert_buf) > 0); + + tor_asprintf(&line, + "ntor-onion-key %s", + cert_buf); + tor_assert(line); + + return line; +} + +/* Allocate and return a new string containing a "bridge-distribution-request" + * line for options. + */ +static char * +get_new_bridge_distribution_request_line(const or_options_t *options) +{ + if (options->BridgeRelay) { + return tor_strdup("bridge-distribution-request any\n"); + } else { + return tor_strdup(""); + } +} + static smartlist_t *mocked_configured_ports = NULL; /** Returns mocked_configured_ports */ @@ -171,71 +434,510 @@ mock_get_configured_ports(void) return mocked_configured_ports; } -/** Run unit tests for router descriptor generation logic. */ +static tor_cert_t * +mock_tor_cert_dup_null(const tor_cert_t *cert) +{ + (void)cert; + return NULL; +} + +static crypto_pk_t *mocked_server_identitykey = NULL; + +/* Returns mocked_server_identitykey with no checks. */ +static crypto_pk_t * +mock_get_server_identity_key(void) +{ + return mocked_server_identitykey; +} + +static crypto_pk_t *mocked_onionkey = NULL; + +/* Returns mocked_onionkey with no checks. */ +static crypto_pk_t * +mock_get_onion_key(void) +{ + return mocked_onionkey; +} + +static routerinfo_t *mocked_routerinfo = NULL; + +/* Returns 0 and sets ri_out to mocked_routerinfo. + * ri_out must not be NULL. There are no other checks. */ +static int +mock_router_build_fresh_unsigned_routerinfo(routerinfo_t **ri_out) +{ + tor_assert(ri_out); + *ri_out = mocked_routerinfo; + return 0; +} + +static ed25519_keypair_t *mocked_master_signing_key = NULL; + +/* Returns mocked_master_signing_key with no checks. */ +static const ed25519_keypair_t * +mock_get_master_signing_keypair(void) +{ + return mocked_master_signing_key; +} + +static struct tor_cert_st *mocked_signing_key_cert = NULL; + +/* Returns mocked_signing_key_cert with no checks. */ +static const struct tor_cert_st * +mock_get_master_signing_key_cert(void) +{ + return mocked_signing_key_cert; +} + +static curve25519_keypair_t *mocked_curve25519_onion_key = NULL; + +/* Returns mocked_curve25519_onion_key with no checks. */ +static const curve25519_keypair_t * +mock_get_current_curve25519_keypair(void) +{ + return mocked_curve25519_onion_key; +} + +/* Unmock get_configured_ports() and free mocked_configured_ports. */ +static void +cleanup_mock_configured_ports(void) +{ + UNMOCK(get_configured_ports); + + if (mocked_configured_ports) { + SMARTLIST_FOREACH(mocked_configured_ports, port_cfg_t *, p, tor_free(p)); + smartlist_free(mocked_configured_ports); + } +} + +/* Mock get_configured_ports() with a list containing or_port and dir_port. + * If a port is 0, don't set it. + * Only sets the minimal data required for the tests to pass. */ +static void +setup_mock_configured_ports(uint16_t or_port, uint16_t dir_port) +{ + cleanup_mock_configured_ports(); + + /* Fake just enough of an ORPort and DirPort to get by */ + MOCK(get_configured_ports, mock_get_configured_ports); + mocked_configured_ports = smartlist_new(); + + if (or_port) { + port_cfg_t *or_port_cfg = tor_malloc_zero(sizeof(*or_port_cfg)); + or_port_cfg->type = CONN_TYPE_OR_LISTENER; + or_port_cfg->addr.family = AF_INET; + or_port_cfg->port = or_port; + smartlist_add(mocked_configured_ports, or_port_cfg); + } + + if (dir_port) { + port_cfg_t *dir_port_cfg = tor_malloc_zero(sizeof(*dir_port_cfg)); + dir_port_cfg->type = CONN_TYPE_DIR_LISTENER; + dir_port_cfg->addr.family = AF_INET; + dir_port_cfg->port = dir_port; + smartlist_add(mocked_configured_ports, dir_port_cfg); + } +} + +/* Clean up the data structures and unmock the functions needed for generating + * a fresh descriptor. */ +static void +cleanup_mocks_for_fresh_descriptor(void) +{ + tor_free(get_options_mutable()->Nickname); + + mocked_server_identitykey = NULL; + UNMOCK(get_server_identity_key); + + crypto_pk_free(mocked_onionkey); + UNMOCK(get_onion_key); +} + +/* Mock the data structures and functions needed for generating a fresh + * descriptor. + * + * Sets options->Nickname from r1->nickname. + * Mocks get_server_identity_key() with r1->identity_pkey. + * + * If rsa_onion_keypair is not NULL, it is used to mock get_onion_key(). + * Otherwise, the public key in r1->onion_pkey is used to mock get_onion_key(). + */ static void -test_dir_formats(void *arg) +setup_mocks_for_fresh_descriptor(const routerinfo_t *r1, + crypto_pk_t *rsa_onion_keypair) +{ + cleanup_mocks_for_fresh_descriptor(); + + tor_assert(r1); + + /* router_build_fresh_signed_extrainfo() requires options->Nickname */ + get_options_mutable()->Nickname = tor_strdup(r1->nickname); + + /* router_build_fresh_signed_extrainfo() requires get_server_identity_key(). + * Use the same one as the call to router_dump_router_to_string() above. + */ + mocked_server_identitykey = r1->identity_pkey; + MOCK(get_server_identity_key, mock_get_server_identity_key); + + /* router_dump_and_sign_routerinfo_descriptor_body() requires + * get_onion_key(). Use the same one as r1. + */ + if (rsa_onion_keypair) { + mocked_onionkey = crypto_pk_dup_key(rsa_onion_keypair); + } else { + mocked_onionkey = router_get_rsa_onion_pkey(r1->onion_pkey, + r1->onion_pkey_len); + } + MOCK(get_onion_key, mock_get_onion_key); +} + +/* Set options based on arg. + * + * b: BridgeRelay 1 + * e: ExtraInfoStatistics 1 + * s: sets all the individual statistics options to 1 + * + * Always sets AssumeReachable to 1. + * + * Does not set ServerTransportPlugin, because it's parsed before use. + * + * Does not set BridgeRecordUsageByCountry, because the tests don't have access + * to a GeoIPFile or GeoIPv6File. */ +static void +setup_dir_formats_options(const char *arg, or_options_t *options) +{ + /* Skip reachability checks for DirPort, ORPort, and tunnelled-dir-server */ + options->AssumeReachable = 1; + + if (strchr(arg, 'b')) { + options->BridgeRelay = 1; + } + + if (strchr(arg, 'e')) { + options->ExtraInfoStatistics = 1; + } + + if (strchr(arg, 's')) { + options->DirReqStatistics = 1; + options->HiddenServiceStatistics = 1; + options->EntryStatistics = 1; + options->CellStatistics = 1; + options->ExitPortStatistics = 1; + options->ConnDirectionStatistics = 1; + options->PaddingStatistics = 1; + } +} + +/* Check that routerinfos r1 and rp1 are consistent. + * Only performs some basic checks. + */ +#define CHECK_ROUTERINFO_CONSISTENCY(r1, rp1) \ +STMT_BEGIN \ + tt_assert(r1); \ + tt_assert(rp1); \ +\ + tt_int_op(rp1->addr,OP_EQ, r1->addr); \ + tt_int_op(rp1->or_port,OP_EQ, r1->or_port); \ + tt_int_op(rp1->dir_port,OP_EQ, r1->dir_port); \ + tt_int_op(rp1->bandwidthrate,OP_EQ, r1->bandwidthrate); \ + tt_int_op(rp1->bandwidthburst,OP_EQ, r1->bandwidthburst); \ + tt_int_op(rp1->bandwidthcapacity,OP_EQ, r1->bandwidthcapacity); \ + crypto_pk_t *rp1_onion_pkey = router_get_rsa_onion_pkey(rp1->onion_pkey, \ + rp1->onion_pkey_len); \ + crypto_pk_t *r1_onion_pkey = router_get_rsa_onion_pkey(r1->onion_pkey, \ + r1->onion_pkey_len); \ + tt_int_op(crypto_pk_cmp_keys(rp1_onion_pkey, r1_onion_pkey), OP_EQ, 0); \ + crypto_pk_free(rp1_onion_pkey); \ + crypto_pk_free(r1_onion_pkey); \ + tt_int_op(crypto_pk_cmp_keys(rp1->identity_pkey, r1->identity_pkey), \ + OP_EQ, 0); \ + tt_int_op(rp1->supports_tunnelled_dir_requests, OP_EQ, \ + r1->supports_tunnelled_dir_requests); \ +STMT_END + +/* Check that routerinfo r1 and extrainfo e1 are consistent. + * Only performs some basic checks. + */ +#define CHECK_EXTRAINFO_CONSISTENCY(r1, e1) \ +STMT_BEGIN \ + tt_assert(r1); \ + tt_assert(e1); \ +\ + tt_str_op(e1->nickname, OP_EQ, r1->nickname); \ +STMT_END + +/** Run unit tests for router descriptor generation logic for a RSA-only + * router. Tor versions without ed25519 (0.2.6 and earlier) are no longer + * officially supported, but the authorities still accept their descriptors. + */ +static void +test_dir_formats_rsa(void *arg) { char *buf = NULL; - char buf2[8192]; - char platform[256]; - char fingerprint[FINGERPRINT_LEN+1]; - char *pk1_str = NULL, *pk2_str = NULL, *cp; - size_t pk1_str_len, pk2_str_len; - routerinfo_t *r1=NULL, *r2=NULL; - crypto_pk_t *pk1 = NULL, *pk2 = NULL; - routerinfo_t *rp1 = NULL, *rp2 = NULL; - addr_policy_t *ex1, *ex2; - routerlist_t *dir1 = NULL, *dir2 = NULL; + char *buf2 = NULL; + char *cp = NULL; + uint8_t *rsa_cc = NULL; - or_options_t *options = get_options_mutable(); - const addr_policy_t *p; - time_t now = time(NULL); - port_cfg_t orport, dirport; - char cert_buf[256]; - (void)arg; - pk1 = pk_generate(0); - pk2 = pk_generate(1); + routerinfo_t *r1 = NULL; + extrainfo_t *e1 = NULL; + routerinfo_t *rp1 = NULL; + extrainfo_t *ep1 = NULL; - tt_assert(pk1 && pk2); + smartlist_t *chunks = NULL; + const char *msg = NULL; + int rv = -1; + + or_options_t *options = get_options_mutable(); + setup_dir_formats_options((const char *)arg, options); hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE); - get_platform_str(platform, sizeof(platform)); - r1 = tor_malloc_zero(sizeof(routerinfo_t)); - r1->addr = 0xc0a80001u; /* 192.168.0.1 */ - r1->cache_info.published_on = 0; - r1->or_port = 9000; - r1->dir_port = 9003; - r1->supports_tunnelled_dir_requests = 1; - tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::"); - r1->ipv6_orport = 9999; - router_set_rsa_onion_pkey(pk1, &r1->onion_pkey, &r1->onion_pkey_len); - /* Fake just enough of an ntor key to get by */ + /* r1 is a minimal, RSA-only descriptor, with DirPort and IPv6 */ + r1 = basic_routerinfo_new("Magri", 0xc0a80001u /* 192.168.0.1 */, + 9000, 9003, + 1000, 5000, 10000, + 0, + NULL); + + /* Fake just enough of an ntor key to get by */ curve25519_keypair_t r1_onion_keypair; curve25519_keypair_generate(&r1_onion_keypair, 0); r1->onion_curve25519_pkey = tor_memdup(&r1_onion_keypair.pubkey, sizeof(curve25519_public_key_t)); - r1->identity_pkey = crypto_pk_dup_key(pk2); - r1->bandwidthrate = 1000; - r1->bandwidthburst = 5000; - r1->bandwidthcapacity = 10000; + + /* Now add IPv6 */ + tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::"); + r1->ipv6_orport = 9999; + r1->exit_policy = NULL; - r1->nickname = tor_strdup("Magri"); - r1->platform = tor_strdup(platform); - ex1 = tor_malloc_zero(sizeof(addr_policy_t)); - ex2 = tor_malloc_zero(sizeof(addr_policy_t)); - ex1->policy_type = ADDR_POLICY_ACCEPT; - tor_addr_from_ipv4h(&ex1->addr, 0); - ex1->maskbits = 0; - ex1->prt_min = ex1->prt_max = 80; - ex2->policy_type = ADDR_POLICY_REJECT; - tor_addr_from_ipv4h(&ex2->addr, 18<<24); - ex2->maskbits = 8; - ex2->prt_min = ex2->prt_max = 24; - r2 = tor_malloc_zero(sizeof(routerinfo_t)); - r2->addr = 0x0a030201u; /* 10.3.2.1 */ + /* XXXX+++ router_dump_to_string should really take this from ri. */ + options->ContactInfo = tor_strdup("Magri White " + ""); + + setup_mock_configured_ports(r1->or_port, r1->dir_port); + + buf = router_dump_router_to_string(r1, r1->identity_pkey, NULL, NULL, NULL); + tt_assert(buf); + + tor_free(options->ContactInfo); + cleanup_mock_configured_ports(); + + /* Synthesise a router descriptor, without the signature */ + chunks = smartlist_new(); + + smartlist_add(chunks, get_new_router_line(r1)); + smartlist_add_strdup(chunks, "or-address [1:2:3:4::]:9999\n"); + + smartlist_add(chunks, get_new_platform_line()); + smartlist_add(chunks, get_new_published_line(r1)); + smartlist_add(chunks, get_new_fingerprint_line(r1)); + + smartlist_add(chunks, get_new_uptime_line(0)); + smartlist_add(chunks, get_new_bandwidth_line(r1)); + + smartlist_add(chunks, get_new_onion_key_block(r1)); + smartlist_add(chunks, get_new_signing_key_block(r1)); + + smartlist_add_strdup(chunks, "hidden-service-dir\n"); + + smartlist_add_strdup(chunks, "contact Magri White " + "\n"); + + smartlist_add(chunks, get_new_bridge_distribution_request_line(options)); + smartlist_add(chunks, get_new_ntor_onion_key_line(&r1_onion_keypair.pubkey)); + smartlist_add_strdup(chunks, "reject *:*\n"); + smartlist_add_strdup(chunks, "tunnelled-dir-server\n"); + + smartlist_add_strdup(chunks, "router-signature\n"); + + size_t len_out = 0; + buf2 = smartlist_join_strings(chunks, "", 0, &len_out); + SMARTLIST_FOREACH(chunks, char *, s, tor_free(s)); + smartlist_free(chunks); + + tt_assert(len_out > 0); + + buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same + * twice */ + + tt_str_op(buf,OP_EQ, buf2); + tor_free(buf); + + setup_mock_configured_ports(r1->or_port, r1->dir_port); + + buf = router_dump_router_to_string(r1, r1->identity_pkey, NULL, NULL, NULL); + tt_assert(buf); + + cleanup_mock_configured_ports(); + + /* Now, try to parse buf */ + cp = buf; + rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL); + + CHECK_ROUTERINFO_CONSISTENCY(r1, rp1); + + tt_assert(rp1->policy_is_reject_star); + + tor_free(buf); + routerinfo_free(rp1); + + /* Test extrainfo creation. + * We avoid calling router_build_fresh_unsigned_routerinfo(), because it's + * too complex. Instead, we re-use the manually-created routerinfos. + */ + + /* Set up standard mocks and data */ + setup_mocks_for_fresh_descriptor(r1, NULL); + + /* router_build_fresh_signed_extrainfo() passes the result of + * get_master_signing_key_cert() directly to tor_cert_dup(), which fails on + * NULL. But we want a NULL ei->cache_info.signing_key_cert to test the + * non-ed key path. + */ + MOCK(tor_cert_dup, mock_tor_cert_dup_null); + + /* Fake just enough of an ORPort and DirPort to get by */ + setup_mock_configured_ports(r1->or_port, r1->dir_port); + + /* Test some of the low-level static functions. */ + e1 = router_build_fresh_signed_extrainfo(r1); + tt_assert(e1); + router_update_routerinfo_from_extrainfo(r1, e1); + rv = router_dump_and_sign_routerinfo_descriptor_body(r1); + tt_assert(rv == 0); + msg = ""; + rv = routerinfo_incompatible_with_extrainfo(r1->identity_pkey, e1, + &r1->cache_info, &msg); + /* If they are incompatible, fail and show the msg string */ + tt_str_op(msg, OP_EQ, ""); + tt_assert(rv == 0); + + /* Now cleanup */ + cleanup_mocks_for_fresh_descriptor(); + + UNMOCK(tor_cert_dup); + + cleanup_mock_configured_ports(); + + CHECK_EXTRAINFO_CONSISTENCY(r1, e1); + + /* Test that the signed ri is parseable */ + tt_assert(r1->cache_info.signed_descriptor_body); + cp = r1->cache_info.signed_descriptor_body; + rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL); + + CHECK_ROUTERINFO_CONSISTENCY(r1, rp1); + + tt_assert(rp1->policy_is_reject_star); + + routerinfo_free(rp1); + + /* Test that the signed ei is parseable */ + tt_assert(e1->cache_info.signed_descriptor_body); + cp = e1->cache_info.signed_descriptor_body; + ep1 = extrainfo_parse_entry_from_string((const char*)cp,NULL,1,NULL,NULL); + + CHECK_EXTRAINFO_CONSISTENCY(r1, ep1); + + /* In future tests, we could check the actual extrainfo statistics. */ + + extrainfo_free(ep1); + + done: + dirserv_free_fingerprint_list(); + + tor_free(options->ContactInfo); + tor_free(options->Nickname); + + cleanup_mock_configured_ports(); + cleanup_mocks_for_fresh_descriptor(); + + if (chunks) { + SMARTLIST_FOREACH(chunks, char *, s, tor_free(s)); + smartlist_free(chunks); + } + + routerinfo_free(r1); + routerinfo_free(rp1); + + extrainfo_free(e1); + extrainfo_free(ep1); + + tor_free(rsa_cc); + + tor_free(buf); + tor_free(buf2); +} + +/* Check that the exit policy in rp2 is as expected. */ +#define CHECK_PARSED_EXIT_POLICY(rp2) \ +STMT_BEGIN \ + tt_int_op(smartlist_len(rp2->exit_policy),OP_EQ, 2); \ + \ + p = smartlist_get(rp2->exit_policy, 0); \ + tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_ACCEPT); \ + tt_assert(tor_addr_is_null(&p->addr)); \ + tt_int_op(p->maskbits,OP_EQ, 0); \ + tt_int_op(p->prt_min,OP_EQ, 80); \ + tt_int_op(p->prt_max,OP_EQ, 80); \ + \ + p = smartlist_get(rp2->exit_policy, 1); \ + tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_REJECT); \ + tt_assert(tor_addr_eq(&p->addr, &ex2->addr)); \ + tt_int_op(p->maskbits,OP_EQ, 8); \ + tt_int_op(p->prt_min,OP_EQ, 24); \ + tt_int_op(p->prt_max,OP_EQ, 24); \ +STMT_END + +/** Run unit tests for router descriptor generation logic for a RSA + ed25519 + * router. + */ +static void +test_dir_formats_rsa_ed25519(void *arg) +{ + char *buf = NULL; + char *buf2 = NULL; + char *cp = NULL; + + crypto_pk_t *r2_onion_pkey = NULL; + char cert_buf[256]; + uint8_t *rsa_cc = NULL; + time_t now = time(NULL); + + routerinfo_t *r2 = NULL; + extrainfo_t *e2 = NULL; + routerinfo_t *r2_out = NULL; + routerinfo_t *rp2 = NULL; + extrainfo_t *ep2 = NULL; + addr_policy_t *ex1, *ex2; + const addr_policy_t *p; + + smartlist_t *chunks = NULL; + int rv = -1; + + or_options_t *options = get_options_mutable(); + setup_dir_formats_options((const char *)arg, options); + + hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE); + + /* r2 is a RSA + ed25519 descriptor, with an exit policy, but no DirPort or + * IPv6 */ + r2 = basic_routerinfo_new("Fred", 0x0a030201u /* 10.3.2.1 */, + 9005, 0, + 3000, 3000, 3000, + 5, + &r2_onion_pkey); + + /* Fake just enough of an ntor key to get by */ + curve25519_keypair_t r2_onion_keypair; + curve25519_keypair_generate(&r2_onion_keypair, 0); + r2->onion_curve25519_pkey = tor_memdup(&r2_onion_keypair.pubkey, + sizeof(curve25519_public_key_t)); + + /* Now add relay ed25519 keys + * We can't use init_mock_ed_keys() here, because the keys are seeded */ ed25519_keypair_t kp1, kp2; ed25519_secret_key_from_seed(&kp1.seckey, (const uint8_t*)"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"); @@ -248,157 +950,78 @@ test_dir_formats(void *arg) &kp2.pubkey, now, 86400, CERT_FLAG_INCLUDE_SIGNING_KEY); - r2->platform = tor_strdup(platform); - r2->cache_info.published_on = 5; - r2->or_port = 9005; - r2->dir_port = 0; - r2->supports_tunnelled_dir_requests = 1; - router_set_rsa_onion_pkey(pk2, &r2->onion_pkey, &r2->onion_pkey_len); - curve25519_keypair_t r2_onion_keypair; - curve25519_keypair_generate(&r2_onion_keypair, 0); - r2->onion_curve25519_pkey = tor_memdup(&r2_onion_keypair.pubkey, - sizeof(curve25519_public_key_t)); - r2->identity_pkey = crypto_pk_dup_key(pk1); - r2->bandwidthrate = r2->bandwidthburst = r2->bandwidthcapacity = 3000; + + /* Now add an exit policy */ + ex1 = tor_malloc_zero(sizeof(addr_policy_t)); + ex2 = tor_malloc_zero(sizeof(addr_policy_t)); + ex1->policy_type = ADDR_POLICY_ACCEPT; + tor_addr_from_ipv4h(&ex1->addr, 0); + ex1->maskbits = 0; + ex1->prt_min = ex1->prt_max = 80; + ex2->policy_type = ADDR_POLICY_REJECT; + tor_addr_from_ipv4h(&ex2->addr, 18<<24); + ex2->maskbits = 8; + ex2->prt_min = ex2->prt_max = 24; + r2->exit_policy = smartlist_new(); smartlist_add(r2->exit_policy, ex1); smartlist_add(r2->exit_policy, ex2); - r2->nickname = tor_strdup("Fred"); - - tt_assert(!crypto_pk_write_public_key_to_string(pk1, &pk1_str, - &pk1_str_len)); - tt_assert(!crypto_pk_write_public_key_to_string(pk2 , &pk2_str, - &pk2_str_len)); - - /* XXXX+++ router_dump_to_string should really take this from ri.*/ - options->ContactInfo = tor_strdup("Magri White " - ""); - /* Skip reachability checks for DirPort and tunnelled-dir-server */ - options->AssumeReachable = 1; - - /* Fake just enough of an ORPort and DirPort to get by */ - MOCK(get_configured_ports, mock_get_configured_ports); - mocked_configured_ports = smartlist_new(); - - memset(&orport, 0, sizeof(orport)); - orport.type = CONN_TYPE_OR_LISTENER; - orport.addr.family = AF_INET; - orport.port = 9000; - smartlist_add(mocked_configured_ports, &orport); - - memset(&dirport, 0, sizeof(dirport)); - dirport.type = CONN_TYPE_DIR_LISTENER; - dirport.addr.family = AF_INET; - dirport.port = 9003; - smartlist_add(mocked_configured_ports, &dirport); - buf = router_dump_router_to_string(r1, pk2, NULL, NULL, NULL); - - UNMOCK(get_configured_ports); - smartlist_free(mocked_configured_ports); - mocked_configured_ports = NULL; + /* Fake just enough of an ORPort to get by */ + setup_mock_configured_ports(r2->or_port, 0); - tor_free(options->ContactInfo); + buf = router_dump_router_to_string(r2, + r2->identity_pkey, r2_onion_pkey, + &r2_onion_keypair, &kp2); tt_assert(buf); - strlcpy(buf2, "router Magri 192.168.0.1 9000 0 9003\n" - "or-address [1:2:3:4::]:9999\n" - "platform Tor "VERSION" on ", sizeof(buf2)); - strlcat(buf2, get_uname(), sizeof(buf2)); - strlcat(buf2, "\n" - "published 1970-01-01 00:00:00\n" - "fingerprint ", sizeof(buf2)); - tt_assert(!crypto_pk_get_fingerprint(pk2, fingerprint, 1)); - strlcat(buf2, fingerprint, sizeof(buf2)); - strlcat(buf2, "\nuptime 0\n" - /* XXX the "0" above is hard-coded, but even if we made it reflect - * uptime, that still wouldn't make it right, because the two - * descriptors might be made on different seconds... hm. */ - "bandwidth 1000 5000 10000\n" - "onion-key\n", sizeof(buf2)); - strlcat(buf2, pk1_str, sizeof(buf2)); - strlcat(buf2, "signing-key\n", sizeof(buf2)); - strlcat(buf2, pk2_str, sizeof(buf2)); - strlcat(buf2, "hidden-service-dir\n", sizeof(buf2)); - strlcat(buf2, "contact Magri White \n", - sizeof(buf2)); - strlcat(buf2, "ntor-onion-key ", sizeof(buf2)); - base64_encode(cert_buf, sizeof(cert_buf), - (const char*)r1_onion_keypair.pubkey.public_key, 32, - BASE64_ENCODE_MULTILINE); - strlcat(buf2, cert_buf, sizeof(buf2)); - strlcat(buf2, "reject *:*\n", sizeof(buf2)); - strlcat(buf2, "tunnelled-dir-server\nrouter-signature\n", sizeof(buf2)); - buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same - * twice */ + cleanup_mock_configured_ports(); - tt_str_op(buf,OP_EQ, buf2); - tor_free(buf); + chunks = smartlist_new(); - buf = router_dump_router_to_string(r1, pk2, NULL, NULL, NULL); - tt_assert(buf); - cp = buf; - rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL); - tt_assert(rp1); - tt_int_op(rp1->addr,OP_EQ, r1->addr); - tt_int_op(rp1->or_port,OP_EQ, r1->or_port); - tt_int_op(rp1->dir_port,OP_EQ, r1->dir_port); - tt_int_op(rp1->bandwidthrate,OP_EQ, r1->bandwidthrate); - tt_int_op(rp1->bandwidthburst,OP_EQ, r1->bandwidthburst); - tt_int_op(rp1->bandwidthcapacity,OP_EQ, r1->bandwidthcapacity); - crypto_pk_t *onion_pkey = router_get_rsa_onion_pkey(rp1->onion_pkey, - rp1->onion_pkey_len); - tt_int_op(crypto_pk_cmp_keys(onion_pkey, pk1), OP_EQ, 0); - crypto_pk_free(onion_pkey); - tt_int_op(crypto_pk_cmp_keys(rp1->identity_pkey, pk2), OP_EQ, 0); - tt_assert(rp1->supports_tunnelled_dir_requests); - //tt_assert(rp1->exit_policy == NULL); - tor_free(buf); + /* Synthesise a router descriptor, without the signatures */ + smartlist_add(chunks, get_new_router_line(r2)); - strlcpy(buf2, - "router Fred 10.3.2.1 9005 0 0\n" - "identity-ed25519\n" - "-----BEGIN ED25519 CERT-----\n", sizeof(buf2)); + smartlist_add_strdup(chunks, + "identity-ed25519\n" + "-----BEGIN ED25519 CERT-----\n"); base64_encode(cert_buf, sizeof(cert_buf), (const char*)r2->cache_info.signing_key_cert->encoded, r2->cache_info.signing_key_cert->encoded_len, BASE64_ENCODE_MULTILINE); - strlcat(buf2, cert_buf, sizeof(buf2)); - strlcat(buf2, "-----END ED25519 CERT-----\n", sizeof(buf2)); - strlcat(buf2, "master-key-ed25519 ", sizeof(buf2)); + smartlist_add_strdup(chunks, cert_buf); + smartlist_add_strdup(chunks, "-----END ED25519 CERT-----\n"); + + smartlist_add_strdup(chunks, "master-key-ed25519 "); { char k[ED25519_BASE64_LEN+1]; - tt_int_op(ed25519_public_to_base64(k, - &r2->cache_info.signing_key_cert->signing_key), - OP_GE, 0); - strlcat(buf2, k, sizeof(buf2)); - strlcat(buf2, "\n", sizeof(buf2)); + ed25519_public_to_base64(k, &r2->cache_info.signing_key_cert->signing_key); + smartlist_add_strdup(chunks, k); + smartlist_add_strdup(chunks, "\n"); } - strlcat(buf2, "platform Tor "VERSION" on ", sizeof(buf2)); - strlcat(buf2, get_uname(), sizeof(buf2)); - strlcat(buf2, "\n" - "published 1970-01-01 00:00:05\n" - "fingerprint ", sizeof(buf2)); - tt_assert(!crypto_pk_get_fingerprint(pk1, fingerprint, 1)); - strlcat(buf2, fingerprint, sizeof(buf2)); - strlcat(buf2, "\nuptime 0\n" - "bandwidth 3000 3000 3000\n", sizeof(buf2)); - strlcat(buf2, "onion-key\n", sizeof(buf2)); - strlcat(buf2, pk2_str, sizeof(buf2)); - strlcat(buf2, "signing-key\n", sizeof(buf2)); - strlcat(buf2, pk1_str, sizeof(buf2)); + + smartlist_add(chunks, get_new_platform_line()); + smartlist_add(chunks, get_new_published_line(r2)); + smartlist_add(chunks, get_new_fingerprint_line(r2)); + + smartlist_add(chunks, get_new_uptime_line(0)); + smartlist_add(chunks, get_new_bandwidth_line(r2)); + + smartlist_add(chunks, get_new_onion_key_block(r2)); + smartlist_add(chunks, get_new_signing_key_block(r2)); + int rsa_cc_len; - rsa_cc = make_tap_onion_key_crosscert(pk2, + rsa_cc = make_tap_onion_key_crosscert(r2_onion_pkey, &kp1.pubkey, - pk1, + r2->identity_pkey, &rsa_cc_len); tt_assert(rsa_cc); base64_encode(cert_buf, sizeof(cert_buf), (char*)rsa_cc, rsa_cc_len, BASE64_ENCODE_MULTILINE); - strlcat(buf2, "onion-key-crosscert\n" - "-----BEGIN CROSSCERT-----\n", sizeof(buf2)); - strlcat(buf2, cert_buf, sizeof(buf2)); - strlcat(buf2, "-----END CROSSCERT-----\n", sizeof(buf2)); + smartlist_add_strdup(chunks, "onion-key-crosscert\n" + "-----BEGIN CROSSCERT-----\n"); + smartlist_add_strdup(chunks, cert_buf); + smartlist_add_strdup(chunks, "-----END CROSSCERT-----\n"); int ntor_cc_sign; { tor_cert_t *ntor_cc = NULL; @@ -413,112 +1036,165 @@ test_dir_formats(void *arg) BASE64_ENCODE_MULTILINE); tor_cert_free(ntor_cc); } - tor_snprintf(buf2+strlen(buf2), sizeof(buf2)-strlen(buf2), + smartlist_add_asprintf(chunks, "ntor-onion-key-crosscert %d\n" "-----BEGIN ED25519 CERT-----\n" "%s" "-----END ED25519 CERT-----\n", ntor_cc_sign, cert_buf); - strlcat(buf2, "hidden-service-dir\n", sizeof(buf2)); - strlcat(buf2, "ntor-onion-key ", sizeof(buf2)); - base64_encode(cert_buf, sizeof(cert_buf), - (const char*)r2_onion_keypair.pubkey.public_key, 32, - BASE64_ENCODE_MULTILINE); - strlcat(buf2, cert_buf, sizeof(buf2)); - strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2)); - strlcat(buf2, "tunnelled-dir-server\n", sizeof(buf2)); - strlcat(buf2, "router-sig-ed25519 ", sizeof(buf2)); + smartlist_add_strdup(chunks, "hidden-service-dir\n"); - /* Fake just enough of an ORPort to get by */ - MOCK(get_configured_ports, mock_get_configured_ports); - mocked_configured_ports = smartlist_new(); + smartlist_add(chunks, get_new_bridge_distribution_request_line(options)); + smartlist_add(chunks, get_new_ntor_onion_key_line(&r2_onion_keypair.pubkey)); + smartlist_add_strdup(chunks, "accept *:80\nreject 18.0.0.0/8:24\n"); + smartlist_add_strdup(chunks, "tunnelled-dir-server\n"); - memset(&orport, 0, sizeof(orport)); - orport.type = CONN_TYPE_OR_LISTENER; - orport.addr.family = AF_INET; - orport.port = 9005; - smartlist_add(mocked_configured_ports, &orport); + smartlist_add_strdup(chunks, "router-sig-ed25519 "); - buf = router_dump_router_to_string(r2, pk1, pk2, &r2_onion_keypair, &kp2); - tt_assert(buf); - buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same + size_t len_out = 0; + buf2 = smartlist_join_strings(chunks, "", 0, &len_out); + SMARTLIST_FOREACH(chunks, char *, s, tor_free(s)); + smartlist_free(chunks); + + tt_assert(len_out > 0); + + buf[strlen(buf2)] = '\0'; /* Don't compare either sig; they're never the same * twice */ tt_str_op(buf, OP_EQ, buf2); tor_free(buf); - buf = router_dump_router_to_string(r2, pk1, NULL, NULL, NULL); + setup_mock_configured_ports(r2->or_port, 0); - UNMOCK(get_configured_ports); - smartlist_free(mocked_configured_ports); - mocked_configured_ports = NULL; + buf = router_dump_router_to_string(r2, r2->identity_pkey, NULL, NULL, NULL); + tt_assert(buf); - /* Reset for later */ + cleanup_mock_configured_ports(); + + /* Now, try to parse buf */ cp = buf; rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL); - tt_assert(rp2); - tt_int_op(rp2->addr,OP_EQ, r2->addr); - tt_int_op(rp2->or_port,OP_EQ, r2->or_port); - tt_int_op(rp2->dir_port,OP_EQ, r2->dir_port); - tt_int_op(rp2->bandwidthrate,OP_EQ, r2->bandwidthrate); - tt_int_op(rp2->bandwidthburst,OP_EQ, r2->bandwidthburst); - tt_int_op(rp2->bandwidthcapacity,OP_EQ, r2->bandwidthcapacity); + + CHECK_ROUTERINFO_CONSISTENCY(r2, rp2); + tt_mem_op(rp2->onion_curve25519_pkey->public_key,OP_EQ, r2->onion_curve25519_pkey->public_key, CURVE25519_PUBKEY_LEN); - onion_pkey = router_get_rsa_onion_pkey(rp2->onion_pkey, - rp2->onion_pkey_len); - tt_int_op(crypto_pk_cmp_keys(onion_pkey, pk2), OP_EQ, 0); - crypto_pk_free(onion_pkey); - tt_int_op(crypto_pk_cmp_keys(rp2->identity_pkey, pk1), OP_EQ, 0); - tt_assert(rp2->supports_tunnelled_dir_requests); - - tt_int_op(smartlist_len(rp2->exit_policy),OP_EQ, 2); - - p = smartlist_get(rp2->exit_policy, 0); - tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_ACCEPT); - tt_assert(tor_addr_is_null(&p->addr)); - tt_int_op(p->maskbits,OP_EQ, 0); - tt_int_op(p->prt_min,OP_EQ, 80); - tt_int_op(p->prt_max,OP_EQ, 80); - - p = smartlist_get(rp2->exit_policy, 1); - tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_REJECT); - tt_assert(tor_addr_eq(&p->addr, &ex2->addr)); - tt_int_op(p->maskbits,OP_EQ, 8); - tt_int_op(p->prt_min,OP_EQ, 24); - tt_int_op(p->prt_max,OP_EQ, 24); - -#if 0 - /* Okay, now for the directories. */ - { - fingerprint_list = smartlist_new(); - crypto_pk_get_fingerprint(pk2, buf, 1); - add_fingerprint_to_dir(buf, fingerprint_list, 0); - crypto_pk_get_fingerprint(pk1, buf, 1); - add_fingerprint_to_dir(buf, fingerprint_list, 0); + + CHECK_PARSED_EXIT_POLICY(rp2); + + tor_free(buf); + routerinfo_free(rp2); + + /* Test extrainfo creation. */ + + /* Set up standard mocks and data */ + setup_mocks_for_fresh_descriptor(r2, r2_onion_pkey); + + /* router_build_fresh_descriptor() requires + * router_build_fresh_unsigned_routerinfo(), but the implementation is + * too complex. Instead, we re-use r2. + */ + mocked_routerinfo = r2; + MOCK(router_build_fresh_unsigned_routerinfo, + mock_router_build_fresh_unsigned_routerinfo); + + /* r2 uses ed25519, so we need to mock the ed key functions */ + mocked_master_signing_key = &kp2; + MOCK(get_master_signing_keypair, mock_get_master_signing_keypair); + + mocked_signing_key_cert = r2->cache_info.signing_key_cert; + MOCK(get_master_signing_key_cert, mock_get_master_signing_key_cert); + + mocked_curve25519_onion_key = &r2_onion_keypair; + MOCK(get_current_curve25519_keypair, mock_get_current_curve25519_keypair); + + /* Fake just enough of an ORPort to get by */ + setup_mock_configured_ports(r2->or_port, 0); + + /* Test the high-level interface. */ + rv = router_build_fresh_descriptor(&r2_out, &e2); + if (rv < 0) { + /* router_build_fresh_descriptor() frees r2 on failure. */ + r2 = NULL; + /* Get rid of an alias to rp2 */ + r2_out = NULL; } + tt_assert(rv == 0); + tt_assert(r2_out); + tt_assert(e2); + /* Guaranteed by mock_router_build_fresh_unsigned_routerinfo() */ + tt_ptr_op(r2_out, OP_EQ, r2); + /* Get rid of an alias to r2 */ + r2_out = NULL; + + /* Now cleanup */ + cleanup_mocks_for_fresh_descriptor(); + + mocked_routerinfo = NULL; + UNMOCK(router_build_fresh_unsigned_routerinfo); + mocked_master_signing_key = NULL; + UNMOCK(get_master_signing_keypair); + mocked_signing_key_cert = NULL; + UNMOCK(get_master_signing_key_cert); + mocked_curve25519_onion_key = NULL; + UNMOCK(get_current_curve25519_keypair); + + cleanup_mock_configured_ports(); + + CHECK_EXTRAINFO_CONSISTENCY(r2, e2); + + /* Test that the signed ri is parseable */ + tt_assert(r2->cache_info.signed_descriptor_body); + cp = r2->cache_info.signed_descriptor_body; + rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL); -#endif /* 0 */ - dirserv_free_fingerprint_list(); + CHECK_ROUTERINFO_CONSISTENCY(r2, rp2); + + tt_mem_op(rp2->onion_curve25519_pkey->public_key,OP_EQ, + r2->onion_curve25519_pkey->public_key, + CURVE25519_PUBKEY_LEN); + + CHECK_PARSED_EXIT_POLICY(rp2); + + routerinfo_free(rp2); + + /* Test that the signed ei is parseable */ + tt_assert(e2->cache_info.signed_descriptor_body); + cp = e2->cache_info.signed_descriptor_body; + ep2 = extrainfo_parse_entry_from_string((const char*)cp,NULL,1,NULL,NULL); + + CHECK_EXTRAINFO_CONSISTENCY(r2, ep2); + + /* In future tests, we could check the actual extrainfo statistics. */ + + extrainfo_free(ep2); done: - if (r1) - routerinfo_free(r1); - if (r2) - routerinfo_free(r2); - if (rp2) - routerinfo_free(rp2); + dirserv_free_fingerprint_list(); + + tor_free(options->Nickname); + + cleanup_mock_configured_ports(); + cleanup_mocks_for_fresh_descriptor(); + + if (chunks) { + SMARTLIST_FOREACH(chunks, char *, s, tor_free(s)); + smartlist_free(chunks); + } + + routerinfo_free(r2); + routerinfo_free(r2_out); + routerinfo_free(rp2); + + extrainfo_free(e2); + extrainfo_free(ep2); tor_free(rsa_cc); + crypto_pk_free(r2_onion_pkey); + tor_free(buf); - tor_free(pk1_str); - tor_free(pk2_str); - if (pk1) crypto_pk_free(pk1); - if (pk2) crypto_pk_free(pk2); - if (rp1) routerinfo_free(rp1); - tor_free(dir1); /* XXXX And more !*/ - tor_free(dir2); /* And more !*/ + tor_free(buf2); } #include "failing_routerdescs.inc" @@ -6546,7 +7222,22 @@ test_dir_format_versions_list(void *arg) struct testcase_t dir_tests[] = { DIR_LEGACY(nicknames), - DIR_LEGACY(formats), + /* extrainfo without any stats */ + DIR_ARG(formats_rsa, TT_FORK, ""), + DIR_ARG(formats_rsa_ed25519, TT_FORK, ""), + /* on a bridge */ + DIR_ARG(formats_rsa, TT_FORK, "b"), + DIR_ARG(formats_rsa_ed25519, TT_FORK, "b"), + /* extrainfo with basic stats */ + DIR_ARG(formats_rsa, TT_FORK, "e"), + DIR_ARG(formats_rsa_ed25519, TT_FORK, "e"), + DIR_ARG(formats_rsa, TT_FORK, "be"), + DIR_ARG(formats_rsa_ed25519, TT_FORK, "be"), + /* extrainfo with all stats */ + DIR_ARG(formats_rsa, TT_FORK, "es"), + DIR_ARG(formats_rsa_ed25519, TT_FORK, "es"), + DIR_ARG(formats_rsa, TT_FORK, "bes"), + DIR_ARG(formats_rsa_ed25519, TT_FORK, "bes"), DIR(routerinfo_parsing, 0), DIR(extrainfo_parsing, 0), DIR(parse_router_list, TT_FORK), diff --git a/src/test/test_dir_common.h b/src/test/test_dir_common.h index d6c5241b14..619dc83eb9 100644 --- a/src/test/test_dir_common.h +++ b/src/test/test_dir_common.h @@ -3,6 +3,9 @@ * Copyright (c) 2007-2019, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +#ifndef TOR_TEST_DIR_COMMON_H +#define TOR_TEST_DIR_COMMON_H + #include "core/or/or.h" #include "feature/nodelist/networkstatus.h" @@ -49,3 +52,4 @@ int dir_common_construct_vote_3(networkstatus_t **vote, networkstatus_t **vote_out, int *n_vrs, time_t now, int clear_rl); +#endif /* !defined(TOR_TEST_DIR_COMMON_H) */ diff --git a/src/test/test_dispatch.c b/src/test/test_dispatch.c new file mode 100644 index 0000000000..d6fe7e781a --- /dev/null +++ b/src/test/test_dispatch.c @@ -0,0 +1,249 @@ +/* Copyright (c) 2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define DISPATCH_PRIVATE + +#include "test/test.h" + +#include "lib/dispatch/dispatch.h" +#include "lib/dispatch/dispatch_cfg.h" +#include "lib/dispatch/dispatch_st.h" +#include "lib/dispatch/msgtypes.h" + +#include "lib/log/escape.h" +#include "lib/malloc/malloc.h" +#include "lib/string/printf.h" + +#include +#include + +static dispatch_t *dispatcher_in_use=NULL; + +/* Construct an empty dispatch_t. */ +static void +test_dispatch_empty(void *arg) +{ + (void)arg; + + dispatch_t *d=NULL; + dispatch_cfg_t *cfg=NULL; + + cfg = dcfg_new(); + d = dispatch_new(cfg); + tt_assert(d); + + done: + dispatch_free(d); + dcfg_free(cfg); +} + +static int total_recv1_simple = 0; +static int total_recv2_simple = 0; + +static void +simple_recv1(const msg_t *m) +{ + total_recv1_simple += m->aux_data__.u64; +} + +static char *recv2_received = NULL; + +static void +simple_recv2(const msg_t *m) +{ + tor_free(recv2_received); + recv2_received = dispatch_fmt_msg_data(dispatcher_in_use, m); + + total_recv2_simple += m->aux_data__.u64*10; +} + +/* Construct a dispatch_t with two messages, make sure that they both get + * delivered. */ +static void +test_dispatch_simple(void *arg) +{ + (void)arg; + + dispatch_t *d=NULL; + dispatch_cfg_t *cfg=NULL; + int r; + + cfg = dcfg_new(); + r = dcfg_msg_set_type(cfg,0,0); + r += dcfg_msg_set_chan(cfg,0,0); + r += dcfg_add_recv(cfg,0,1,simple_recv1); + r += dcfg_msg_set_type(cfg,1,0); + r += dcfg_msg_set_chan(cfg,1,0); + r += dcfg_add_recv(cfg,1,1,simple_recv2); + r += dcfg_add_recv(cfg,1,1,simple_recv2); /* second copy */ + tt_int_op(r, OP_EQ, 0); + + d = dispatch_new(cfg); + tt_assert(d); + dispatcher_in_use = d; + + msg_aux_data_t data = {.u64 = 7}; + r = dispatch_send(d, 99, 0, 0, 0, data); + tt_int_op(r, OP_EQ, 0); + tt_int_op(total_recv1_simple, OP_EQ, 0); + + r = dispatch_flush(d, 0, INT_MAX); + tt_int_op(r, OP_EQ, 0); + tt_int_op(total_recv1_simple, OP_EQ, 7); + tt_int_op(total_recv2_simple, OP_EQ, 0); + + total_recv1_simple = 0; + r = dispatch_send(d, 99, 0, 1, 0, data); + tt_int_op(r, OP_EQ, 0); + r = dispatch_flush(d, 0, INT_MAX); + tt_int_op(total_recv1_simple, OP_EQ, 0); + tt_int_op(total_recv2_simple, OP_EQ, 140); + + tt_str_op(recv2_received, OP_EQ, "<>"); // no format function was set. + + done: + dispatch_free(d); + dcfg_free(cfg); + tor_free(recv2_received); +} + +/* Construct a dispatch_t with a message and no reciever; make sure that it + * gets dropped properly. */ +static void +test_dispatch_no_recipient(void *arg) +{ + (void)arg; + + dispatch_t *d=NULL; + dispatch_cfg_t *cfg=NULL; + int r; + + cfg = dcfg_new(); + r = dcfg_msg_set_type(cfg,0,0); + r += dcfg_msg_set_chan(cfg,0,0); + tt_int_op(r, OP_EQ, 0); + + d = dispatch_new(cfg); + tt_assert(d); + dispatcher_in_use = d; + + msg_aux_data_t data = { .u64 = 7}; + r = dispatch_send(d, 99, 0, 0, 0, data); + tt_int_op(r, OP_EQ, 0); + + r = dispatch_flush(d, 0, INT_MAX); + tt_int_op(r, OP_EQ, 0); + + done: + dispatch_free(d); + dcfg_free(cfg); +} + +struct coord { int x; int y; }; +static void +free_coord(msg_aux_data_t d) +{ + tor_free(d.ptr); +} +static char * +fmt_coord(msg_aux_data_t d) +{ + char *v; + struct coord *c = d.ptr; + tor_asprintf(&v, "[%d, %d]", c->x, c->y); + return v; +} +static dispatch_typefns_t coord_fns = { + .fmt_fn = fmt_coord, + .free_fn = free_coord, +}; +static void +alert_run_immediate(dispatch_t *d, channel_id_t ch, void *arg) +{ + (void)arg; + dispatch_flush(d, ch, INT_MAX); +} + +static char *received_data=NULL; + +static void +recv_typed_data(const msg_t *m) +{ + tor_free(received_data); + received_data = dispatch_fmt_msg_data(dispatcher_in_use, m); +} + +static void +test_dispatch_with_types(void *arg) +{ + (void)arg; + + dispatch_t *d=NULL; + dispatch_cfg_t *cfg=NULL; + int r; + + cfg = dcfg_new(); + r = dcfg_msg_set_type(cfg,5,3); + r += dcfg_msg_set_chan(cfg,5,2); + r += dcfg_add_recv(cfg,5,0,recv_typed_data); + r += dcfg_type_set_fns(cfg,3,&coord_fns); + tt_int_op(r, OP_EQ, 0); + + d = dispatch_new(cfg); + tt_assert(d); + dispatcher_in_use = d; + + /* Make this message get run immediately. */ + r = dispatch_set_alert_fn(d, 2, alert_run_immediate, NULL); + tt_int_op(r, OP_EQ, 0); + + struct coord *xy = tor_malloc(sizeof(*xy)); + xy->x = 13; + xy->y = 37; + msg_aux_data_t data = {.ptr = xy}; + r = dispatch_send(d, 99/*sender*/, 2/*channel*/, 5/*msg*/, 3/*type*/, data); + tt_int_op(r, OP_EQ, 0); + tt_str_op(received_data, OP_EQ, "[13, 37]"); + + done: + dispatch_free(d); + dcfg_free(cfg); + tor_free(received_data); + dispatcher_in_use = NULL; +} + +static void +test_dispatch_bad_type_setup(void *arg) +{ + (void)arg; + static dispatch_typefns_t fns; + dispatch_cfg_t *cfg = dcfg_new(); + + tt_int_op(0, OP_EQ, dcfg_type_set_fns(cfg, 7, &coord_fns)); + + fns = coord_fns; + fns.fmt_fn = NULL; + tt_int_op(-1, OP_EQ, dcfg_type_set_fns(cfg, 7, &fns)); + + fns = coord_fns; + fns.free_fn = NULL; + tt_int_op(-1, OP_EQ, dcfg_type_set_fns(cfg, 7, &fns)); + + fns = coord_fns; + tt_int_op(0, OP_EQ, dcfg_type_set_fns(cfg, 7, &fns)); + + done: + dcfg_free(cfg); +} + +#define T(name) \ + { #name, test_dispatch_ ## name, TT_FORK, NULL, NULL } + +struct testcase_t dispatch_tests[] = { + T(empty), + T(simple), + T(no_recipient), + T(with_types), + T(bad_type_setup), + END_OF_TESTCASES +}; diff --git a/src/test/test_dns.c b/src/test/test_dns.c index 231e6965f7..51ff8729d0 100644 --- a/src/test/test_dns.c +++ b/src/test/test_dns.c @@ -67,7 +67,7 @@ NS(test_main)(void *arg) tt_assert(tor_addr_family(nameserver_addr) == AF_INET); tt_assert(tor_addr_eq_ipv4h(nameserver_addr, 0x7f000001)); -#endif +#endif /* !defined(_WIN32) */ UNMOCK(get_options); @@ -77,7 +77,7 @@ NS(test_main)(void *arg) } #undef NS_SUBMODULE -#endif +#endif /* defined(HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR) */ #define NS_SUBMODULE clip_ttl diff --git a/src/test/test_dos.c b/src/test/test_dos.c index 4756c5014e..bda9908e6c 100644 --- a/src/test/test_dos.c +++ b/src/test/test_dos.c @@ -411,7 +411,7 @@ test_dos_bucket_refill(void *arg) } tt_uint_op(current_circ_count, OP_EQ, 0); tt_uint_op(dos_stats->cc_stats.circuit_bucket, OP_EQ, current_circ_count); -#endif +#endif /* SIZEOF_TIME_T == 8 */ done: tor_free(chan); diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index 729795b674..c43b21c673 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -67,7 +67,7 @@ static networkstatus_t *dummy_consensus = NULL; static smartlist_t *big_fake_net_nodes = NULL; -static smartlist_t * +static const smartlist_t * bfn_mock_nodelist_get_list(void) { return big_fake_net_nodes; @@ -197,6 +197,7 @@ big_fake_network_setup(const struct testcase_t *testcase) n->md->exit_policy = parse_short_policy("accept 443"); } + n->nodelist_idx = smartlist_len(big_fake_net_nodes); smartlist_add(big_fake_net_nodes, n); } diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c index aeb71ec583..38aca90266 100644 --- a/src/test/test_extorport.c +++ b/src/test/test_extorport.c @@ -9,7 +9,7 @@ #include "core/mainloop/connection.h" #include "core/or/connection_or.h" #include "app/config/config.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "lib/crypt_ops/crypto_rand.h" #include "feature/relay/ext_orport.h" #include "core/mainloop/mainloop.h" @@ -18,6 +18,7 @@ #include "test/test.h" #include "test/test_helpers.h" +#include "test/rng_test_helpers.h" #ifdef HAVE_SYS_STAT_H #include @@ -176,7 +177,7 @@ test_ext_or_init_auth(void *arg) /* Shouldn't be initialized already, or our tests will be a bit * meaningless */ ext_or_auth_cookie = tor_malloc_zero(32); - tt_assert(tor_mem_is_zero((char*)ext_or_auth_cookie, 32)); + tt_assert(fast_mem_is_zero((char*)ext_or_auth_cookie, 32)); /* Now make sure we use a temporary file */ fn = get_fname("ext_cookie_file"); @@ -201,7 +202,7 @@ test_ext_or_init_auth(void *arg) tt_mem_op(cp,OP_EQ, "! Extended ORPort Auth Cookie !\x0a", 32); tt_mem_op(cp+32,OP_EQ, ext_or_auth_cookie, 32); memcpy(cookie0, ext_or_auth_cookie, 32); - tt_assert(!tor_mem_is_zero((char*)ext_or_auth_cookie, 32)); + tt_assert(!fast_mem_is_zero((char*)ext_or_auth_cookie, 32)); /* Operation should be idempotent. */ tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1)); @@ -302,16 +303,6 @@ test_ext_or_cookie_auth(void *arg) tor_free(client_hash2); } -static void -crypto_rand_return_tse_str(char *to, size_t n) -{ - if (n != 32) { - TT_FAIL(("Asked for %d bytes, not 32", (int)n)); - return; - } - memcpy(to, "te road There is always another ", 32); -} - static void test_ext_or_cookie_auth_testvec(void *arg) { @@ -326,7 +317,7 @@ test_ext_or_cookie_auth_testvec(void *arg) memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32); ext_or_auth_cookie_is_set = 1; - MOCK(crypto_rand, crypto_rand_return_tse_str); + testing_enable_prefilled_rng("te road There is always another ", 32); tt_int_op(0, OP_EQ, handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply, @@ -351,7 +342,7 @@ test_ext_or_cookie_auth_testvec(void *arg) "33b3cd77ff79bd80c2074bbf438119a2"); done: - UNMOCK(crypto_rand); + testing_disable_prefilled_rng(); tor_free(reply); tor_free(client_hash); tor_free(mem_op_hex_tmp); @@ -414,9 +405,9 @@ do_ext_or_handshake(or_connection_t *conn) CONTAINS("\x01\x00", 2); WRITE("\x01", 1); WRITE("But when I look ahead up the whi", 32); - MOCK(crypto_rand, crypto_rand_return_tse_str); + testing_enable_prefilled_rng("te road There is always another ", 32); tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn)); - UNMOCK(crypto_rand); + testing_disable_prefilled_rng(); tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH); CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b" @@ -481,9 +472,9 @@ test_ext_or_handshake(void *arg) tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn)); /* send the rest of the nonce. */ WRITE("ahead up the whi", 16); - MOCK(crypto_rand, crypto_rand_return_tse_str); + testing_enable_prefilled_rng("te road There is always another ", 32); tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn)); - UNMOCK(crypto_rand); + testing_disable_prefilled_rng(); /* We should get the right reply from the server. */ CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b" "\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21" @@ -582,7 +573,7 @@ test_ext_or_handshake(void *arg) done: UNMOCK(connection_write_to_buf_impl_); - UNMOCK(crypto_rand); + testing_disable_prefilled_rng(); if (conn) connection_free_minimal(TO_CONN(conn)); #undef CONTAINS diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c index 13de1e154b..489c257761 100644 --- a/src/test/test_helpers.c +++ b/src/test/test_helpers.c @@ -78,7 +78,7 @@ helper_setup_fake_routerlist(void) { int retval; routerlist_t *our_routerlist = NULL; - smartlist_t *our_nodelist = NULL; + const smartlist_t *our_nodelist = NULL; /* Read the file that contains our test descriptors. */ diff --git a/src/test/test_hs.c b/src/test/test_hs.c index a611b46ca6..2b69aae547 100644 --- a/src/test/test_hs.c +++ b/src/test/test_hs.c @@ -6,7 +6,7 @@ * \brief Unit tests for hidden service. **/ -#define CONTROL_PRIVATE +#define CONTROL_EVENTS_PRIVATE #define CIRCUITBUILD_PRIVATE #define RENDCOMMON_PRIVATE #define RENDSERVICE_PRIVATE @@ -15,6 +15,8 @@ #include "core/or/or.h" #include "test/test.h" #include "feature/control/control.h" +#include "feature/control/control_events.h" +#include "feature/control/control_fmt.h" #include "app/config/config.h" #include "feature/hs/hs_common.h" #include "feature/rend/rendcommon.h" @@ -321,6 +323,16 @@ test_hs_desc_event(void *arg) tt_str_op(received_msg,OP_EQ, expected_msg); tor_free(received_msg); + /* test HSDir rate limited */ + rend_query.auth_type = REND_NO_AUTH; + control_event_hsv2_descriptor_failed(&rend_query.base_, NULL, + "QUERY_RATE_LIMITED"); + expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" NO_AUTH " \ + "UNKNOWN REASON=QUERY_RATE_LIMITED\r\n"; + tt_assert(received_msg); + tt_str_op(received_msg,OP_EQ, expected_msg); + tor_free(received_msg); + /* Test invalid content with no HSDir fingerprint. */ char *exp_msg; control_event_hs_descriptor_content(rend_query.onion_address, @@ -436,7 +448,7 @@ test_hs_rend_data(void *arg) tt_int_op(client_v2->auth_type, OP_EQ, REND_BASIC_AUTH); tt_int_op(strlen(client_v2->onion_address), OP_EQ, 0); tt_mem_op(client_v2->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id)); - tt_int_op(tor_mem_is_zero(client_v2->descriptor_cookie, + tt_int_op(fast_mem_is_zero(client_v2->descriptor_cookie, sizeof(client_v2->descriptor_cookie)), OP_EQ, 1); tt_assert(client->hsdirs_fp); tt_int_op(smartlist_len(client->hsdirs_fp), OP_EQ, 0); diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c index 9182829116..d71f8b6b18 100644 --- a/src/test/test_hs_cache.c +++ b/src/test/test_hs_cache.c @@ -238,14 +238,13 @@ helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key) { char hsdir_cache_key[ED25519_BASE64_LEN+1]; - retval = ed25519_public_to_base64(hsdir_cache_key, - blinded_key); - tt_int_op(retval, OP_EQ, 0); + ed25519_public_to_base64(hsdir_cache_key, blinded_key); tor_asprintf(&hsdir_query_str, GET("/tor/hs/3/%s"), hsdir_cache_key); } /* Simulate an HTTP GET request to the HSDir */ conn = dir_connection_new(AF_INET); + tt_assert(conn); tor_addr_from_ipv4h(&conn->base_.addr, 0x7f000001); TO_CONN(conn)->linked = 1;/* Pretend the conn is encrypted :) */ retval = directory_handle_command_get(conn, hsdir_query_str, @@ -487,7 +486,7 @@ test_client_cache(void *arg) NULL, &published_desc_str); tt_int_op(retval, OP_EQ, 0); memcpy(wanted_subcredential, published_desc->subcredential, DIGEST256_LEN); - tt_assert(!tor_mem_is_zero((char*)wanted_subcredential, DIGEST256_LEN)); + tt_assert(!fast_mem_is_zero((char*)wanted_subcredential, DIGEST256_LEN)); } /* Test handle_response_fetch_hsdesc_v3() */ diff --git a/src/test/test_hs_cell.c b/src/test/test_hs_cell.c index f8af631c8b..cdcbe23e69 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, 0); + hs_service_intro_point_t *ip = service_intro_point_new(NULL); /* 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, 0); + ip = service_intro_point_new(NULL); 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_client.c b/src/test/test_hs_client.c index 2f2bb45581..0d25a98bb3 100644 --- a/src/test/test_hs_client.c +++ b/src/test/test_hs_client.c @@ -14,6 +14,7 @@ #define CIRCUITBUILD_PRIVATE #define CIRCUITLIST_PRIVATE #define CONNECTION_PRIVATE +#define CRYPT_PATH_PRIVATE #include "test/test.h" #include "test/test_helpers.h" @@ -44,6 +45,7 @@ #include "core/or/cpath_build_state_st.h" #include "core/or/crypt_path_st.h" +#include "core/or/crypt_path.h" #include "feature/dircommon/dir_connection_st.h" #include "core/or/entry_connection_st.h" #include "core/or/extend_info_st.h" @@ -241,12 +243,14 @@ test_e2e_rend_circuit_setup_legacy(void *arg) tt_int_op(retval, OP_EQ, 1); /* Check the digest algo */ - tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.f_digest), + tt_int_op( + crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest), OP_EQ, DIGEST_SHA1); - tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.b_digest), + tt_int_op( + crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest), OP_EQ, DIGEST_SHA1); - tt_assert(or_circ->cpath->crypto.f_crypto); - tt_assert(or_circ->cpath->crypto.b_crypto); + tt_assert(or_circ->cpath->pvt_crypto.f_crypto); + tt_assert(or_circ->cpath->pvt_crypto.b_crypto); /* Ensure that circ purpose was changed */ tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED); @@ -311,12 +315,14 @@ test_e2e_rend_circuit_setup(void *arg) tt_int_op(retval, OP_EQ, 1); /* Check that the crypt path has prop224 algorithm parameters */ - tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.f_digest), + tt_int_op( + crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest), OP_EQ, DIGEST_SHA3_256); - tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.b_digest), + tt_int_op( + crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest), OP_EQ, DIGEST_SHA3_256); - tt_assert(or_circ->cpath->crypto.f_crypto); - tt_assert(or_circ->cpath->crypto.b_crypto); + tt_assert(or_circ->cpath->pvt_crypto.f_crypto); + tt_assert(or_circ->cpath->pvt_crypto.b_crypto); /* Ensure that circ purpose was changed */ tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED); @@ -395,7 +401,7 @@ test_client_pick_intro(void *arg) tt_assert(fetched_desc); tt_mem_op(fetched_desc->subcredential, OP_EQ, desc->subcredential, DIGEST256_LEN); - tt_assert(!tor_mem_is_zero((char*)fetched_desc->subcredential, + tt_assert(!fast_mem_is_zero((char*)fetched_desc->subcredential, DIGEST256_LEN)); tor_free(encoded); } @@ -403,6 +409,9 @@ test_client_pick_intro(void *arg) /* 2) Mark all intro points except _the chosen one_ as failed. Then query the * desc and get a random intro: check that we got _the chosen one_. */ { + /* Tell hs_get_extend_info_from_lspecs() to skip the private address check. + */ + get_options_mutable()->ExtendAllowPrivateAddresses = 1; /* Pick the chosen intro point and get its ei */ hs_desc_intro_point_t *chosen_intro_point = smartlist_get(desc->encrypted_data.intro_points, 0); @@ -430,7 +439,7 @@ test_client_pick_intro(void *arg) for (int i = 0; i < 64; ++i) { extend_info_t *ip = client_get_random_intro(&service_kp.pubkey); tor_assert(ip); - tt_assert(!tor_mem_is_zero((char*)ip->identity_digest, DIGEST_LEN)); + tt_assert(!fast_mem_is_zero((char*)ip->identity_digest, DIGEST_LEN)); tt_mem_op(ip->identity_digest, OP_EQ, chosen_intro_ei->identity_digest, DIGEST_LEN); extend_info_free(ip); @@ -476,6 +485,18 @@ test_client_pick_intro(void *arg) SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points, hs_desc_intro_point_t *, ip) { extend_info_t *intro_ei = desc_intro_point_to_extend_info(ip); + /* desc_intro_point_to_extend_info() doesn't return IPv6 intro points + * yet, because we can't extend to them. See #24404, #24451, and #24181. + */ + if (intro_ei == NULL) { + /* Pretend we're making a direct connection, and that we can use IPv6 + */ + get_options_mutable()->ClientUseIPv6 = 1; + intro_ei = hs_get_extend_info_from_lspecs(ip->link_specifiers, + &ip->onion_key, 1); + tt_assert(tor_addr_family(&intro_ei->addr) == AF_INET6); + } + tt_assert(intro_ei); if (intro_ei) { const char *ptr; char ip_addr[TOR_ADDR_BUF_LEN]; diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c index eb7f3bfbb0..abded6021e 100644 --- a/src/test/test_hs_common.c +++ b/src/test/test_hs_common.c @@ -275,7 +275,7 @@ test_start_time_of_next_time_period(void *arg) static void cleanup_nodelist(void) { - smartlist_t *nodelist = nodelist_get_list(); + const smartlist_t *nodelist = nodelist_get_list(); SMARTLIST_FOREACH_BEGIN(nodelist, node_t *, node) { tor_free(node->md); node->md = NULL; @@ -603,6 +603,10 @@ test_desc_reupload_logic(void *arg) SMARTLIST_FOREACH(ns->routerstatus_list, routerstatus_t *, rs, routerstatus_free(rs)); smartlist_clear(ns->routerstatus_list); + if (service) { + remove_service(get_hs_service_map(), service); + hs_service_free(service); + } networkstatus_vote_free(ns); cleanup_nodelist(); hs_free_all(); diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c index ba67712f1b..7cedc987bb 100644 --- a/src/test/test_hs_control.c +++ b/src/test/test_hs_control.c @@ -6,11 +6,13 @@ * \brief Unit tests for hidden service control port event and command. **/ -#define CONTROL_PRIVATE +#define CONTROL_EVENTS_PRIVATE #include "core/or/or.h" #include "test/test.h" #include "feature/control/control.h" +#include "feature/control/control_events.h" +#include "feature/control/control_fmt.h" #include "app/config/config.h" #include "feature/hs/hs_common.h" #include "feature/hs/hs_control.h" @@ -105,8 +107,7 @@ test_hs_desc_event(void *arg) memset(&blinded_pk, 'B', sizeof(blinded_pk)); memset(&hsdir_rs, 0, sizeof(hsdir_rs)); memcpy(hsdir_rs.identity_digest, HSDIR_EXIST_ID, DIGEST_LEN); - ret = ed25519_public_to_base64(base64_blinded_pk, &blinded_pk); - tt_int_op(ret, OP_EQ, 0); + ed25519_public_to_base64(base64_blinded_pk, &blinded_pk); memcpy(&ident.identity_pk, &identity_kp.pubkey, sizeof(ed25519_public_key_t)); memcpy(&ident.blinded_pk, &blinded_pk, sizeof(blinded_pk)); diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c index de584ed47a..6fe5573c0f 100644 --- a/src/test/test_hs_descriptor.c +++ b/src/test/test_hs_descriptor.c @@ -21,6 +21,7 @@ #include "test/hs_test_helpers.h" #include "test/test_helpers.h" #include "test/log_test_helpers.h" +#include "test/rng_test_helpers.h" #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS DISABLE_GCC_WARNING(overlength-strings) @@ -30,13 +31,6 @@ DISABLE_GCC_WARNING(overlength-strings) #include "test_hs_descriptor.inc" ENABLE_GCC_WARNING(overlength-strings) -/* Mock function to fill all bytes with 1 */ -static void -mock_crypto_strongest_rand(uint8_t *out, size_t out_len) -{ - memset(out, 1, out_len); -} - /* Test certificate encoding put in a descriptor. */ static void test_cert_encoding(void *arg) @@ -132,7 +126,7 @@ test_descriptor_padding(void *arg) tt_assert(padded_plaintext); tor_free(plaintext); /* Make sure our padding has been zeroed. */ - tt_int_op(tor_mem_is_zero((char *) padded_plaintext + plaintext_len, + tt_int_op(fast_mem_is_zero((char *) padded_plaintext + plaintext_len, padded_len - plaintext_len), OP_EQ, 1); tor_free(padded_plaintext); /* Never never have a padded length smaller than the plaintext. */ @@ -149,7 +143,7 @@ test_descriptor_padding(void *arg) tt_assert(padded_plaintext); tor_free(plaintext); /* Make sure our padding has been zeroed. */ - tt_int_op(tor_mem_is_zero((char *) padded_plaintext + plaintext_len, + tt_int_op(fast_mem_is_zero((char *) padded_plaintext + plaintext_len, padded_len - plaintext_len), OP_EQ, 1); tor_free(padded_plaintext); /* Never never have a padded length smaller than the plaintext. */ @@ -166,7 +160,7 @@ test_descriptor_padding(void *arg) tt_assert(padded_plaintext); tor_free(plaintext); /* Make sure our padding has been zeroed. */ - tt_int_op(tor_mem_is_zero((char *) padded_plaintext + plaintext_len, + tt_int_op(fast_mem_is_zero((char *) padded_plaintext + plaintext_len, padded_len - plaintext_len), OP_EQ, 1); tor_free(padded_plaintext); /* Never never have a padded length smaller than the plaintext. */ @@ -178,115 +172,6 @@ test_descriptor_padding(void *arg) return; } -static void -test_link_specifier(void *arg) -{ - ssize_t ret; - hs_desc_link_specifier_t spec; - smartlist_t *link_specifiers = smartlist_new(); - char buf[256]; - char *b64 = NULL; - link_specifier_t *ls = NULL; - - (void) arg; - - /* Always this port. */ - spec.u.ap.port = 42; - smartlist_add(link_specifiers, &spec); - - /* Test IPv4 for starter. */ - { - uint32_t ipv4; - - spec.type = LS_IPV4; - ret = tor_addr_parse(&spec.u.ap.addr, "1.2.3.4"); - tt_int_op(ret, OP_EQ, AF_INET); - b64 = encode_link_specifiers(link_specifiers); - tt_assert(b64); - - /* Decode it and validate the format. */ - ret = base64_decode(buf, sizeof(buf), b64, strlen(b64)); - tt_int_op(ret, OP_GT, 0); - /* First byte is the number of link specifier. */ - tt_int_op(get_uint8(buf), OP_EQ, 1); - ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1); - tt_int_op(ret, OP_EQ, 8); - /* Should be 2 bytes for port and 4 bytes for IPv4. */ - tt_int_op(link_specifier_get_ls_len(ls), OP_EQ, 6); - ipv4 = link_specifier_get_un_ipv4_addr(ls); - tt_int_op(tor_addr_to_ipv4h(&spec.u.ap.addr), OP_EQ, ipv4); - tt_int_op(link_specifier_get_un_ipv4_port(ls), OP_EQ, spec.u.ap.port); - - link_specifier_free(ls); - ls = NULL; - tor_free(b64); - } - - /* Test IPv6. */ - { - uint8_t ipv6[16]; - - spec.type = LS_IPV6; - ret = tor_addr_parse(&spec.u.ap.addr, "[1:2:3:4::]"); - tt_int_op(ret, OP_EQ, AF_INET6); - b64 = encode_link_specifiers(link_specifiers); - tt_assert(b64); - - /* Decode it and validate the format. */ - ret = base64_decode(buf, sizeof(buf), b64, strlen(b64)); - tt_int_op(ret, OP_GT, 0); - /* First byte is the number of link specifier. */ - tt_int_op(get_uint8(buf), OP_EQ, 1); - ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1); - tt_int_op(ret, OP_EQ, 20); - /* Should be 2 bytes for port and 16 bytes for IPv6. */ - tt_int_op(link_specifier_get_ls_len(ls), OP_EQ, 18); - for (unsigned int i = 0; i < sizeof(ipv6); i++) { - ipv6[i] = link_specifier_get_un_ipv6_addr(ls, i); - } - tt_mem_op(tor_addr_to_in6_addr8(&spec.u.ap.addr), OP_EQ, ipv6, - sizeof(ipv6)); - tt_int_op(link_specifier_get_un_ipv6_port(ls), OP_EQ, spec.u.ap.port); - - link_specifier_free(ls); - ls = NULL; - tor_free(b64); - } - - /* Test legacy. */ - { - uint8_t *id; - - spec.type = LS_LEGACY_ID; - memset(spec.u.legacy_id, 'Y', sizeof(spec.u.legacy_id)); - b64 = encode_link_specifiers(link_specifiers); - tt_assert(b64); - - /* Decode it and validate the format. */ - ret = base64_decode(buf, sizeof(buf), b64, strlen(b64)); - tt_int_op(ret, OP_GT, 0); - /* First byte is the number of link specifier. */ - tt_int_op(get_uint8(buf), OP_EQ, 1); - ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1); - /* 20 bytes digest + 1 byte type + 1 byte len. */ - tt_int_op(ret, OP_EQ, 22); - tt_int_op(link_specifier_getlen_un_legacy_id(ls), OP_EQ, DIGEST_LEN); - /* Digest length is 20 bytes. */ - tt_int_op(link_specifier_get_ls_len(ls), OP_EQ, DIGEST_LEN); - id = link_specifier_getarray_un_legacy_id(ls); - tt_mem_op(spec.u.legacy_id, OP_EQ, id, DIGEST_LEN); - - link_specifier_free(ls); - ls = NULL; - tor_free(b64); - } - - done: - link_specifier_free(ls); - tor_free(b64); - smartlist_free(link_specifiers); -} - static void test_encode_descriptor(void *arg) { @@ -848,8 +733,7 @@ test_desc_signature(void *arg) ret = ed25519_sign_prefixed(&sig, (const uint8_t *) data, strlen(data), "Tor onion service descriptor sig v3", &kp); tt_int_op(ret, OP_EQ, 0); - ret = ed25519_signature_to_base64(sig_b64, &sig); - tt_int_op(ret, OP_EQ, 0); + ed25519_signature_to_base64(sig_b64, &sig); /* Build the descriptor that should be valid. */ tor_asprintf(&desc, "%ssignature %s\n", data, sig_b64); ret = desc_sig_is_valid(sig_b64, &kp.pubkey, desc, strlen(desc)); @@ -909,7 +793,7 @@ test_build_authorized_client(void *arg) client_pubkey_b16, strlen(client_pubkey_b16)); - MOCK(crypto_strongest_rand_, mock_crypto_strongest_rand); + testing_enable_prefilled_rng("\x01", 1); hs_desc_build_authorized_client(subcredential, &client_auth_pk, &auth_ephemeral_sk, @@ -925,15 +809,13 @@ test_build_authorized_client(void *arg) done: tor_free(desc_client); tor_free(mem_op_hex_tmp); - UNMOCK(crypto_strongest_rand_); + testing_disable_prefilled_rng(); } struct testcase_t hs_descriptor[] = { /* Encoding tests. */ { "cert_encoding", test_cert_encoding, TT_FORK, NULL, NULL }, - { "link_specifier", test_link_specifier, TT_FORK, - NULL, NULL }, { "encode_descriptor", test_encode_descriptor, TT_FORK, NULL, NULL }, { "descriptor_padding", test_descriptor_padding, TT_FORK, diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c index 558fc32c54..732836fb5b 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, 0); + ip = service_intro_point_new(NULL); 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, 0); + ip = service_intro_point_new(NULL); 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 43bf894383..a303f10411 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -21,6 +21,7 @@ #define STATEFILE_PRIVATE #define TOR_CHANNEL_INTERNAL_ #define HS_CLIENT_PRIVATE +#define CRYPT_PATH_PRIVATE #include "test/test.h" #include "test/test_helpers.h" @@ -60,6 +61,7 @@ #include "core/or/cpath_build_state_st.h" #include "core/or/crypt_path_st.h" +#include "core/or/crypt_path.h" #include "feature/nodelist/networkstatus_st.h" #include "feature/nodelist/node_st.h" #include "core/or/origin_circuit_st.h" @@ -193,12 +195,14 @@ test_e2e_rend_circuit_setup(void *arg) tt_int_op(retval, OP_EQ, 1); /* Check the digest algo */ - tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.f_digest), + tt_int_op( + crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.f_digest), OP_EQ, DIGEST_SHA3_256); - tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->crypto.b_digest), + tt_int_op( + crypto_digest_get_algorithm(or_circ->cpath->pvt_crypto.b_digest), OP_EQ, DIGEST_SHA3_256); - tt_assert(or_circ->cpath->crypto.f_crypto); - tt_assert(or_circ->cpath->crypto.b_crypto); + tt_assert(or_circ->cpath->pvt_crypto.f_crypto); + tt_assert(or_circ->cpath->pvt_crypto.b_crypto); /* Ensure that circ purpose was changed */ tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_S_REND_JOINED); @@ -328,17 +332,18 @@ helper_create_service_with_clients(int num_clients) 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, 0); + link_specifier_t *ls; + hs_service_intro_point_t *ip = service_intro_point_new(NULL); tor_assert(ip); /* Add a first unused link specifier. */ - ls = tor_malloc_zero(sizeof(*ls)); - ls->type = LS_IPV4; + ls = link_specifier_new(); + link_specifier_set_ls_type(ls, LS_IPV4); smartlist_add(ip->base.link_specifiers, ls); /* Add a second link specifier used by a test. */ - ls = tor_malloc_zero(sizeof(*ls)); - ls->type = LS_LEGACY_ID; - memset(ls->u.legacy_id, 'A', sizeof(ls->u.legacy_id)); + ls = link_specifier_new(); + link_specifier_set_ls_type(ls, LS_LEGACY_ID); + memset(link_specifier_getarray_un_legacy_id(ls), 'A', + link_specifier_getlen_un_legacy_id(ls)); smartlist_add(ip->base.link_specifiers, ls); return ip; @@ -392,11 +397,11 @@ test_load_keys(void *arg) tt_assert(s); /* Ok we have the service object. Validate few things. */ - tt_assert(!tor_mem_is_zero(s->onion_address, sizeof(s->onion_address))); + tt_assert(!fast_mem_is_zero(s->onion_address, sizeof(s->onion_address))); tt_int_op(hs_address_is_valid(s->onion_address), OP_EQ, 1); - tt_assert(!tor_mem_is_zero((char *) s->keys.identity_sk.seckey, + tt_assert(!fast_mem_is_zero((char *) s->keys.identity_sk.seckey, ED25519_SECKEY_LEN)); - tt_assert(!tor_mem_is_zero((char *) s->keys.identity_pk.pubkey, + tt_assert(!fast_mem_is_zero((char *) s->keys.identity_pk.pubkey, ED25519_PUBKEY_LEN)); /* Check onion address from identity key. */ hs_build_address(&s->keys.identity_pk, s->config.version, addr); @@ -676,7 +681,7 @@ test_service_intro_point(void *arg) ip = helper_create_service_ip(); tt_assert(ip); /* Make sure the authentication keypair is not zeroes. */ - tt_int_op(tor_mem_is_zero((const char *) &ip->auth_key_kp, + tt_int_op(fast_mem_is_zero((const char *) &ip->auth_key_kp, sizeof(ed25519_keypair_t)), OP_EQ, 0); /* The introduce2_max MUST be in that range. */ tt_u64_op(ip->introduce2_max, OP_GE, @@ -811,10 +816,11 @@ test_helper_functions(void *arg) const node_t *node = get_node_from_intro_point(ip); tt_ptr_op(node, OP_EQ, &mock_node); SMARTLIST_FOREACH_BEGIN(ip->base.link_specifiers, - hs_desc_link_specifier_t *, ls) { - if (ls->type == LS_LEGACY_ID) { + link_specifier_t *, ls) { + if (link_specifier_get_ls_type(ls) == LS_LEGACY_ID) { /* Change legacy id in link specifier which is not the mock node. */ - memset(ls->u.legacy_id, 'B', sizeof(ls->u.legacy_id)); + memset(link_specifier_getarray_un_legacy_id(ls), 'B', + link_specifier_getlen_un_legacy_id(ls)); } } SMARTLIST_FOREACH_END(ls); node = get_node_from_intro_point(ip); @@ -872,6 +878,10 @@ test_helper_functions(void *arg) done: /* This will free the service and all objects associated to it. */ + if (service) { + remove_service(get_hs_service_map(), service); + hs_service_free(service); + } hs_service_free_all(); UNMOCK(node_get_by_id); } @@ -881,7 +891,7 @@ static void test_intro_circuit_opened(void *arg) { int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL; - hs_service_t *service; + hs_service_t *service = NULL; origin_circuit_t *circ = NULL; (void) arg; @@ -929,6 +939,10 @@ test_intro_circuit_opened(void *arg) done: circuit_free_(TO_CIRCUIT(circ)); + if (service) { + remove_service(get_hs_service_map(), service); + hs_service_free(service); + } hs_free_all(); UNMOCK(circuit_mark_for_close_); UNMOCK(relay_send_command_from_edge_); @@ -943,7 +957,7 @@ test_intro_established(void *arg) int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL; uint8_t payload[RELAY_PAYLOAD_SIZE] = {0}; origin_circuit_t *circ = NULL; - hs_service_t *service; + hs_service_t *service = NULL; hs_service_intro_point_t *ip = NULL; (void) arg; @@ -1004,6 +1018,10 @@ test_intro_established(void *arg) done: if (circ) circuit_free_(TO_CIRCUIT(circ)); + if (service) { + remove_service(get_hs_service_map(), service); + hs_service_free(service); + } hs_free_all(); UNMOCK(circuit_mark_for_close_); } @@ -1015,7 +1033,7 @@ test_rdv_circuit_opened(void *arg) { int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL; origin_circuit_t *circ = NULL; - hs_service_t *service; + hs_service_t *service = NULL; (void) arg; @@ -1046,6 +1064,10 @@ test_rdv_circuit_opened(void *arg) done: circuit_free_(TO_CIRCUIT(circ)); + if (service) { + remove_service(get_hs_service_map(), service); + hs_service_free(service); + } hs_free_all(); UNMOCK(circuit_mark_for_close_); UNMOCK(relay_send_command_from_edge_); @@ -1133,6 +1155,10 @@ test_closing_intro_circs(void *arg) circuit_free_(TO_CIRCUIT(intro_circ)); } /* Frees the service object. */ + if (service) { + remove_service(get_hs_service_map(), service); + hs_service_free(service); + } hs_free_all(); UNMOCK(assert_circuit_ok); } @@ -1145,7 +1171,7 @@ test_introduce2(void *arg) int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL; uint8_t payload[RELAY_PAYLOAD_SIZE] = {0}; origin_circuit_t *circ = NULL; - hs_service_t *service; + hs_service_t *service = NULL; hs_service_intro_point_t *ip = NULL; (void) arg; @@ -1212,6 +1238,10 @@ test_introduce2(void *arg) dummy_state = NULL; if (circ) circuit_free_(TO_CIRCUIT(circ)); + if (service) { + remove_service(get_hs_service_map(), service); + hs_service_free(service); + } hs_free_all(); UNMOCK(circuit_mark_for_close_); } @@ -1296,6 +1326,10 @@ test_service_event(void *arg) done: hs_circuitmap_remove_circuit(TO_CIRCUIT(circ)); circuit_free_(TO_CIRCUIT(circ)); + if (service) { + remove_service(get_hs_service_map(), service); + hs_service_free(service); + } hs_free_all(); UNMOCK(circuit_mark_for_close_); } @@ -1306,7 +1340,7 @@ test_rotate_descriptors(void *arg) { int ret; time_t next_rotation_time, now; - hs_service_t *service; + hs_service_t *service = NULL; hs_service_descriptor_t *desc_next; (void) arg; @@ -1398,6 +1432,10 @@ test_rotate_descriptors(void *arg) tt_assert(service->desc_next); done: + if (service) { + remove_service(get_hs_service_map(), service); + hs_service_free(service); + } hs_free_all(); UNMOCK(get_or_state); UNMOCK(circuit_mark_for_close_); @@ -1411,7 +1449,7 @@ test_build_update_descriptors(void *arg) { int ret; node_t *node; - hs_service_t *service; + hs_service_t *service = NULL; hs_service_intro_point_t *ip_cur, *ip_next; routerinfo_t ri; @@ -1560,9 +1598,9 @@ test_build_update_descriptors(void *arg) tt_int_op(smartlist_len(ip_cur->base.link_specifiers), OP_EQ, 3); /* Make sure we have a valid encryption keypair generated when we pick an * intro point in the update process. */ - tt_assert(!tor_mem_is_zero((char *) ip_cur->enc_key_kp.seckey.secret_key, + tt_assert(!fast_mem_is_zero((char *) ip_cur->enc_key_kp.seckey.secret_key, CURVE25519_SECKEY_LEN)); - tt_assert(!tor_mem_is_zero((char *) ip_cur->enc_key_kp.pubkey.public_key, + tt_assert(!fast_mem_is_zero((char *) ip_cur->enc_key_kp.pubkey.public_key, CURVE25519_PUBKEY_LEN)); tt_u64_op(ip_cur->time_to_expire, OP_GE, now + INTRO_POINT_LIFETIME_MIN_SECONDS); @@ -1628,6 +1666,10 @@ test_build_update_descriptors(void *arg) tt_u64_op(service->desc_next->next_upload_time, OP_EQ, 0); done: + if (service) { + remove_service(get_hs_service_map(), service); + hs_service_free(service); + } hs_free_all(); nodelist_free_all(); } @@ -1882,9 +1924,9 @@ test_rendezvous1_parsing(void *arg) } /* Send out the RENDEZVOUS1 and make sure that our mock func worked */ - tt_assert(tor_mem_is_zero(rend1_payload, 32)); + tt_assert(fast_mem_is_zero(rend1_payload, 32)); hs_circ_service_rp_has_opened(service, service_circ); - tt_assert(!tor_mem_is_zero(rend1_payload, 32)); + tt_assert(!fast_mem_is_zero(rend1_payload, 32)); tt_int_op(rend1_payload_len, OP_EQ, HS_LEGACY_RENDEZVOUS_CELL_SIZE); /******************************/ diff --git a/src/test/test_key_expiration.sh b/src/test/test_key_expiration.sh index 3474210607..54abb4a2fa 100755 --- a/src/test/test_key_expiration.sh +++ b/src/test/test_key_expiration.sh @@ -6,14 +6,14 @@ umask 077 set -e -if [ $# -eq 0 ] || [ ! -f ${1} ] || [ ! -x ${1} ]; then +if [ $# -eq 0 ] || [ ! -f "${1}" ] || [ ! -x "${1}" ]; then if [ "$TESTING_TOR_BINARY" = "" ] ; then echo "Usage: ${0} PATH_TO_TOR [case-number]" exit 1 fi fi -UNAME_OS=`uname -s | cut -d_ -f1` +UNAME_OS=$(uname -s | cut -d_ -f1) if test "$UNAME_OS" = 'CYGWIN' || \ test "$UNAME_OS" = 'MSYS' || \ test "$UNAME_OS" = 'MINGW'; then @@ -47,11 +47,11 @@ dump() { xxd -p "$1" | tr -d '\n '; } die() { echo "$1" >&2 ; exit 5; } check_dir() { [ -d "$1" ] || die "$1 did not exist"; } check_file() { [ -e "$1" ] || die "$1 did not exist"; } -check_no_file() { [ -e "$1" ] && die "$1 was not supposed to exist" || true; } -check_files_eq() { cmp "$1" "$2" || die "$1 and $2 did not match: `dump $1` vs `dump $2`"; } +check_no_file() { if [ -e "$1" ]; then die "$1 was not supposed to exist"; fi } +check_files_eq() { cmp "$1" "$2" || die "$1 and $2 did not match: $(dump "$1") vs $(dump "$2")"; } check_keys_eq() { check_files_eq "${SRC}/keys/${1}" "${ME}/keys/${1}"; } -DATA_DIR=`mktemp -d -t tor_key_expiration_tests.XXXXXX` +DATA_DIR=$(mktemp -d -t tor_key_expiration_tests.XXXXXX) if [ -z "$DATA_DIR" ]; then echo "Failure: mktemp invocation returned empty string" >&2 exit 3 @@ -60,10 +60,10 @@ if [ ! -d "$DATA_DIR" ]; then echo "Failure: mktemp invocation result doesn't point to directory" >&2 exit 3 fi -trap "rm -rf '$DATA_DIR'" 0 +trap 'rm -rf "$DATA_DIR"' 0 # Use an absolute path for this or Tor will complain -DATA_DIR=`cd "${DATA_DIR}" && pwd` +DATA_DIR=$(cd "${DATA_DIR}" && pwd) touch "${DATA_DIR}/empty_torrc" touch "${DATA_DIR}/empty_defaults_torrc" diff --git a/src/test/test_keygen.sh b/src/test/test_keygen.sh index 7afff271cb..cbdfd1909c 100755 --- a/src/test/test_keygen.sh +++ b/src/test/test_keygen.sh @@ -6,14 +6,14 @@ umask 077 set -e -if [ $# -eq 0 ] || [ ! -f ${1} ] || [ ! -x ${1} ]; then +if [ $# -eq 0 ] || [ ! -f "${1}" ] || [ ! -x "${1}" ]; then if [ "$TESTING_TOR_BINARY" = "" ] ; then echo "Usage: ${0} PATH_TO_TOR [case-number]" exit 1 fi fi -UNAME_OS=`uname -s | cut -d_ -f1` +UNAME_OS=$(uname -s | cut -d_ -f1) if test "$UNAME_OS" = 'CYGWIN' || \ test "$UNAME_OS" = 'MSYS' || \ test "$UNAME_OS" = 'MINGW'; then @@ -64,11 +64,11 @@ dump() { xxd -p "$1" | tr -d '\n '; } die() { echo "$1" >&2 ; exit 5; } check_dir() { [ -d "$1" ] || die "$1 did not exist"; } check_file() { [ -e "$1" ] || die "$1 did not exist"; } -check_no_file() { [ -e "$1" ] && die "$1 was not supposed to exist" || true; } -check_files_eq() { cmp "$1" "$2" || die "$1 and $2 did not match: `dump $1` vs `dump $2`"; } +check_no_file() { if [ -e "$1" ]; then die "$1 was not supposed to exist"; fi } +check_files_eq() { cmp "$1" "$2" || die "$1 and $2 did not match: $(dump "$1") vs $(dump "$2")"; } check_keys_eq() { check_files_eq "${SRC}/keys/${1}" "${ME}/keys/${1}"; } -DATA_DIR=`mktemp -d -t tor_keygen_tests.XXXXXX` +DATA_DIR=$(mktemp -d -t tor_keygen_tests.XXXXXX) if [ -z "$DATA_DIR" ]; then echo "Failure: mktemp invocation returned empty string" >&2 exit 3 @@ -77,10 +77,10 @@ if [ ! -d "$DATA_DIR" ]; then echo "Failure: mktemp invocation result doesn't point to directory" >&2 exit 3 fi -trap "rm -rf '$DATA_DIR'" 0 +trap 'rm -rf "$DATA_DIR"' 0 # Use an absolute path for this or Tor will complain -DATA_DIR=`cd "${DATA_DIR}" && pwd` +DATA_DIR=$(cd "${DATA_DIR}" && pwd) touch "${DATA_DIR}/empty_torrc" touch "${DATA_DIR}/empty_defaults_torrc" @@ -144,7 +144,9 @@ ME="${DATA_DIR}/case2a" SRC="${DATA_DIR}/orig" mkdir -p "${ME}/keys" cp "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint > "${ME}/stdout" && die "Somehow succeeded when missing secret key, certs: `cat ${ME}/stdout`" || true +if ${TOR} --DataDirectory "${ME}" --list-fingerprint > "${ME}/stdout"; then + die "Somehow succeeded when missing secret key, certs: $(cat "${ME}/stdout")" +fi check_files_eq "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/ed25519_master_id_public_key" grep "We needed to load a secret key.*but couldn't find it" "${ME}/stdout" >/dev/null || die "Tor didn't declare that it was missing a secret key" @@ -281,7 +283,9 @@ SRC="${DATA_DIR}/encrypted" mkdir -p "${ME}/keys" cp "${SRC}/keys/ed25519_master_id_secret_key_encrypted" "${ME}/keys/" cp "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint > "${ME}/stdout" && die "Tor started with encrypted secret key and no certs" || true +if ${TOR} --DataDirectory "${ME}" --list-fingerprint > "${ME}/stdout"; then + die "Tor started with encrypted secret key and no certs" +fi check_no_file "${ME}/keys/ed25519_signing_cert" check_no_file "${ME}/keys/ed25519_signing_secret_key" @@ -370,7 +374,9 @@ mkdir -p "${ME}/keys" cp "${SRC}/keys/ed25519_master_id_public_key" "${ME}/keys/" cp "${OTHER}/keys/ed25519_master_id_secret_key" "${ME}/keys/" -${TOR} --DataDirectory "${ME}" --list-fingerprint >"${ME}/stdout" && die "Successfully started with mismatched keys!?" || true +if ${TOR} --DataDirectory "${ME}" --list-fingerprint >"${ME}/stdout"; then + die "Successfully started with mismatched keys!?" +fi grep "public_key does not match.*secret_key" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a key mismatch" @@ -386,7 +392,9 @@ ME="${DATA_DIR}/case11a" mkdir -p "${ME}/keys" -${TOR} --DataDirectory "${ME}" --passphrase-fd 1 > "${ME}/stdout" && die "Successfully started with passphrase-fd but no keygen?" || true +if ${TOR} --DataDirectory "${ME}" --passphrase-fd 1 > "${ME}/stdout"; then + die "Successfully started with passphrase-fd but no keygen?" +fi grep "passphrase-fd specified without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments." @@ -402,7 +410,9 @@ ME="${DATA_DIR}/case11b" mkdir -p "${ME}/keys" -${TOR} --DataDirectory "${ME}" --no-passphrase > "${ME}/stdout" && die "Successfully started with no-passphrase but no keygen?" || true +if ${TOR} --DataDirectory "${ME}" --no-passphrase > "${ME}/stdout"; then + die "Successfully started with no-passphrase but no keygen?" +fi grep "no-passphrase specified without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments." @@ -418,7 +428,9 @@ ME="${DATA_DIR}/case11C" mkdir -p "${ME}/keys" -${TOR} --DataDirectory "${ME}" --newpass > "${ME}/stdout" && die "Successfully started with newpass but no keygen?" || true +if ${TOR} --DataDirectory "${ME}" --newpass > "${ME}/stdout"; then + die "Successfully started with newpass but no keygen?" +fi grep "newpass specified without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments." @@ -456,7 +468,9 @@ ME="${DATA_DIR}/case11E" mkdir -p "${ME}/keys" -${TOR} --DataDirectory "${ME}" --keygen --passphrase-fd ewigeblumenkraft > "${ME}/stdout" && die "Successfully started with bogus passphrase-fd?" || true +if ${TOR} --DataDirectory "${ME}" --keygen --passphrase-fd ewigeblumenkraft > "${ME}/stdout"; then + die "Successfully started with bogus passphrase-fd?" +fi grep "Invalid --passphrase-fd value" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments." @@ -473,7 +487,9 @@ ME="${DATA_DIR}/case11F" mkdir -p "${ME}/keys" -${TOR} --DataDirectory "${ME}" --keygen --passphrase-fd 1 --no-passphrase > "${ME}/stdout" && die "Successfully started with bogus passphrase-fd combination?" || true +if ${TOR} --DataDirectory "${ME}" --keygen --passphrase-fd 1 --no-passphrase > "${ME}/stdout"; then + die "Successfully started with bogus passphrase-fd combination?" +fi grep "no-passphrase specified with --passphrase-fd" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments." diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c index 34f59f26cd..5e78e1ce4d 100644 --- a/src/test/test_link_handshake.c +++ b/src/test/test_link_handshake.c @@ -263,7 +263,7 @@ test_link_handshake_certs_ok(void *arg) tt_assert(c1->handshake_state->authenticated_rsa); tt_assert(! c1->handshake_state->authenticated_ed25519); } - tt_assert(! tor_mem_is_zero( + tt_assert(! fast_mem_is_zero( (char*)c1->handshake_state->authenticated_rsa_peer_id, 20)); chan2 = tor_malloc_zero(sizeof(*chan2)); @@ -290,7 +290,7 @@ test_link_handshake_certs_ok(void *arg) tt_ptr_op(c2->handshake_state->certs->ed_id_sign, OP_EQ, NULL); } tt_assert(c2->handshake_state->certs->id_cert); - tt_assert(tor_mem_is_zero( + tt_assert(fast_mem_is_zero( (char*)c2->handshake_state->authenticated_rsa_peer_id, 20)); /* no authentication has happened yet, since we haen't gotten an AUTH cell. */ @@ -948,7 +948,7 @@ test_link_handshake_send_authchallenge(void *arg) #else tt_int_op(36, OP_EQ, cell1->payload_len); tt_int_op(36, OP_EQ, cell2->payload_len); -#endif +#endif /* defined(HAVE_WORKING_TOR_TLS_GET_TLSSECRETS) */ tt_int_op(0, OP_EQ, cell1->circ_id); tt_int_op(0, OP_EQ, cell2->circ_id); tt_int_op(CELL_AUTH_CHALLENGE, OP_EQ, cell1->command); @@ -960,7 +960,7 @@ test_link_handshake_send_authchallenge(void *arg) #else tt_mem_op("\x00\x01\x00\x03", OP_EQ, cell1->payload + 32, 4); tt_mem_op("\x00\x01\x00\x03", OP_EQ, cell2->payload + 32, 4); -#endif +#endif /* defined(HAVE_WORKING_TOR_TLS_GET_TLSSECRETS) */ tt_mem_op(cell1->payload, OP_NE, cell2->payload, 32); done: diff --git a/src/test/test_logging.c b/src/test/test_logging.c index 6416e98a4e..bb7018fe1c 100644 --- a/src/test/test_logging.c +++ b/src/test/test_logging.c @@ -15,7 +15,7 @@ #endif static void -dummy_cb_fn(int severity, uint32_t domain, const char *msg) +dummy_cb_fn(int severity, log_domain_mask_t domain, const char *msg) { (void)severity; (void)domain; (void)msg; } diff --git a/src/test/test_namemap.c b/src/test/test_namemap.c new file mode 100644 index 0000000000..df77d4e2de --- /dev/null +++ b/src/test/test_namemap.c @@ -0,0 +1,174 @@ +/* Copyright (c) 2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "test/test.h" + +#include "lib/cc/torint.h" +#include "lib/container/namemap.h" +#include "lib/container/namemap_st.h" +#include "lib/malloc/malloc.h" + +#include +#include + +static void +test_namemap_empty(void *arg) +{ + (void)arg; + + namemap_t m; + namemap_init(&m); + namemap_t m2 = NAMEMAP_INIT(); + + tt_uint_op(0, OP_EQ, namemap_get_size(&m)); + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, "hello")); + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, "hello")); + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, "hello128")); + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, "")); + tt_uint_op(0, OP_EQ, namemap_get_size(&m)); + + tt_uint_op(0, OP_EQ, namemap_get_size(&m2)); + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m2, "hello")); + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m2, "hello")); + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m2, "hello128")); + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m2, "")); + tt_uint_op(0, OP_EQ, namemap_get_size(&m)); + + done: + namemap_clear(&m); + namemap_clear(&m2); +} + +static void +test_namemap_toolong(void *arg) +{ + (void)arg; + namemap_t m; + char *ok = NULL; + char *toolong = NULL; + namemap_init(&m); + + ok = tor_malloc_zero(MAX_NAMEMAP_NAME_LEN+1); + memset(ok, 'x', MAX_NAMEMAP_NAME_LEN); + + toolong = tor_malloc_zero(MAX_NAMEMAP_NAME_LEN+2); + memset(toolong, 'x', MAX_NAMEMAP_NAME_LEN+1); + + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, ok)); + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, toolong)); + unsigned u1 = namemap_get_or_create_id(&m, toolong); + unsigned u2 = namemap_get_or_create_id(&m, ok); + tt_uint_op(u1, OP_EQ, NAMEMAP_ERR); + tt_uint_op(u2, OP_NE, NAMEMAP_ERR); + tt_uint_op(u2, OP_EQ, namemap_get_id(&m, ok)); + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m, toolong)); + + tt_str_op(ok, OP_EQ, namemap_get_name(&m, u2)); + tt_ptr_op(NULL, OP_EQ, namemap_get_name(&m, u1)); + + done: + tor_free(ok); + tor_free(toolong); + namemap_clear(&m); +} + +static void +test_namemap_blackbox(void *arg) +{ + (void)arg; + + namemap_t m1, m2; + namemap_init(&m1); + namemap_init(&m2); + + unsigned u1 = namemap_get_or_create_id(&m1, "hello"); + unsigned u2 = namemap_get_or_create_id(&m1, "world"); + tt_uint_op(u1, OP_NE, NAMEMAP_ERR); + tt_uint_op(u2, OP_NE, NAMEMAP_ERR); + tt_uint_op(u1, OP_NE, u2); + + tt_uint_op(u1, OP_EQ, namemap_get_id(&m1, "hello")); + tt_uint_op(u1, OP_EQ, namemap_get_or_create_id(&m1, "hello")); + tt_uint_op(u2, OP_EQ, namemap_get_id(&m1, "world")); + tt_uint_op(u2, OP_EQ, namemap_get_or_create_id(&m1, "world")); + + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m1, "HELLO")); + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m2, "hello")); + + unsigned u3 = namemap_get_or_create_id(&m2, "hola"); + tt_uint_op(u3, OP_NE, NAMEMAP_ERR); + tt_uint_op(NAMEMAP_ERR, OP_EQ, namemap_get_id(&m1, "hola")); + tt_uint_op(u3, OP_EQ, namemap_get_or_create_id(&m2, "hola")); + tt_uint_op(u3, OP_EQ, namemap_get_id(&m2, "hola")); + + unsigned int u4 = namemap_get_or_create_id(&m1, "hola"); + tt_uint_op(u4, OP_NE, NAMEMAP_ERR); + tt_uint_op(u4, OP_EQ, namemap_get_id(&m1, "hola")); + tt_uint_op(u3, OP_EQ, namemap_get_id(&m2, "hola")); + + tt_str_op("hello", OP_EQ, namemap_get_name(&m1, u1)); + tt_str_op("world", OP_EQ, namemap_get_name(&m1, u2)); + tt_str_op("hola", OP_EQ, namemap_get_name(&m2, u3)); + tt_str_op("hola", OP_EQ, namemap_get_name(&m1, u4)); + + tt_ptr_op(NULL, OP_EQ, namemap_get_name(&m2, u3 + 10)); + + done: + namemap_clear(&m1); + namemap_clear(&m2); +} + +static void +test_namemap_internals(void *arg) +{ + (void)arg; + // This test actually assumes know something about the identity layout. + namemap_t m; + namemap_init(&m); + + tt_uint_op(0, OP_EQ, namemap_get_or_create_id(&m, "that")); + tt_uint_op(0, OP_EQ, namemap_get_or_create_id(&m, "that")); + tt_uint_op(1, OP_EQ, namemap_get_or_create_id(&m, "is")); + tt_uint_op(1, OP_EQ, namemap_get_or_create_id(&m, "is")); + + tt_uint_op(0, OP_EQ, namemap_get_id(&m, "that")); + tt_uint_op(0, OP_EQ, namemap_get_id(&m, "that")); + tt_uint_op(1, OP_EQ, namemap_get_id(&m, "is")); + tt_uint_op(2, OP_EQ, namemap_get_or_create_id(&m, "not")); + tt_uint_op(1, OP_EQ, namemap_get_or_create_id(&m, "is")); + tt_uint_op(2, OP_EQ, namemap_get_or_create_id(&m, "not")); + + done: + namemap_clear(&m); +} + +static void +test_namemap_fmt(void *arg) +{ + (void)arg; + namemap_t m = NAMEMAP_INIT(); + + unsigned a = namemap_get_or_create_id(&m, "greetings"); + unsigned b = namemap_get_or_create_id(&m, "earthlings"); + + tt_str_op(namemap_fmt_name(&m, a), OP_EQ, "greetings"); + tt_str_op(namemap_fmt_name(&m, b), OP_EQ, "earthlings"); + tt_int_op(a, OP_NE, 100); + tt_int_op(b, OP_NE, 100); + tt_str_op(namemap_fmt_name(&m, 100), OP_EQ, "{100}"); + + done: + namemap_clear(&m); +} + +#define T(name) \ + { #name, test_namemap_ ## name , 0, NULL, NULL } + +struct testcase_t namemap_tests[] = { + T(empty), + T(toolong), + T(blackbox), + T(internals), + T(fmt), + END_OF_TESTCASES +}; diff --git a/src/test/test_options.c b/src/test/test_options.c index f12e6b6763..7009910b0f 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -31,14 +31,14 @@ typedef struct { int severity; - uint32_t domain; + log_domain_mask_t domain; char *msg; } logmsg_t; static smartlist_t *messages = NULL; static void -log_cback(int severity, uint32_t domain, const char *msg) +log_cback(int severity, log_domain_mask_t domain, const char *msg) { logmsg_t *x = tor_malloc(sizeof(*x)); x->severity = severity; @@ -430,6 +430,7 @@ get_options_test_data(const char *conf) // Being kinda lame and just fixing the immedate breakage for now.. result->opt->ConnectionPadding = -1; // default must be "auto" result->opt->DormantClientTimeout = 1800; // must be over 600. + result->opt->CircuitPadding = 1; // default must be "1" rv = config_get_lines(conf, &cl, 1); tt_int_op(rv, OP_EQ, 0); diff --git a/src/test/test_periodic_event.c b/src/test/test_periodic_event.c index ebac20838f..267156a908 100644 --- a/src/test/test_periodic_event.c +++ b/src/test/test_periodic_event.c @@ -51,12 +51,13 @@ test_pe_initialize(void *arg) * need to run the main loop and then wait for a second delaying the unit * tests. Instead, we'll test the callback work indepedently elsewhere. */ initialize_periodic_events(); + periodic_events_connect_all(); set_network_participation(false); rescan_periodic_events(get_options()); /* Validate that all events have been set up. */ - for (int i = 0; periodic_events[i].name; ++i) { - periodic_event_item_t *item = &periodic_events[i]; + for (int i = 0; mainloop_periodic_events[i].name; ++i) { + periodic_event_item_t *item = &mainloop_periodic_events[i]; tt_assert(item->ev); tt_assert(item->fn); tt_u64_op(item->last_action_time, OP_EQ, 0); @@ -89,8 +90,8 @@ test_pe_launch(void *arg) /* Hack: We'll set a dumb fn() of each events so they don't get called when * dispatching them. We just want to test the state of the callbacks, not * the whole code path. */ - for (int i = 0; periodic_events[i].name; ++i) { - periodic_event_item_t *item = &periodic_events[i]; + for (int i = 0; mainloop_periodic_events[i].name; ++i) { + periodic_event_item_t *item = &mainloop_periodic_events[i]; item->fn = dumb_event_fn; } @@ -107,17 +108,18 @@ test_pe_launch(void *arg) periodic_event_item_t *item = &periodic_events[i]; tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0); } -#endif +#endif /* 0 */ initialize_periodic_events(); + periodic_events_connect_all(); /* Now that we've initialized, rescan the list to launch. */ periodic_events_on_new_options(options); int mask = PERIODIC_EVENT_ROLE_CLIENT|PERIODIC_EVENT_ROLE_ALL| PERIODIC_EVENT_ROLE_NET_PARTICIPANT; - for (int i = 0; periodic_events[i].name; ++i) { - periodic_event_item_t *item = &periodic_events[i]; + for (int i = 0; mainloop_periodic_events[i].name; ++i) { + periodic_event_item_t *item = &mainloop_periodic_events[i]; int should_be_enabled = !!(item->roles & mask); tt_int_op(periodic_event_is_enabled(item), OP_EQ, should_be_enabled); // enabled or not, the event has not yet been run. @@ -134,8 +136,8 @@ test_pe_launch(void *arg) PERIODIC_EVENT_ROLE_RELAY|PERIODIC_EVENT_ROLE_DIRSERVER| PERIODIC_EVENT_ROLE_ALL|PERIODIC_EVENT_ROLE_NET_PARTICIPANT); - for (int i = 0; periodic_events[i].name; ++i) { - periodic_event_item_t *item = &periodic_events[i]; + for (int i = 0; mainloop_periodic_events[i].name; ++i) { + periodic_event_item_t *item = &mainloop_periodic_events[i]; /* Only Client role should be disabled. */ if (item->roles == PERIODIC_EVENT_ROLE_CLIENT) { tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0); @@ -156,8 +158,8 @@ test_pe_launch(void *arg) set_network_participation(false); periodic_events_on_new_options(options); - for (int i = 0; periodic_events[i].name; ++i) { - periodic_event_item_t *item = &periodic_events[i]; + for (int i = 0; mainloop_periodic_events[i].name; ++i) { + periodic_event_item_t *item = &mainloop_periodic_events[i]; int should_be_enabled = (item->roles & PERIODIC_EVENT_ROLE_ALL) && !(item->flags & PERIODIC_EVENT_FLAG_NEED_NET); tt_int_op(periodic_event_is_enabled(item), OP_EQ, should_be_enabled); @@ -177,8 +179,8 @@ test_pe_launch(void *arg) * trigger a rescan of the event disabling the HS service event. */ to_remove = &service; - for (int i = 0; periodic_events[i].name; ++i) { - periodic_event_item_t *item = &periodic_events[i]; + for (int i = 0; mainloop_periodic_events[i].name; ++i) { + periodic_event_item_t *item = &mainloop_periodic_events[i]; tt_int_op(periodic_event_is_enabled(item), OP_EQ, (item->roles != PERIODIC_EVENT_ROLE_CONTROLEV)); } @@ -300,12 +302,13 @@ test_pe_hs_service(void *arg) consider_hibernation(time(NULL)); /* Initialize the events so we can enable them */ initialize_periodic_events(); + periodic_events_connect_all(); /* Hack: We'll set a dumb fn() of each events so they don't get called when * dispatching them. We just want to test the state of the callbacks, not * the whole code path. */ - for (int i = 0; periodic_events[i].name; ++i) { - periodic_event_item_t *item = &periodic_events[i]; + for (int i = 0; mainloop_periodic_events[i].name; ++i) { + periodic_event_item_t *item = &mainloop_periodic_events[i]; item->fn = dumb_event_fn; } @@ -318,8 +321,8 @@ test_pe_hs_service(void *arg) * trigger a rescan of the event disabling the HS service event. */ to_remove = &service; - for (int i = 0; periodic_events[i].name; ++i) { - periodic_event_item_t *item = &periodic_events[i]; + for (int i = 0; mainloop_periodic_events[i].name; ++i) { + periodic_event_item_t *item = &mainloop_periodic_events[i]; if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) { tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1); } @@ -329,8 +332,8 @@ test_pe_hs_service(void *arg) /* Remove the service from the global map, it should trigger a rescan and * disable the HS service events. */ remove_service(get_hs_service_map(), &service); - for (int i = 0; periodic_events[i].name; ++i) { - periodic_event_item_t *item = &periodic_events[i]; + for (int i = 0; mainloop_periodic_events[i].name; ++i) { + periodic_event_item_t *item = &mainloop_periodic_events[i]; if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) { tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0); } diff --git a/src/test/test_policy.c b/src/test/test_policy.c index 46d4a1b94a..e58bb3d174 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -6,13 +6,18 @@ #include "core/or/or.h" #include "app/config/config.h" +#include "core/or/circuitbuild.h" #include "core/or/policies.h" #include "feature/dirparse/policy_parse.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_descriptor.h" #include "feature/relay/router.h" #include "lib/encoding/confline.h" #include "test/test.h" +#include "test/log_test_helpers.h" #include "core/or/addr_policy_st.h" +#include "core/or/extend_info_st.h" #include "core/or/port_cfg_st.h" #include "feature/nodelist/node_st.h" #include "feature/nodelist/routerinfo_st.h" @@ -2024,6 +2029,101 @@ test_policies_fascist_firewall_allows_address(void *arg) expect_ap); \ STMT_END +/* Check that fascist_firewall_choose_address_ls() returns the expected + * results. */ +#define CHECK_CHOSEN_ADDR_NULL_LS() \ + STMT_BEGIN \ + tor_addr_port_t chosen_ls_ap; \ + tor_addr_make_null(&chosen_ls_ap.addr, AF_UNSPEC); \ + chosen_ls_ap.port = 0; \ + setup_full_capture_of_logs(LOG_WARN); \ + fascist_firewall_choose_address_ls(NULL, 1, &chosen_ls_ap); \ + expect_single_log_msg("Unknown or missing link specifiers"); \ + teardown_capture_of_logs(); \ + STMT_END + +#define CHECK_CHOSEN_ADDR_LS(fake_ls, pref_only, expect_rv, expect_ap) \ + STMT_BEGIN \ + tor_addr_port_t chosen_ls_ap; \ + tor_addr_make_null(&chosen_ls_ap.addr, AF_UNSPEC); \ + chosen_ls_ap.port = 0; \ + setup_full_capture_of_logs(LOG_WARN); \ + fascist_firewall_choose_address_ls(fake_ls, pref_only, &chosen_ls_ap); \ + if (smartlist_len(fake_ls) == 0) { \ + expect_single_log_msg("Link specifiers are empty"); \ + } else { \ + expect_no_log_entry(); \ + tt_assert(tor_addr_eq(&(expect_ap).addr, &chosen_ls_ap.addr)); \ + tt_int_op((expect_ap).port, OP_EQ, chosen_ls_ap.port); \ + } \ + teardown_capture_of_logs(); \ + STMT_END + +#define CHECK_LS_LEGACY_ONLY(fake_ls) \ + STMT_BEGIN \ + tor_addr_port_t chosen_ls_ap; \ + tor_addr_make_null(&chosen_ls_ap.addr, AF_UNSPEC); \ + chosen_ls_ap.port = 0; \ + setup_full_capture_of_logs(LOG_WARN); \ + fascist_firewall_choose_address_ls(fake_ls, 0, &chosen_ls_ap); \ + expect_single_log_msg("None of our link specifiers have IPv4 or IPv6"); \ + teardown_capture_of_logs(); \ + STMT_END + +#define CHECK_HS_EXTEND_INFO_ADDR_LS(fake_ls, direct_conn, expect_ap) \ + STMT_BEGIN \ + curve25519_secret_key_t seckey; \ + curve25519_secret_key_generate(&seckey, 0); \ + curve25519_public_key_t pubkey; \ + curve25519_public_key_generate(&pubkey, &seckey); \ + setup_full_capture_of_logs(LOG_WARN); \ + extend_info_t *ei = hs_get_extend_info_from_lspecs(fake_ls, &pubkey, \ + direct_conn); \ + if (fake_ls == NULL) { \ + tt_ptr_op(ei, OP_EQ, NULL); \ + expect_single_log_msg("Specified link specifiers is null"); \ + } else { \ + expect_no_log_entry(); \ + tt_assert(tor_addr_eq(&(expect_ap).addr, &ei->addr)); \ + tt_int_op((expect_ap).port, OP_EQ, ei->port); \ + extend_info_free(ei); \ + } \ + teardown_capture_of_logs(); \ + STMT_END + +#define CHECK_HS_EXTEND_INFO_ADDR_LS_NULL_KEY(fake_ls) \ + STMT_BEGIN \ + setup_full_capture_of_logs(LOG_WARN); \ + extend_info_t *ei = hs_get_extend_info_from_lspecs(fake_ls, NULL, 0); \ + tt_ptr_op(ei, OP_EQ, NULL); \ + expect_single_log_msg("Specified onion key is null"); \ + teardown_capture_of_logs(); \ + STMT_END + +#define CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(fake_ls, direct_conn) \ + STMT_BEGIN \ + curve25519_secret_key_t seckey; \ + curve25519_secret_key_generate(&seckey, 0); \ + curve25519_public_key_t pubkey; \ + curve25519_public_key_generate(&pubkey, &seckey); \ + extend_info_t *ei = hs_get_extend_info_from_lspecs(fake_ls, &pubkey, \ + direct_conn); \ + tt_ptr_op(ei, OP_EQ, NULL); \ + STMT_END + +#define CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_MSG(fake_ls, msg_level, msg) \ + STMT_BEGIN \ + curve25519_secret_key_t seckey; \ + curve25519_secret_key_generate(&seckey, 0); \ + curve25519_public_key_t pubkey; \ + curve25519_public_key_generate(&pubkey, &seckey); \ + setup_full_capture_of_logs(msg_level); \ + extend_info_t *ei = hs_get_extend_info_from_lspecs(fake_ls, &pubkey, 0); \ + tt_ptr_op(ei, OP_EQ, NULL); \ + expect_single_log_msg(msg); \ + teardown_capture_of_logs(); \ + STMT_END + /** Mock the preferred address function to return zero (prefer IPv4). */ static int mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv4(void) @@ -2472,6 +2572,141 @@ test_policies_fascist_firewall_choose_address(void *arg) UNMOCK(fascist_firewall_rand_prefer_ipv6_addr); + /* Test firewall_choose_address_ls(). To do this, we make a fake link + * specifier. */ + smartlist_t *lspecs = smartlist_new(), + *lspecs_blank = smartlist_new(), + *lspecs_v4 = smartlist_new(), + *lspecs_v6 = smartlist_new(), + *lspecs_no_legacy = smartlist_new(), + *lspecs_legacy_only = smartlist_new(); + link_specifier_t *fake_ls; + + /* IPv4 link specifier */ + fake_ls = link_specifier_new(); + link_specifier_set_ls_type(fake_ls, LS_IPV4); + link_specifier_set_un_ipv4_addr(fake_ls, + tor_addr_to_ipv4h(&ipv4_or_ap.addr)); + link_specifier_set_un_ipv4_port(fake_ls, ipv4_or_ap.port); + link_specifier_set_ls_len(fake_ls, sizeof(ipv4_or_ap.addr.addr.in_addr) + + sizeof(ipv4_or_ap.port)); + smartlist_add(lspecs, fake_ls); + smartlist_add(lspecs_v4, fake_ls); + smartlist_add(lspecs_no_legacy, fake_ls); + + /* IPv6 link specifier */ + fake_ls = link_specifier_new(); + link_specifier_set_ls_type(fake_ls, LS_IPV6); + size_t addr_len = link_specifier_getlen_un_ipv6_addr(fake_ls); + const uint8_t *in6_addr = tor_addr_to_in6_addr8(&ipv6_or_ap.addr); + uint8_t *ipv6_array = link_specifier_getarray_un_ipv6_addr(fake_ls); + memcpy(ipv6_array, in6_addr, addr_len); + link_specifier_set_un_ipv6_port(fake_ls, ipv6_or_ap.port); + link_specifier_set_ls_len(fake_ls, addr_len + sizeof(ipv6_or_ap.port)); + smartlist_add(lspecs, fake_ls); + smartlist_add(lspecs_v6, fake_ls); + + /* Legacy ID link specifier */ + fake_ls = link_specifier_new(); + link_specifier_set_ls_type(fake_ls, LS_LEGACY_ID); + uint8_t *legacy_id = link_specifier_getarray_un_legacy_id(fake_ls); + memset(legacy_id, 'A', sizeof(*legacy_id)); + link_specifier_set_ls_len(fake_ls, + link_specifier_getlen_un_legacy_id(fake_ls)); + smartlist_add(lspecs, fake_ls); + smartlist_add(lspecs_legacy_only, fake_ls); + smartlist_add(lspecs_v4, fake_ls); + smartlist_add(lspecs_v6, fake_ls); + + /* Check with bogus requests. */ + tor_addr_port_t null_ap; \ + tor_addr_make_null(&null_ap.addr, AF_UNSPEC); \ + null_ap.port = 0; \ + + /* Check for a null link state. */ + CHECK_CHOSEN_ADDR_NULL_LS(); + CHECK_HS_EXTEND_INFO_ADDR_LS(NULL, 1, null_ap); + + /* Check for a blank link state. */ + CHECK_CHOSEN_ADDR_LS(lspecs_blank, 0, 0, null_ap); + CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(lspecs_blank, 0); + + /* Check for a link state with only a Legacy ID. */ + CHECK_LS_LEGACY_ONLY(lspecs_legacy_only); + CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(lspecs_legacy_only, 0); + smartlist_free(lspecs_legacy_only); + + /* Check with a null onion_key. */ + CHECK_HS_EXTEND_INFO_ADDR_LS_NULL_KEY(lspecs_blank); + smartlist_free(lspecs_blank); + + /* Check with a null onion_key. */ + CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_MSG(lspecs_no_legacy, LOG_WARN, + "Missing Legacy ID in link state"); + smartlist_free(lspecs_no_legacy); + + /* Enable both IPv4 and IPv6. */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 1; + mock_options.ClientUseIPv6 = 1; + + /* Prefer IPv4, enable both IPv4 and IPv6. */ + mock_options.ClientPreferIPv6ORPort = 0; + + CHECK_CHOSEN_ADDR_LS(lspecs, 0, 1, ipv4_or_ap); + CHECK_CHOSEN_ADDR_LS(lspecs, 1, 1, ipv4_or_ap); + + CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 1, ipv4_or_ap); + CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 0, ipv4_or_ap); + + /* Prefer IPv6, enable both IPv4 and IPv6. */ + mock_options.ClientPreferIPv6ORPort = 1; + + CHECK_CHOSEN_ADDR_LS(lspecs, 0, 1, ipv6_or_ap); + CHECK_CHOSEN_ADDR_LS(lspecs, 1, 1, ipv6_or_ap); + + CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 1, ipv6_or_ap); + CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 0, ipv4_or_ap); + + /* IPv4-only. */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 1; + mock_options.ClientUseIPv6 = 0; + + CHECK_CHOSEN_ADDR_LS(lspecs, 0, 1, ipv4_or_ap); + CHECK_CHOSEN_ADDR_LS(lspecs, 1, 1, ipv4_or_ap); + + CHECK_CHOSEN_ADDR_LS(lspecs_v6, 0, 0, null_ap); + + CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 1, ipv4_or_ap); + CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 0, ipv4_or_ap); + + CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(lspecs_v6, 0); + CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(lspecs_v6, 1); + + /* IPv6-only. */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 0; + mock_options.ClientUseIPv6 = 1; + + CHECK_CHOSEN_ADDR_LS(lspecs, 0, 1, ipv6_or_ap); + CHECK_CHOSEN_ADDR_LS(lspecs, 1, 1, ipv6_or_ap); + + CHECK_CHOSEN_ADDR_LS(lspecs_v4, 0, 0, null_ap); + + CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 1, ipv6_or_ap); + CHECK_HS_EXTEND_INFO_ADDR_LS(lspecs, 0, ipv4_or_ap); + + CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(lspecs_v4, 1); + CHECK_HS_EXTEND_INFO_ADDR_LS_EXPECT_NULL(lspecs_v6, 0); + + smartlist_free(lspecs_v4); + smartlist_free(lspecs_v6); + + SMARTLIST_FOREACH(lspecs, link_specifier_t *, lspec, \ + link_specifier_free(lspec)); \ + smartlist_free(lspecs); + done: UNMOCK(get_options); } diff --git a/src/test/test_prob_distr.c b/src/test/test_prob_distr.c index 37cfdae7d9..0ecbf65f41 100644 --- a/src/test/test_prob_distr.c +++ b/src/test/test_prob_distr.c @@ -33,6 +33,7 @@ #include "lib/math/prob_distr.h" #include "lib/math/fp.h" #include "lib/crypt_ops/crypto_rand.h" +#include "test/rng_test_helpers.h" #include #include @@ -1117,49 +1118,15 @@ test_psi_dist_sample(const struct dist *dist) } } -/* This is the seed of the deterministic randomness */ -static uint8_t rng_seed[16]; -static crypto_xof_t *rng_xof = NULL; - -/** Initialize the seed of the deterministic randomness. */ -static void -init_deterministic_rand(void) -{ - crypto_rand((char*)rng_seed, sizeof(rng_seed)); - crypto_xof_free(rng_xof); - rng_xof = crypto_xof_new(); - crypto_xof_add_bytes(rng_xof, rng_seed, sizeof(rng_seed)); -} - static void -teardown_deterministic_rand(void) +write_stochastic_warning(void) { - crypto_xof_free(rng_xof); -} - -static void -dump_seed(void) -{ - printf("\n" + if (tinytest_cur_test_has_failed()) { + printf("\n" "NOTE: This is a stochastic test, and we expect it to fail from\n" "time to time, with some low probability. If you see it fail more\n" - "than one trial in 100, though, please tell us.\n\n" - "Seed: %s\n", - hex_str((const char*)rng_seed, sizeof(rng_seed))); -} - -/** Produce deterministic randomness for the stochastic tests using the global - * deterministic_rand_counter seed - * - * This function produces deterministic data over multiple calls iff it's - * called in the same call order with the same 'n' parameter (which is the - * case for the psi test). If not, outputs will deviate. */ -static void -crypto_rand_deterministic(char *out, size_t n) -{ - /* Use a XOF to squeeze bytes out of that silly counter */ - tor_assert(rng_xof); - crypto_xof_squeeze_bytes(rng_xof, (uint8_t*)out, n); + "than one trial in 100, though, please tell us.\n\n"); + } } static void @@ -1199,8 +1166,7 @@ test_stochastic_uniform(void *arg) }; bool ok = true, tests_failed = true; - init_deterministic_rand(); - MOCK(crypto_rand, crypto_rand_deterministic); + testing_enable_reproducible_rng(); ok &= test_psi_dist_sample(&uniform01.base); ok &= test_psi_dist_sample(&uniform_pos.base); @@ -1215,10 +1181,9 @@ test_stochastic_uniform(void *arg) done: if (tests_failed) { - dump_seed(); + write_stochastic_warning(); } - teardown_deterministic_rand(); - UNMOCK(crypto_rand); + testing_disable_reproducible_rng(); } static bool @@ -1288,8 +1253,7 @@ test_stochastic_genpareto(void *arg) bool tests_failed = true; (void) arg; - init_deterministic_rand(); - MOCK(crypto_rand, crypto_rand_deterministic); + testing_enable_reproducible_rng(); ok = test_stochastic_genpareto_impl(0, 1, -0.25); tt_assert(ok); @@ -1310,10 +1274,9 @@ test_stochastic_genpareto(void *arg) done: if (tests_failed) { - dump_seed(); + write_stochastic_warning(); } - teardown_deterministic_rand(); - UNMOCK(crypto_rand); + testing_disable_reproducible_rng(); } static void @@ -1324,8 +1287,7 @@ test_stochastic_geometric(void *arg) (void) arg; - init_deterministic_rand(); - MOCK(crypto_rand, crypto_rand_deterministic); + testing_enable_reproducible_rng(); ok = test_stochastic_geometric_impl(0.1); tt_assert(ok); @@ -1340,10 +1302,9 @@ test_stochastic_geometric(void *arg) done: if (tests_failed) { - dump_seed(); + write_stochastic_warning(); } - teardown_deterministic_rand(); - UNMOCK(crypto_rand); + testing_disable_reproducible_rng(); } static void @@ -1353,8 +1314,7 @@ test_stochastic_logistic(void *arg) bool tests_failed = true; (void) arg; - init_deterministic_rand(); - MOCK(crypto_rand, crypto_rand_deterministic); + testing_enable_reproducible_rng(); ok = test_stochastic_logistic_impl(0, 1); tt_assert(ok); @@ -1369,21 +1329,18 @@ test_stochastic_logistic(void *arg) done: if (tests_failed) { - dump_seed(); + write_stochastic_warning(); } - teardown_deterministic_rand(); - UNMOCK(crypto_rand); + testing_disable_reproducible_rng(); } static void test_stochastic_log_logistic(void *arg) { bool ok = 0; - bool tests_failed = true; (void) arg; - init_deterministic_rand(); - MOCK(crypto_rand, crypto_rand_deterministic); + testing_enable_reproducible_rng(); ok = test_stochastic_log_logistic_impl(1, 1); tt_assert(ok); @@ -1394,25 +1351,18 @@ test_stochastic_log_logistic(void *arg) ok = test_stochastic_log_logistic_impl(exp(-10), 1e-2); tt_assert(ok); - tests_failed = false; - done: - if (tests_failed) { - dump_seed(); - } - teardown_deterministic_rand(); - UNMOCK(crypto_rand); + write_stochastic_warning(); + testing_disable_reproducible_rng(); } static void test_stochastic_weibull(void *arg) { bool ok = 0; - bool tests_failed = true; (void) arg; - init_deterministic_rand(); - MOCK(crypto_rand, crypto_rand_deterministic); + testing_enable_reproducible_rng(); ok = test_stochastic_weibull_impl(1, 0.5); tt_assert(ok); @@ -1425,13 +1375,9 @@ test_stochastic_weibull(void *arg) ok = test_stochastic_weibull_impl(10, 1); tt_assert(ok); - tests_failed = false; - done: - if (tests_failed) { - dump_seed(); - } - teardown_deterministic_rand(); + write_stochastic_warning(); + testing_disable_reproducible_rng(); UNMOCK(crypto_rand); } diff --git a/src/test/test_process.c b/src/test/test_process.c index 7cc01d2442..7836312761 100644 --- a/src/test/test_process.c +++ b/src/test/test_process.c @@ -594,7 +594,7 @@ test_unix(void *arg) done: process_free(process); -#endif +#endif /* !defined(_WIN32) */ } static void @@ -649,7 +649,7 @@ test_win32(void *arg) done: tor_free(joined_argv); process_free(process); -#endif +#endif /* defined(_WIN32) */ } struct testcase_t process_tests[] = { diff --git a/src/test/test_process_slow.c b/src/test/test_process_slow.c index 1322d7b833..91252c725d 100644 --- a/src/test/test_process_slow.c +++ b/src/test/test_process_slow.c @@ -135,7 +135,7 @@ get_win32_test_binary_path(void) done: return NULL; } -#endif +#endif /* defined(_WIN32) */ static void main_loop_timeout_cb(periodic_timer_t *timer, void *data) diff --git a/src/test/test_protover.c b/src/test/test_protover.c index 63c508bd13..1759aef97d 100644 --- a/src/test/test_protover.c +++ b/src/test/test_protover.c @@ -22,7 +22,7 @@ test_protover_parse(void *arg) tt_skip(); done: ; -#else +#else /* !(defined(HAVE_RUST)) */ char *re_encoded = NULL; const char *orig = "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16,900"; @@ -89,7 +89,7 @@ test_protover_parse(void *arg) SMARTLIST_FOREACH(elts, proto_entry_t *, ent, proto_entry_free(ent)); smartlist_free(elts); tor_free(re_encoded); -#endif +#endif /* defined(HAVE_RUST) */ } static void @@ -133,7 +133,7 @@ test_protover_parse_fail(void *arg) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); tt_ptr_op(elts, OP_EQ, NULL); -#endif +#endif /* defined(HAVE_RUST) */ done: ; } @@ -335,7 +335,7 @@ test_protover_all_supported(void *arg) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaa=1-65536", &msg)); tor_end_capture_bugs_(); -#endif +#endif /* !defined(HAVE_RUST) */ done: tor_end_capture_bugs_(); @@ -459,7 +459,7 @@ test_protover_supported_protocols(void *arg) tt_assert(protocol_list_supports_protocol(supported_protocols, PRT_LINKAUTH, PROTOVER_LINKAUTH_V1)); -#endif +#endif /* defined(HAVE_WORKING_TOR_TLS_GET_TLSSECRETS) */ /* Latest LinkAuth is not exposed in the headers. */ tt_assert(protocol_list_supports_protocol(supported_protocols, PRT_LINKAUTH, diff --git a/src/test/test_pt.c b/src/test/test_pt.c index d2996f4cc3..87e3ba356c 100644 --- a/src/test/test_pt.c +++ b/src/test/test_pt.c @@ -7,12 +7,13 @@ #define PT_PRIVATE #define UTIL_PRIVATE #define STATEFILE_PRIVATE -#define CONTROL_PRIVATE +#define CONTROL_EVENTS_PRIVATE #define PROCESS_PRIVATE #include "core/or/or.h" #include "app/config/config.h" #include "app/config/confparse.h" #include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/client/transports.h" #include "core/or/circuitbuild.h" #include "app/config/statefile.h" diff --git a/src/test/test_ptr_slow.c b/src/test/test_ptr_slow.c new file mode 100644 index 0000000000..76bdbf1891 --- /dev/null +++ b/src/test/test_ptr_slow.c @@ -0,0 +1,106 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "core/or/or.h" +#include "test/test.h" +#include "test/ptr_helpers.h" + +#include +#include + +/** Assert that a can be cast to void * and back. */ +static void +assert_int_voidptr_roundtrip(int a) +{ + intptr_t ap = (intptr_t)a; + void *b = cast_intptr_to_voidstar(ap); + intptr_t c = cast_voidstar_to_intptr(b); + void *d = cast_intptr_to_voidstar(c); + + tt_assert(ap == c); + tt_assert(b == d); + + done: + return; +} + +/** Test for possibility of casting `int` to `void *` and back. */ +static void +test_int_voidstar_interop(void *arg) +{ + int a; + (void)arg; + + for (a = -1024; a <= 1024; a++) { + assert_int_voidptr_roundtrip(a); + } + + for (a = INT_MIN; a <= INT_MIN+1024; a++) { + assert_int_voidptr_roundtrip(a); + } + + for (a = INT_MAX-1024; a < INT_MAX; a++) { + assert_int_voidptr_roundtrip(a); + } + + a = 1; + for (unsigned long i = 0; i < sizeof(int) * 8; i++) { + assert_int_voidptr_roundtrip(a); + a = (a << 1); + } +} + +/** Assert that a can be cast to void * and back. */ +static void +assert_uint_voidptr_roundtrip(unsigned int a) +{ + uintptr_t ap = (uintptr_t)a; + void *b = cast_uintptr_to_voidstar(ap); + uintptr_t c = cast_voidstar_to_uintptr(b); + void *d = cast_uintptr_to_voidstar(c); + + tt_assert(ap == c); + tt_assert(b == d); + + done: + return; +} + +/** Test for possibility of casting `int` to `void *` and back. */ +static void +test_uint_voidstar_interop(void *arg) +{ + unsigned int a; + (void)arg; + + for (a = 0; a <= 1024; a++) { + assert_uint_voidptr_roundtrip(a); + } + + for (a = UINT_MAX-1024; a < UINT_MAX; a++) { + assert_uint_voidptr_roundtrip(a); + } + + a = 1; + for (unsigned long i = 0; i < sizeof(int) * 8; i++) { + assert_uint_voidptr_roundtrip(a); + a = (a << 1); + } +} + +struct testcase_t slow_ptr_tests[] = { + { .name = "int_voidstar_interop", + .fn = test_int_voidstar_interop, + .flags = 0, + .setup = NULL, + .setup_data = NULL }, + { .name = "uint_voidstar_interop", + .fn = test_uint_voidstar_interop, + .flags = 0, + .setup = NULL, + .setup_data = NULL }, + END_OF_TESTCASES +}; diff --git a/src/test/test_pubsub_build.c b/src/test/test_pubsub_build.c new file mode 100644 index 0000000000..ce5bf60080 --- /dev/null +++ b/src/test/test_pubsub_build.c @@ -0,0 +1,621 @@ +/* Copyright (c) 2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define DISPATCH_PRIVATE +#define PUBSUB_PRIVATE + +#include "test/test.h" + +#include "lib/cc/torint.h" +#include "lib/dispatch/dispatch.h" +#include "lib/dispatch/dispatch_naming.h" +#include "lib/dispatch/dispatch_st.h" +#include "lib/dispatch/msgtypes.h" +#include "lib/pubsub/pubsub_macros.h" +#include "lib/pubsub/pubsub_build.h" +#include "lib/pubsub/pubsub_builder_st.h" + +#include "lib/log/escape.h" +#include "lib/malloc/malloc.h" +#include "lib/string/printf.h" + +#include "test/log_test_helpers.h" + +#include +#include + +static char * +ex_int_fmt(msg_aux_data_t aux) +{ + int val = (int) aux.u64; + char *r=NULL; + tor_asprintf(&r, "%d", val); + return r; +} + +static char * +ex_str_fmt(msg_aux_data_t aux) +{ + return esc_for_log(aux.ptr); +} + +static void +ex_str_free(msg_aux_data_t aux) +{ + tor_free_(aux.ptr); +} + +static dispatch_typefns_t intfns = { + .fmt_fn = ex_int_fmt +}; + +static dispatch_typefns_t stringfns = { + .free_fn = ex_str_free, + .fmt_fn = ex_str_fmt +}; + +DECLARE_MESSAGE_INT(bunch_of_coconuts, int, int); +DECLARE_PUBLISH(bunch_of_coconuts); +DECLARE_SUBSCRIBE(bunch_of_coconuts, coconut_recipient_cb); + +DECLARE_MESSAGE(yes_we_have_no, string, char *); +DECLARE_PUBLISH(yes_we_have_no); +DECLARE_SUBSCRIBE(yes_we_have_no, absent_item_cb); + +static void +coconut_recipient_cb(const msg_t *m, int n_coconuts) +{ + (void)m; + (void)n_coconuts; +} + +static void +absent_item_cb(const msg_t *m, const char *fruitname) +{ + (void)m; + (void)fruitname; +} + +#define FLAG_SKIP 99999 + +static void +seed_dispatch_builder(pubsub_builder_t *b, + unsigned fl1, unsigned fl2, unsigned fl3, unsigned fl4) +{ + pubsub_connector_t *c = NULL; + + { + c = pubsub_connector_for_subsystem(b, get_subsys_id("sys1")); + DISPATCH_REGISTER_TYPE(c, int, &intfns); + if (fl1 != FLAG_SKIP) + DISPATCH_ADD_PUB_(c, main, bunch_of_coconuts, fl1); + if (fl2 != FLAG_SKIP) + DISPATCH_ADD_SUB_(c, main, yes_we_have_no, fl2); + pubsub_connector_free(c); + } + + { + c = pubsub_connector_for_subsystem(b, get_subsys_id("sys2")); + DISPATCH_REGISTER_TYPE(c, string, &stringfns); + if (fl3 != FLAG_SKIP) + DISPATCH_ADD_PUB_(c, main, yes_we_have_no, fl3); + if (fl4 != FLAG_SKIP) + DISPATCH_ADD_SUB_(c, main, bunch_of_coconuts, fl4); + pubsub_connector_free(c); + } +} + +static void +seed_pubsub_builder_basic(pubsub_builder_t *b) +{ + seed_dispatch_builder(b, 0, 0, 0, 0); +} + +/* Regular builder with valid types and messages. + */ +static void +test_pubsub_build_types_ok(void *arg) +{ + (void)arg; + pubsub_builder_t *b = NULL; + dispatch_t *dispatcher = NULL; + pubsub_connector_t *c = NULL; + pubsub_items_t *items = NULL; + + b = pubsub_builder_new(); + seed_pubsub_builder_basic(b); + + dispatcher = pubsub_builder_finalize(b, &items); + b = NULL; + tt_assert(dispatcher); + tt_assert(items); + tt_int_op(smartlist_len(items->items), OP_EQ, 4); + + // Make sure that the bindings got build correctly. + SMARTLIST_FOREACH_BEGIN(items->items, pubsub_cfg_t *, item) { + if (item->is_publish) { + tt_assert(item->pub_binding); + tt_ptr_op(item->pub_binding->dispatch_ptr, OP_EQ, dispatcher); + } + } SMARTLIST_FOREACH_END(item); + + tt_int_op(dispatcher->n_types, OP_GE, 2); + tt_assert(dispatcher->typefns); + + tt_assert(dispatcher->typefns[get_msg_type_id("int")].fmt_fn == ex_int_fmt); + tt_assert(dispatcher->typefns[get_msg_type_id("string")].fmt_fn == + ex_str_fmt); + + // Now clear the bindings, like we would do before freeing the + // the dispatcher. + pubsub_items_clear_bindings(items); + SMARTLIST_FOREACH_BEGIN(items->items, pubsub_cfg_t *, item) { + if (item->is_publish) { + tt_assert(item->pub_binding); + tt_ptr_op(item->pub_binding->dispatch_ptr, OP_EQ, NULL); + } + } SMARTLIST_FOREACH_END(item); + + done: + pubsub_connector_free(c); + pubsub_builder_free(b); + dispatch_free(dispatcher); + pubsub_items_free(items); +} + +/* We fail if the same type is defined in two places with different functions. + */ +static void +test_pubsub_build_types_decls_conflict(void *arg) +{ + (void)arg; + pubsub_builder_t *b = NULL; + dispatch_t *dispatcher = NULL; + pubsub_connector_t *c = NULL; + + b = pubsub_builder_new(); + seed_pubsub_builder_basic(b); + { + c = pubsub_connector_for_subsystem(b, get_subsys_id("sys3")); + // Extra declaration of int: we don't allow this. + DISPATCH_REGISTER_TYPE(c, int, &stringfns); + pubsub_connector_free(c); + } + + setup_full_capture_of_logs(LOG_WARN); + dispatcher = pubsub_builder_finalize(b, NULL); + b = NULL; + tt_assert(dispatcher == NULL); + // expect_log_msg_containing("(int) declared twice"); // XXXX + + done: + pubsub_connector_free(c); + pubsub_builder_free(b); + dispatch_free(dispatcher); + teardown_capture_of_logs(); +} + +/* If a message ID exists but nobody is publishing or subscribing to it, + * that's okay. */ +static void +test_pubsub_build_unused_message(void *arg) +{ + (void)arg; + pubsub_builder_t *b = NULL; + dispatch_t *dispatcher = NULL; + + b = pubsub_builder_new(); + seed_pubsub_builder_basic(b); + + // This message isn't actually generated by anyone, but that will be fine: + // we just log it at info. + get_message_id("unused"); + setup_capture_of_logs(LOG_INFO); + + dispatcher = pubsub_builder_finalize(b, NULL); + b = NULL; + tt_assert(dispatcher); + expect_log_msg_containing( + "Nobody is publishing or subscribing to message"); + + done: + pubsub_builder_free(b); + dispatch_free(dispatcher); + teardown_capture_of_logs(); +} + +/* Publishing or subscribing to a message with no subscribers / publishers + * should fail and warn. */ +static void +test_pubsub_build_missing_pubsub(void *arg) +{ + (void)arg; + pubsub_builder_t *b = NULL; + dispatch_t *dispatcher = NULL; + + b = pubsub_builder_new(); + seed_dispatch_builder(b, 0, 0, FLAG_SKIP, FLAG_SKIP); + + setup_full_capture_of_logs(LOG_WARN); + dispatcher = pubsub_builder_finalize(b, NULL); + b = NULL; + tt_assert(dispatcher == NULL); + + expect_log_msg_containing( + "Message \"bunch_of_coconuts\" has publishers, but no subscribers."); + expect_log_msg_containing( + "Message \"yes_we_have_no\" has subscribers, but no publishers."); + + done: + pubsub_builder_free(b); + dispatch_free(dispatcher); + teardown_capture_of_logs(); +} + +/* Make sure that a stub publisher or subscriber prevents an error from + * happening even if there are no other publishers/subscribers for a message + */ +static void +test_pubsub_build_stub_pubsub(void *arg) +{ + (void)arg; + pubsub_builder_t *b = NULL; + dispatch_t *dispatcher = NULL; + + b = pubsub_builder_new(); + seed_dispatch_builder(b, 0, 0, DISP_FLAG_STUB, DISP_FLAG_STUB); + + dispatcher = pubsub_builder_finalize(b, NULL); + b = NULL; + tt_assert(dispatcher); + + // 1 subscriber. + tt_int_op(1, OP_EQ, + dispatcher->table[get_message_id("yes_we_have_no")]->n_enabled); + // no subscribers + tt_ptr_op(NULL, OP_EQ, + dispatcher->table[get_message_id("bunch_of_coconuts")]); + + done: + pubsub_builder_free(b); + dispatch_free(dispatcher); +} + +/* Only one channel per msg id. */ +static void +test_pubsub_build_channels_conflict(void *arg) +{ + (void)arg; + pubsub_builder_t *b = NULL; + dispatch_t *dispatcher = NULL; + pubsub_connector_t *c = NULL; + + b = pubsub_builder_new(); + seed_pubsub_builder_basic(b); + pub_binding_t btmp; + + { + c = pubsub_connector_for_subsystem(b, get_subsys_id("problems")); + /* Usually the DISPATCH_ADD_PUB macro would keep us from using + * the wrong channel */ + pubsub_add_pub_(c, &btmp, get_channel_id("hithere"), + get_message_id("bunch_of_coconuts"), + get_msg_type_id("int"), + 0 /* flags */, + "somewhere.c", 22); + pubsub_connector_free(c); + }; + + setup_full_capture_of_logs(LOG_WARN); + dispatcher = pubsub_builder_finalize(b, NULL); + b = NULL; + tt_assert(dispatcher == NULL); + + expect_log_msg_containing("Message \"bunch_of_coconuts\" is associated " + "with multiple inconsistent channels."); + + done: + pubsub_builder_free(b); + dispatch_free(dispatcher); + teardown_capture_of_logs(); +} + +/* Only one type per msg id. */ +static void +test_pubsub_build_types_conflict(void *arg) +{ + (void)arg; + pubsub_builder_t *b = NULL; + dispatch_t *dispatcher = NULL; + pubsub_connector_t *c = NULL; + + b = pubsub_builder_new(); + seed_pubsub_builder_basic(b); + pub_binding_t btmp; + + { + c = pubsub_connector_for_subsystem(b, get_subsys_id("problems")); + /* Usually the DISPATCH_ADD_PUB macro would keep us from using + * the wrong channel */ + pubsub_add_pub_(c, &btmp, get_channel_id("hithere"), + get_message_id("bunch_of_coconuts"), + get_msg_type_id("string"), + 0 /* flags */, + "somewhere.c", 22); + pubsub_connector_free(c); + }; + + setup_full_capture_of_logs(LOG_WARN); + dispatcher = pubsub_builder_finalize(b, NULL); + b = NULL; + tt_assert(dispatcher == NULL); + + expect_log_msg_containing("Message \"bunch_of_coconuts\" is associated " + "with multiple inconsistent message types."); + + done: + pubsub_builder_free(b); + dispatch_free(dispatcher); + teardown_capture_of_logs(); +} + +/* The same module can't publish and subscribe the same message */ +static void +test_pubsub_build_pubsub_same(void *arg) +{ + (void)arg; + pubsub_builder_t *b = NULL; + dispatch_t *dispatcher = NULL; + pubsub_connector_t *c = NULL; + + b = pubsub_builder_new(); + seed_pubsub_builder_basic(b); + + { + c = pubsub_connector_for_subsystem(b, get_subsys_id("sys1")); + // already publishing this. + DISPATCH_ADD_SUB(c, main, bunch_of_coconuts); + pubsub_connector_free(c); + }; + + setup_full_capture_of_logs(LOG_WARN); + dispatcher = pubsub_builder_finalize(b, NULL); + b = NULL; + tt_assert(dispatcher == NULL); + + expect_log_msg_containing("Message \"bunch_of_coconuts\" is published " + "and subscribed by the same subsystem \"sys1\"."); + + done: + pubsub_builder_free(b); + dispatch_free(dispatcher); + teardown_capture_of_logs(); +} + +/* More than one subsystem may publish or subscribe, and that's okay. */ +static void +test_pubsub_build_pubsub_multi(void *arg) +{ + (void)arg; + pubsub_builder_t *b = NULL; + dispatch_t *dispatcher = NULL; + pubsub_connector_t *c = NULL; + + b = pubsub_builder_new(); + seed_pubsub_builder_basic(b); + pub_binding_t btmp; + + { + c = pubsub_connector_for_subsystem(b, get_subsys_id("sys3")); + DISPATCH_ADD_SUB(c, main, bunch_of_coconuts); + pubsub_add_pub_(c, &btmp, get_channel_id("main"), + get_message_id("yes_we_have_no"), + get_msg_type_id("string"), + 0 /* flags */, + "somewhere.c", 22); + pubsub_connector_free(c); + }; + + dispatcher = pubsub_builder_finalize(b, NULL); + b = NULL; + tt_assert(dispatcher); + + // 1 subscribers + tt_int_op(1, OP_EQ, + dispatcher->table[get_message_id("yes_we_have_no")]->n_enabled); + // 2 subscribers. + dtbl_entry_t *ent = + dispatcher->table[get_message_id("bunch_of_coconuts")]; + tt_int_op(2, OP_EQ, ent->n_enabled); + tt_int_op(2, OP_EQ, ent->n_fns); + tt_ptr_op(ent->rcv[0].fn, OP_EQ, recv_fn__bunch_of_coconuts); + tt_ptr_op(ent->rcv[1].fn, OP_EQ, recv_fn__bunch_of_coconuts); + + done: + pubsub_builder_free(b); + dispatch_free(dispatcher); +} + +static void +some_other_coconut_hook(const msg_t *m) +{ + (void)m; +} + +/* Subscribe hooks should be build correctly when there are a bunch of + * them. */ +static void +test_pubsub_build_sub_many(void *arg) +{ + (void)arg; + pubsub_builder_t *b = NULL; + dispatch_t *dispatcher = NULL; + pubsub_connector_t *c = NULL; + char *sysname = NULL; + b = pubsub_builder_new(); + seed_pubsub_builder_basic(b); + + int i; + for (i = 1; i < 100; ++i) { + tor_asprintf(&sysname, "system%d",i); + c = pubsub_connector_for_subsystem(b, get_subsys_id(sysname)); + if (i % 7) { + DISPATCH_ADD_SUB(c, main, bunch_of_coconuts); + } else { + pubsub_add_sub_(c, some_other_coconut_hook, + get_channel_id("main"), + get_message_id("bunch_of_coconuts"), + get_msg_type_id("int"), + 0 /* flags */, + "somewhere.c", 22); + } + pubsub_connector_free(c); + tor_free(sysname); + }; + + dispatcher = pubsub_builder_finalize(b, NULL); + b = NULL; + tt_assert(dispatcher); + + dtbl_entry_t *ent = + dispatcher->table[get_message_id("bunch_of_coconuts")]; + tt_int_op(100, OP_EQ, ent->n_enabled); + tt_int_op(100, OP_EQ, ent->n_fns); + tt_ptr_op(ent->rcv[0].fn, OP_EQ, recv_fn__bunch_of_coconuts); + tt_ptr_op(ent->rcv[1].fn, OP_EQ, recv_fn__bunch_of_coconuts); + tt_ptr_op(ent->rcv[76].fn, OP_EQ, recv_fn__bunch_of_coconuts); + tt_ptr_op(ent->rcv[77].fn, OP_EQ, some_other_coconut_hook); + tt_ptr_op(ent->rcv[78].fn, OP_EQ, recv_fn__bunch_of_coconuts); + + done: + pubsub_builder_free(b); + dispatch_free(dispatcher); + tor_free(sysname); +} + +/* The same subsystem can only declare one publish or subscribe. */ +static void +test_pubsub_build_pubsub_redundant(void *arg) +{ + (void)arg; + pubsub_builder_t *b = NULL; + dispatch_t *dispatcher = NULL; + pubsub_connector_t *c = NULL; + + b = pubsub_builder_new(); + seed_pubsub_builder_basic(b); + pub_binding_t btmp; + + { + c = pubsub_connector_for_subsystem(b, get_subsys_id("sys2")); + DISPATCH_ADD_SUB(c, main, bunch_of_coconuts); + pubsub_add_pub_(c, &btmp, get_channel_id("main"), + get_message_id("yes_we_have_no"), + get_msg_type_id("string"), + 0 /* flags */, + "somewhere.c", 22); + pubsub_connector_free(c); + }; + + setup_full_capture_of_logs(LOG_WARN); + dispatcher = pubsub_builder_finalize(b, NULL); + b = NULL; + tt_assert(dispatcher == NULL); + + expect_log_msg_containing( + "Message \"yes_we_have_no\" is configured to be published by " + "subsystem \"sys2\" more than once."); + expect_log_msg_containing( + "Message \"bunch_of_coconuts\" is configured to be subscribed by " + "subsystem \"sys2\" more than once."); + + done: + pubsub_builder_free(b); + dispatch_free(dispatcher); + teardown_capture_of_logs(); +} + +/* It's fine to declare the excl flag. */ +static void +test_pubsub_build_excl_ok(void *arg) +{ + (void)arg; + pubsub_builder_t *b = NULL; + dispatch_t *dispatcher = NULL; + + b = pubsub_builder_new(); + // Try one excl/excl pair and one excl/non pair. + seed_dispatch_builder(b, DISP_FLAG_EXCL, 0, + DISP_FLAG_EXCL, DISP_FLAG_EXCL); + + dispatcher = pubsub_builder_finalize(b, NULL); + b = NULL; + tt_assert(dispatcher); + + // 1 subscribers + tt_int_op(1, OP_EQ, + dispatcher->table[get_message_id("yes_we_have_no")]->n_enabled); + // 1 subscriber. + tt_int_op(1, OP_EQ, + dispatcher->table[get_message_id("bunch_of_coconuts")]->n_enabled); + + done: + pubsub_builder_free(b); + dispatch_free(dispatcher); +} + +/* but if you declare the excl flag, you need to mean it. */ +static void +test_pubsub_build_excl_bad(void *arg) +{ + (void)arg; + pubsub_builder_t *b = NULL; + dispatch_t *dispatcher = NULL; + pubsub_connector_t *c = NULL; + + b = pubsub_builder_new(); + seed_dispatch_builder(b, DISP_FLAG_EXCL, DISP_FLAG_EXCL, + 0, 0); + + { + c = pubsub_connector_for_subsystem(b, get_subsys_id("sys3")); + DISPATCH_ADD_PUB_(c, main, bunch_of_coconuts, 0); + DISPATCH_ADD_SUB_(c, main, yes_we_have_no, 0); + pubsub_connector_free(c); + }; + + setup_full_capture_of_logs(LOG_WARN); + dispatcher = pubsub_builder_finalize(b, NULL); + b = NULL; + tt_assert(dispatcher == NULL); + + expect_log_msg_containing("has multiple publishers, but at least one is " + "marked as exclusive."); + expect_log_msg_containing("has multiple subscribers, but at least one is " + "marked as exclusive."); + + done: + pubsub_builder_free(b); + dispatch_free(dispatcher); + teardown_capture_of_logs(); +} + +#define T(name, flags) \ + { #name, test_pubsub_build_ ## name , (flags), NULL, NULL } + +struct testcase_t pubsub_build_tests[] = { + T(types_ok, TT_FORK), + T(types_decls_conflict, TT_FORK), + T(unused_message, TT_FORK), + T(missing_pubsub, TT_FORK), + T(stub_pubsub, TT_FORK), + T(channels_conflict, TT_FORK), + T(types_conflict, TT_FORK), + T(pubsub_same, TT_FORK), + T(pubsub_multi, TT_FORK), + T(sub_many, TT_FORK), + T(pubsub_redundant, TT_FORK), + T(excl_ok, TT_FORK), + T(excl_bad, TT_FORK), + END_OF_TESTCASES +}; diff --git a/src/test/test_pubsub_msg.c b/src/test/test_pubsub_msg.c new file mode 100644 index 0000000000..73c7c9f540 --- /dev/null +++ b/src/test/test_pubsub_msg.c @@ -0,0 +1,305 @@ +/* Copyright (c) 2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define DISPATCH_PRIVATE + +#include "test/test.h" + +#include "lib/dispatch/dispatch.h" +#include "lib/dispatch/dispatch_naming.h" +#include "lib/dispatch/dispatch_st.h" +#include "lib/dispatch/msgtypes.h" +#include "lib/pubsub/pubsub_flags.h" +#include "lib/pubsub/pub_binding_st.h" +#include "lib/pubsub/pubsub_build.h" +#include "lib/pubsub/pubsub_builder_st.h" +#include "lib/pubsub/pubsub_connect.h" +#include "lib/pubsub/pubsub_publish.h" + +#include "lib/log/escape.h" +#include "lib/malloc/malloc.h" +#include "lib/string/printf.h" + +#include +#include + +static char * +ex_str_fmt(msg_aux_data_t aux) +{ + return esc_for_log(aux.ptr); +} +static void +ex_str_free(msg_aux_data_t aux) +{ + tor_free_(aux.ptr); +} +static dispatch_typefns_t stringfns = { + .free_fn = ex_str_free, + .fmt_fn = ex_str_fmt +}; + +// We're using the lowest-level publish/subscribe logic here, to avoid the +// pubsub_macros.h macros and just test the dispatch core. We'll use a string +// type for everything. + +#define DECLARE_MESSAGE(suffix) \ + static pub_binding_t pub_binding_##suffix; \ + static int msg_received_##suffix = 0; \ + static void recv_msg_##suffix(const msg_t *m) { \ + (void)m; \ + ++msg_received_##suffix; \ + } \ + EAT_SEMICOLON + +#define ADD_PUBLISH(binding_suffix, subsys, channel, msg, flags) \ + STMT_BEGIN { \ + con = pubsub_connector_for_subsystem(builder, \ + get_subsys_id(#subsys)); \ + pubsub_add_pub_(con, &pub_binding_##binding_suffix, \ + get_channel_id(#channel), \ + get_message_id(#msg), get_msg_type_id("string"), \ + (flags), __FILE__, __LINE__); \ + pubsub_connector_free(con); \ + } STMT_END + +#define ADD_SUBSCRIBE(hook_suffix, subsys, channel, msg, flags) \ + STMT_BEGIN { \ + con = pubsub_connector_for_subsystem(builder, \ + get_subsys_id(#subsys)); \ + pubsub_add_sub_(con, recv_msg_##hook_suffix, \ + get_channel_id(#channel), \ + get_message_id(#msg), get_msg_type_id("string"), \ + (flags), __FILE__, __LINE__); \ + pubsub_connector_free(con); \ + } STMT_END + +#define SEND(binding_suffix, val) \ + STMT_BEGIN { \ + msg_aux_data_t data_; \ + data_.ptr = tor_strdup(val); \ + pubsub_pub_(&pub_binding_##binding_suffix, data_); \ + } STMT_END + +DECLARE_MESSAGE(msg1); +DECLARE_MESSAGE(msg2); +DECLARE_MESSAGE(msg3); +DECLARE_MESSAGE(msg4); +DECLARE_MESSAGE(msg5); + +static smartlist_t *strings_received = NULL; +static void +recv_msg_copy_string(const msg_t *m) +{ + const char *s = m->aux_data__.ptr; + smartlist_add(strings_received, tor_strdup(s)); +} + +static void * +setup_dispatcher(const struct testcase_t *testcase) +{ + (void)testcase; + pubsub_builder_t *builder = pubsub_builder_new(); + pubsub_connector_t *con; + + { + con = pubsub_connector_for_subsystem(builder, get_subsys_id("types")); + pubsub_connector_register_type_(con, + get_msg_type_id("string"), + &stringfns, + "nowhere.c", 99); + pubsub_connector_free(con); + } + // message1 has one publisher and one subscriber. + ADD_PUBLISH(msg1, sys1, main, message1, 0); + ADD_SUBSCRIBE(msg1, sys2, main, message1, 0); + + // message2 has a publisher and a stub subscriber. + ADD_PUBLISH(msg2, sys1, main, message2, 0); + ADD_SUBSCRIBE(msg2, sys2, main, message2, DISP_FLAG_STUB); + + // message3 has a publisher and three subscribers. + ADD_PUBLISH(msg3, sys1, main, message3, 0); + ADD_SUBSCRIBE(msg3, sys2, main, message3, 0); + ADD_SUBSCRIBE(msg3, sys3, main, message3, 0); + ADD_SUBSCRIBE(msg3, sys4, main, message3, 0); + + // message4 has one publisher and two subscribers, but it's on another + // channel. + ADD_PUBLISH(msg4, sys2, other, message4, 0); + ADD_SUBSCRIBE(msg4, sys1, other, message4, 0); + ADD_SUBSCRIBE(msg4, sys3, other, message4, 0); + + // message5 has a huge number of recipients. + ADD_PUBLISH(msg5, sys3, main, message5, 0); + ADD_SUBSCRIBE(msg5, sys4, main, message5, 0); + ADD_SUBSCRIBE(msg5, sys5, main, message5, 0); + ADD_SUBSCRIBE(msg5, sys6, main, message5, 0); + ADD_SUBSCRIBE(msg5, sys7, main, message5, 0); + ADD_SUBSCRIBE(msg5, sys8, main, message5, 0); + for (int i = 0; i < 1000-5; ++i) { + char *sys; + tor_asprintf(&sys, "xsys-%d", i); + con = pubsub_connector_for_subsystem(builder, get_subsys_id(sys)); + pubsub_add_sub_(con, recv_msg_copy_string, + get_channel_id("main"), + get_message_id("message5"), + get_msg_type_id("string"), 0, "here", 100); + pubsub_connector_free(con); + tor_free(sys); + } + + return pubsub_builder_finalize(builder, NULL); +} + +static int +cleanup_dispatcher(const struct testcase_t *testcase, void *dispatcher_) +{ + (void)testcase; + dispatch_t *dispatcher = dispatcher_; + dispatch_free(dispatcher); + return 1; +} + +static const struct testcase_setup_t dispatcher_setup = { + setup_dispatcher, cleanup_dispatcher +}; + +static void +test_pubsub_msg_minimal(void *arg) +{ + dispatch_t *d = arg; + + tt_int_op(0, OP_EQ, msg_received_msg1); + SEND(msg1, "hello world"); + tt_int_op(0, OP_EQ, msg_received_msg1); // hasn't actually arrived yet. + + tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 1000)); + tt_int_op(1, OP_EQ, msg_received_msg1); // we got the message! + + done: + ; +} + +static void +test_pubsub_msg_send_to_stub(void *arg) +{ + dispatch_t *d = arg; + + tt_int_op(0, OP_EQ, msg_received_msg2); + SEND(msg2, "hello silence"); + tt_int_op(0, OP_EQ, msg_received_msg2); // hasn't actually arrived yet. + + tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 1000)); + tt_int_op(0, OP_EQ, msg_received_msg2); // doesn't arrive -- stub hook. + + done: + ; +} + +static void +test_pubsub_msg_cancel_msgs(void *arg) +{ + dispatch_t *d = arg; + + tt_int_op(0, OP_EQ, msg_received_msg1); + for (int i = 0; i < 100; ++i) { + SEND(msg1, "hello world"); + } + tt_int_op(0, OP_EQ, msg_received_msg1); // hasn't actually arrived yet. + + tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 10)); + tt_int_op(10, OP_EQ, msg_received_msg1); // we got the message 10 times. + + // At this point, the dispatcher will be freed with queued, undelivered + // messages. + done: + ; +} + +struct alertfn_target { + dispatch_t *d; + channel_id_t ch; + int count; +}; +static void +alertfn_generic(dispatch_t *d, channel_id_t ch, void *arg) +{ + struct alertfn_target *t = arg; + tt_ptr_op(d, OP_EQ, t->d); + tt_int_op(ch, OP_EQ, t->ch); + ++t->count; + done: + ; +} + +static void +test_pubsub_msg_alertfns(void *arg) +{ + dispatch_t *d = arg; + struct alertfn_target ch1_a = { d, get_channel_id("main"), 0 }; + struct alertfn_target ch2_a = { d, get_channel_id("other"), 0 }; + + tt_int_op(0, OP_EQ, + dispatch_set_alert_fn(d, get_channel_id("main"), + alertfn_generic, &ch1_a)); + tt_int_op(0, OP_EQ, + dispatch_set_alert_fn(d, get_channel_id("other"), + alertfn_generic, &ch2_a)); + + SEND(msg3, "hello"); + tt_int_op(ch1_a.count, OP_EQ, 1); + SEND(msg3, "world"); + tt_int_op(ch1_a.count, OP_EQ, 1); // only the first message sends an alert + tt_int_op(ch2_a.count, OP_EQ, 0); // no alert for 'other' + + SEND(msg4, "worse things happen in C"); + tt_int_op(ch2_a.count, OP_EQ, 1); + + // flush the first (main) channel... + tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 1000)); + tt_int_op(6, OP_EQ, msg_received_msg3); // 3 subscribers, 2 instances. + + // now that the main channel is flushed, sending another message on it + // starts another alert. + tt_int_op(ch1_a.count, OP_EQ, 1); + SEND(msg1, "plover"); + tt_int_op(ch1_a.count, OP_EQ, 2); + tt_int_op(ch2_a.count, OP_EQ, 1); + + done: + ; +} + +/* try more than N_FAST_FNS hooks on msg5 */ +static void +test_pubsub_msg_many_hooks(void *arg) +{ + dispatch_t *d = arg; + strings_received = smartlist_new(); + + tt_int_op(0, OP_EQ, msg_received_msg5); + SEND(msg5, "hello world"); + tt_int_op(0, OP_EQ, msg_received_msg5); + tt_int_op(0, OP_EQ, smartlist_len(strings_received)); + + tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 100000)); + tt_int_op(5, OP_EQ, msg_received_msg5); + tt_int_op(995, OP_EQ, smartlist_len(strings_received)); + + done: + SMARTLIST_FOREACH(strings_received, char *, s, tor_free(s)); + smartlist_free(strings_received); +} + +#define T(name) \ + { #name, test_pubsub_msg_ ## name , TT_FORK, \ + &dispatcher_setup, NULL } + +struct testcase_t pubsub_msg_tests[] = { + T(minimal), + T(send_to_stub), + T(cancel_msgs), + T(alertfns), + T(many_hooks), + END_OF_TESTCASES +}; diff --git a/src/test/test_rebind.sh b/src/test/test_rebind.sh index ea2012957e..e0d8394d38 100755 --- a/src/test/test_rebind.sh +++ b/src/test/test_rebind.sh @@ -7,7 +7,7 @@ if test "$UNAME_OS" = 'CYGWIN' || \ test "$UNAME_OS" = 'MSYS' || \ test "$UNAME_OS" = 'MINGW'; then if test "$APPVEYOR" = 'True'; then - echo "This test is disabled on Windows CI, as it requires firewall examptions. Skipping." >&2 + echo "This test is disabled on Windows CI, as it requires firewall exemptions. Skipping." >&2 exit 77 fi fi @@ -15,10 +15,15 @@ fi exitcode=0 tmpdir= -clean () { test -n "$tmpdir" && test -d "$tmpdir" && rm -rf "$tmpdir" || :; } +clean () { + if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then + rm -rf "$tmpdir" + fi +} + trap clean EXIT HUP INT TERM -tmpdir="`mktemp -d -t tor_rebind_test.XXXXXX`" +tmpdir="$(mktemp -d -t tor_rebind_test.XXXXXX)" if [ -z "$tmpdir" ]; then echo >&2 mktemp failed exit 2 diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c index 0623583511..c65279fb25 100644 --- a/src/test/test_relaycell.c +++ b/src/test/test_relaycell.c @@ -17,6 +17,7 @@ #include "core/or/circuitbuild.h" #include "core/or/circuitlist.h" #include "core/or/connection_edge.h" +#include "core/or/sendme.h" #include "core/or/relay.h" #include "test/test.h" #include "test/log_test_helpers.h" @@ -812,7 +813,11 @@ test_circbw_relay(void *arg) ASSERT_UNCOUNTED_BW(); /* Sendme on circuit with non-full window: counted */ - PACK_CELL(0, RELAY_COMMAND_SENDME, "Data1234"); + PACK_CELL(0, RELAY_COMMAND_SENDME, ""); + /* Recording a cell, the window is updated after decryption so off by one in + * order to record and then we process it with the proper window. */ + circ->cpath->package_window = 901; + sendme_record_cell_digest_on_circ(TO_CIRCUIT(circ), circ->cpath); circ->cpath->package_window = 900; connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); diff --git a/src/test/test_relaycrypt.c b/src/test/test_relaycrypt.c index fe6889e521..4bbf07c3ec 100644 --- a/src/test/test_relaycrypt.c +++ b/src/test/test_relaycrypt.c @@ -3,6 +3,8 @@ * Copyright (c) 2007-2019, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +#define CRYPT_PATH_PRIVATE + #include "core/or/or.h" #include "core/or/circuitbuild.h" #define CIRCUITLIST_PRIVATE @@ -10,7 +12,7 @@ #include "lib/crypt_ops/crypto_rand.h" #include "core/or/relay.h" #include "core/crypto/relay_crypto.h" - +#include "core/or/crypt_path.h" #include "core/or/cell_st.h" #include "core/or/or_circuit_st.h" #include "core/or/origin_circuit_st.h" @@ -49,10 +51,10 @@ testing_circuitset_setup(const struct testcase_t *testcase) cs->origin_circ->base_.purpose = CIRCUIT_PURPOSE_C_GENERAL; for (i=0; i<3; ++i) { crypt_path_t *hop = tor_malloc_zero(sizeof(*hop)); - relay_crypto_init(&hop->crypto, KEY_MATERIAL[i], sizeof(KEY_MATERIAL[i]), - 0, 0); + relay_crypto_init(&hop->pvt_crypto, KEY_MATERIAL[i], + sizeof(KEY_MATERIAL[i]), 0, 0); hop->state = CPATH_STATE_OPEN; - onion_append_to_cpath(&cs->origin_circ->cpath, hop); + cpath_extend_linked_list(&cs->origin_circ->cpath, hop); tt_ptr_op(hop, OP_EQ, cs->origin_circ->cpath->prev); } diff --git a/src/test/test_rng.c b/src/test/test_rng.c index c749de112a..dcf08fff1d 100644 --- a/src/test/test_rng.c +++ b/src/test/test_rng.c @@ -46,7 +46,7 @@ main(int argc, char **argv) return 1; } } -#endif +#endif /* 0 */ crypto_fast_rng_t *rng = crypto_fast_rng_new(); while (1) { diff --git a/src/test/test_router.c b/src/test/test_router.c index ea0ee3e84c..5477ab51e9 100644 --- a/src/test/test_router.c +++ b/src/test/test_router.c @@ -100,6 +100,9 @@ test_router_dump_router_to_string_no_bridge_distribution_method(void *arg) router = (routerinfo_t*)router_get_my_routerinfo(); tt_ptr_op(router, !=, NULL); + /* The real router_get_my_routerinfo() looks up onion_curve25519_pkey using + * get_current_curve25519_keypair(), but we don't initialise static data in + * this test. */ router->onion_curve25519_pkey = &ntor_keypair.pubkey; /* Generate our server descriptor and ensure that the substring diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c index 727fa5660f..0c6b533698 100644 --- a/src/test/test_routerkeys.c +++ b/src/test/test_routerkeys.c @@ -399,7 +399,7 @@ test_routerkeys_ed_key_init_split(void *arg) tt_assert(kp2 != NULL); tt_assert(cert == NULL); tt_mem_op(&kp1->pubkey, OP_EQ, &kp2->pubkey, sizeof(kp2->pubkey)); - tt_assert(tor_mem_is_zero((char*)kp2->seckey.seckey, + tt_assert(fast_mem_is_zero((char*)kp2->seckey.seckey, sizeof(kp2->seckey.seckey))); ed25519_keypair_free(kp2); kp2 = NULL; @@ -409,7 +409,7 @@ test_routerkeys_ed_key_init_split(void *arg) tt_assert(kp2 != NULL); tt_assert(cert == NULL); tt_mem_op(&kp1->pubkey, OP_EQ, &kp2->pubkey, sizeof(kp2->pubkey)); - tt_assert(tor_mem_is_zero((char*)kp2->seckey.seckey, + tt_assert(fast_mem_is_zero((char*)kp2->seckey.seckey, sizeof(kp2->seckey.seckey))); ed25519_keypair_free(kp2); kp2 = NULL; @@ -455,11 +455,11 @@ test_routerkeys_ed_keys_init_all(void *arg) options->TestingLinkKeySlop = 2*3600; #ifdef _WIN32 - mkdir(dir); - mkdir(keydir); + tt_int_op(0, OP_EQ, mkdir(dir)); + tt_int_op(0, OP_EQ, mkdir(keydir)); #else - mkdir(dir, 0700); - mkdir(keydir, 0700); + tt_int_op(0, OP_EQ, mkdir(dir, 0700)); + tt_int_op(0, OP_EQ, mkdir(keydir, 0700)); #endif /* defined(_WIN32) */ options->DataDirectory = dir; diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c index 84ec8cc462..6d596e87ea 100644 --- a/src/test/test_routerlist.c +++ b/src/test/test_routerlist.c @@ -631,7 +631,7 @@ mock_clock_skew_warning(const connection_t *conn, long apparent_skew, (void)conn; mock_apparent_skew = apparent_skew; tt_int_op(trusted, OP_EQ, 1); - tt_int_op(domain, OP_EQ, LD_GENERAL); + tt_i64_op(domain, OP_EQ, LD_GENERAL); tt_str_op(received, OP_EQ, "microdesc flavor consensus"); tt_str_op(source, OP_EQ, "CONSENSUS"); done: diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c index c45f0e1595..cc73e6c20a 100644 --- a/src/test/test_routerset.c +++ b/src/test/test_routerset.c @@ -1765,7 +1765,7 @@ NS(node_get_by_nickname)(const char *nickname, unsigned flags) * Structural test for routerset_get_all_nodes, when the nodelist has no nodes. */ -NS_DECL(smartlist_t *, nodelist_get_list, (void)); +NS_DECL(const smartlist_t *, nodelist_get_list, (void)); static smartlist_t *NS(mock_smartlist); @@ -1795,7 +1795,7 @@ NS(test_main)(void *arg) ; } -smartlist_t * +const smartlist_t * NS(nodelist_get_list)(void) { CALLED(nodelist_get_list)++; @@ -1811,7 +1811,7 @@ NS(nodelist_get_list)(void) * the running_only flag is set, but the nodes are not running. */ -NS_DECL(smartlist_t *, nodelist_get_list, (void)); +NS_DECL(const smartlist_t *, nodelist_get_list, (void)); static smartlist_t *NS(mock_smartlist); static node_t NS(mock_node); @@ -1844,7 +1844,7 @@ NS(test_main)(void *arg) ; } -smartlist_t * +const smartlist_t * NS(nodelist_get_list)(void) { CALLED(nodelist_get_list)++; diff --git a/src/test/test_rust.sh b/src/test/test_rust.sh index 00b3e88d37..804d2ada36 100755 --- a/src/test/test_rust.sh +++ b/src/test/test_rust.sh @@ -14,11 +14,12 @@ rustc_host=$(rustc -vV | grep host | sed 's/host: //') for cargo_toml_dir in "${abs_top_srcdir:-../../..}"/src/rust/*; do if [ -e "${cargo_toml_dir}/Cargo.toml" ]; then + # shellcheck disable=SC2086 cd "${abs_top_builddir:-../../..}/src/rust" && \ CARGO_TARGET_DIR="${abs_top_builddir:-../../..}/src/rust/target" \ - "${CARGO:-cargo}" test ${CARGO_ONLINE-"--frozen"} \ + "${CARGO:-cargo}" test "${CARGO_ONLINE-'--frozen'}" \ --features "test_linking_hack" \ - --target $rustc_host \ + --target "$rustc_host" \ ${EXTRA_CARGO_OPTIONS} \ --manifest-path "${cargo_toml_dir}/Cargo.toml" || exitcode=1 fi diff --git a/src/test/test_sendme.c b/src/test/test_sendme.c new file mode 100644 index 0000000000..eb402232bc --- /dev/null +++ b/src/test/test_sendme.c @@ -0,0 +1,365 @@ +/* Copyright (c) 2014-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/* Unit tests for handling different kinds of relay cell */ + +#define CIRCUITLIST_PRIVATE +#define NETWORKSTATUS_PRIVATE +#define SENDME_PRIVATE +#define RELAY_PRIVATE + +#include "core/or/circuit_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/circuitlist.h" +#include "core/or/relay.h" +#include "core/or/sendme.h" + +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/networkstatus_st.h" + +#include "lib/crypt_ops/crypto_digest.h" + +#include "test/test.h" +#include "test/log_test_helpers.h" + +static void +setup_mock_consensus(void) +{ + current_md_consensus = current_ns_consensus = + tor_malloc_zero(sizeof(networkstatus_t)); + current_md_consensus->net_params = smartlist_new(); + current_md_consensus->routerstatus_list = smartlist_new(); +} + +static void +free_mock_consensus(void) +{ + SMARTLIST_FOREACH(current_md_consensus->routerstatus_list, void *, r, + tor_free(r)); + smartlist_free(current_md_consensus->routerstatus_list); + smartlist_free(current_ns_consensus->net_params); + tor_free(current_ns_consensus); +} + +static void +test_v1_record_digest(void *arg) +{ + or_circuit_t *or_circ = NULL; + circuit_t *circ = NULL; + + (void) arg; + + /* Create our dummy circuit. */ + or_circ = or_circuit_new(1, NULL); + /* Points it to the OR circuit now. */ + circ = TO_CIRCUIT(or_circ); + + /* The package window has to be a multiple of CIRCWINDOW_INCREMENT minus 1 + * in order to catched the CIRCWINDOW_INCREMENT-nth cell. Try something that + * shouldn't be noted. */ + circ->package_window = CIRCWINDOW_INCREMENT; + sendme_record_cell_digest_on_circ(circ, NULL); + tt_assert(!circ->sendme_last_digests); + + /* This should work now. Package window at CIRCWINDOW_INCREMENT + 1. */ + circ->package_window++; + sendme_record_cell_digest_on_circ(circ, NULL); + tt_assert(circ->sendme_last_digests); + tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1); + + /* Next cell in the package window shouldn't do anything. */ + circ->package_window++; + sendme_record_cell_digest_on_circ(circ, NULL); + tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1); + + /* The next CIRCWINDOW_INCREMENT should add one more digest. */ + circ->package_window = (CIRCWINDOW_INCREMENT * 2) + 1; + sendme_record_cell_digest_on_circ(circ, NULL); + tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 2); + + done: + circuit_free_(circ); +} + +static void +test_v1_consensus_params(void *arg) +{ + (void) arg; + + setup_mock_consensus(); + tt_assert(current_md_consensus); + + /* Both zeroes. */ + smartlist_add(current_md_consensus->net_params, + (void *) "sendme_emit_min_version=0"); + smartlist_add(current_md_consensus->net_params, + (void *) "sendme_accept_min_version=0"); + tt_int_op(get_emit_min_version(), OP_EQ, 0); + tt_int_op(get_accept_min_version(), OP_EQ, 0); + smartlist_clear(current_md_consensus->net_params); + + /* Both ones. */ + smartlist_add(current_md_consensus->net_params, + (void *) "sendme_emit_min_version=1"); + smartlist_add(current_md_consensus->net_params, + (void *) "sendme_accept_min_version=1"); + tt_int_op(get_emit_min_version(), OP_EQ, 1); + tt_int_op(get_accept_min_version(), OP_EQ, 1); + smartlist_clear(current_md_consensus->net_params); + + /* Different values from each other. */ + smartlist_add(current_md_consensus->net_params, + (void *) "sendme_emit_min_version=1"); + smartlist_add(current_md_consensus->net_params, + (void *) "sendme_accept_min_version=0"); + tt_int_op(get_emit_min_version(), OP_EQ, 1); + tt_int_op(get_accept_min_version(), OP_EQ, 0); + smartlist_clear(current_md_consensus->net_params); + + /* Validate is the cell version is coherent with our internal default value + * and the one in the consensus. */ + smartlist_add(current_md_consensus->net_params, + (void *) "sendme_accept_min_version=1"); + /* Minimum acceptable value is 1. */ + tt_int_op(cell_version_can_be_handled(1), OP_EQ, true); + /* Minimum acceptable value is 1 so a cell version of 0 is refused. */ + tt_int_op(cell_version_can_be_handled(0), OP_EQ, false); + + done: + free_mock_consensus(); +} + +static void +test_v1_build_cell(void *arg) +{ + uint8_t payload[RELAY_PAYLOAD_SIZE], digest[DIGEST_LEN]; + ssize_t ret; + crypto_digest_t *cell_digest = NULL; + or_circuit_t *or_circ = NULL; + circuit_t *circ = NULL; + + (void) arg; + + or_circ = or_circuit_new(1, NULL); + circ = TO_CIRCUIT(or_circ); + circ->sendme_last_digests = smartlist_new(); + + cell_digest = crypto_digest_new(); + tt_assert(cell_digest); + crypto_digest_add_bytes(cell_digest, "AAAAAAAAAAAAAAAAAAAA", 20); + crypto_digest_get_digest(cell_digest, (char *) digest, sizeof(digest)); + smartlist_add(circ->sendme_last_digests, tor_memdup(digest, sizeof(digest))); + + /* SENDME v1 payload is 3 bytes + 20 bytes digest. See spec. */ + ret = build_cell_payload_v1(digest, payload); + tt_int_op(ret, OP_EQ, 23); + + /* Validation. */ + + /* An empty payload means SENDME version 0 thus valid. */ + tt_int_op(sendme_is_valid(circ, payload, 0), OP_EQ, true); + /* Current phoney digest should have been popped. */ + tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0); + + /* An unparseable cell means invalid. */ + setup_full_capture_of_logs(LOG_INFO); + tt_int_op(sendme_is_valid(circ, (const uint8_t *) "A", 1), OP_EQ, false); + expect_log_msg_containing("Unparseable SENDME cell received. " + "Closing circuit."); + teardown_capture_of_logs(); + + /* No cell digest recorded for this. */ + setup_full_capture_of_logs(LOG_INFO); + tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, false); + expect_log_msg_containing("We received a SENDME but we have no cell digests " + "to match. Closing circuit."); + teardown_capture_of_logs(); + + /* Note the wrong digest in the circuit, cell should fail validation. */ + circ->package_window = CIRCWINDOW_INCREMENT + 1; + sendme_record_cell_digest_on_circ(circ, NULL); + tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1); + setup_full_capture_of_logs(LOG_INFO); + tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, false); + /* After a validation, the last digests is always popped out. */ + tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0); + expect_log_msg_containing("SENDME v1 cell digest do not match."); + teardown_capture_of_logs(); + + /* Record the cell digest into the circuit, cell should validate. */ + memcpy(or_circ->crypto.sendme_digest, digest, sizeof(digest)); + circ->package_window = CIRCWINDOW_INCREMENT + 1; + sendme_record_cell_digest_on_circ(circ, NULL); + tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1); + tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, true); + /* After a validation, the last digests is always popped out. */ + tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0); + + done: + crypto_digest_free(cell_digest); + circuit_free_(circ); +} + +static void +test_cell_payload_pad(void *arg) +{ + size_t pad_offset, payload_len, expected_offset; + + (void) arg; + + /* Offset should be 0, not enough room for padding. */ + payload_len = RELAY_PAYLOAD_SIZE; + pad_offset = get_pad_cell_offset(payload_len); + tt_int_op(pad_offset, OP_EQ, 0); + tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE); + + /* Still no room because we keep 4 extra bytes. */ + pad_offset = get_pad_cell_offset(payload_len - 4); + tt_int_op(pad_offset, OP_EQ, 0); + tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE); + + /* We should have 1 byte of padding. Meaning, the offset should be the + * CELL_PAYLOAD_SIZE minus 1 byte. */ + expected_offset = CELL_PAYLOAD_SIZE - 1; + pad_offset = get_pad_cell_offset(payload_len - 5); + tt_int_op(pad_offset, OP_EQ, expected_offset); + tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE); + + /* Now some arbitrary small payload length. The cell size is header + 10 + + * extra 4 bytes we keep so the offset should be there. */ + expected_offset = RELAY_HEADER_SIZE + 10 + 4; + pad_offset = get_pad_cell_offset(10); + tt_int_op(pad_offset, OP_EQ, expected_offset); + tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE); + + /* Data length of 0. */ + expected_offset = RELAY_HEADER_SIZE + 4; + pad_offset = get_pad_cell_offset(0); + tt_int_op(pad_offset, OP_EQ, expected_offset); + tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE); + + done: + ; +} + +static void +test_cell_version_validation(void *arg) +{ + (void) arg; + + /* We currently only support up to SENDME_MAX_SUPPORTED_VERSION so we are + * going to test the boundaries there. */ + + tt_assert(cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION)); + + /* Version below our supported should pass. */ + tt_assert(cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION - 1)); + + /* Extra version from our supported should fail. */ + tt_assert(!cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION + 1)); + + /* Simple check for version 0. */ + tt_assert(cell_version_can_be_handled(0)); + + /* We MUST handle the default cell version that we emit or accept. */ + tt_assert(cell_version_can_be_handled(SENDME_EMIT_MIN_VERSION_DEFAULT)); + tt_assert(cell_version_can_be_handled(SENDME_ACCEPT_MIN_VERSION_DEFAULT)); + + done: + ; +} + +/* check our decisions about how much stuff to put into relay cells. */ +static void +test_package_payload_len(void *arg) +{ + (void)arg; + /* this is not a real circuit: it only has the fields needed for this + * test. */ + circuit_t *c = tor_malloc_zero(sizeof(circuit_t)); + + /* check initial conditions. */ + circuit_reset_sendme_randomness(c); + tt_assert(! c->have_sent_sufficiently_random_cell); + tt_int_op(c->send_randomness_after_n_cells, OP_GE, CIRCWINDOW_INCREMENT / 2); + tt_int_op(c->send_randomness_after_n_cells, OP_LT, CIRCWINDOW_INCREMENT); + + /* We have a bunch of cells before we need to send randomness, so the first + * few can be packaged full. */ + int initial = c->send_randomness_after_n_cells; + size_t n = connection_edge_get_inbuf_bytes_to_package(10000, 0, c); + tt_uint_op(RELAY_PAYLOAD_SIZE, OP_EQ, n); + n = connection_edge_get_inbuf_bytes_to_package(95000, 1, c); + tt_uint_op(RELAY_PAYLOAD_SIZE, OP_EQ, n); + tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 2); + + /* If package_partial isn't set, we won't package a partially full cell at + * all. */ + n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 0, c); + tt_int_op(n, OP_EQ, 0); + /* no change in our state, since nothing was sent. */ + tt_assert(! c->have_sent_sufficiently_random_cell); + tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 2); + + /* If package_partial is set and the partial cell is not going to have + * _enough_ randomness, we package it, but we don't consider ourselves to + * have sent a sufficiently random cell. */ + n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 1, c); + tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE-1); + tt_assert(! c->have_sent_sufficiently_random_cell); + tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 3); + + /* Make sure we set have_set_sufficiently_random_cell as appropriate. */ + n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-64, 1, c); + tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE-64); + tt_assert(c->have_sent_sufficiently_random_cell); + tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 4); + + /* Now let's look at what happens when we get down to zero. Since we have + * sent a sufficiently random cell, we will not force this one to have a gap. + */ + c->send_randomness_after_n_cells = 0; + n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c); + tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE); + /* Now these will be reset. */ + tt_assert(! c->have_sent_sufficiently_random_cell); + tt_int_op(c->send_randomness_after_n_cells, OP_GE, + CIRCWINDOW_INCREMENT / 2 - 1); + + /* What would happen if we hadn't sent a sufficiently random cell? */ + c->send_randomness_after_n_cells = 0; + n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c); + const size_t reduced_payload_size = RELAY_PAYLOAD_SIZE - 4 - 16; + tt_int_op(n, OP_EQ, reduced_payload_size); + /* Now these will be reset. */ + tt_assert(! c->have_sent_sufficiently_random_cell); + tt_int_op(c->send_randomness_after_n_cells, OP_GE, + CIRCWINDOW_INCREMENT / 2 - 1); + + /* Here is a fun case: if it's time to package a small cell, then + * package_partial==0 should mean we accept that many bytes. + */ + c->send_randomness_after_n_cells = 0; + n = connection_edge_get_inbuf_bytes_to_package(reduced_payload_size, 0, c); + tt_int_op(n, OP_EQ, reduced_payload_size); + + done: + tor_free(c); +} + +struct testcase_t sendme_tests[] = { + { "v1_record_digest", test_v1_record_digest, TT_FORK, + NULL, NULL }, + { "v1_consensus_params", test_v1_consensus_params, TT_FORK, + NULL, NULL }, + { "v1_build_cell", test_v1_build_cell, TT_FORK, + NULL, NULL }, + { "cell_payload_pad", test_cell_payload_pad, TT_FORK, + NULL, NULL }, + { "cell_version_validation", test_cell_version_validation, TT_FORK, + NULL, NULL }, + { "package_payload_len", test_package_payload_len, 0, NULL, NULL }, + + END_OF_TESTCASES +}; diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c index 5fa7e80d07..9c8703fa6f 100644 --- a/src/test/test_shared_random.c +++ b/src/test/test_shared_random.c @@ -449,12 +449,12 @@ test_sr_commit(void *arg) /* We should have a reveal value. */ tt_assert(commit_has_reveal_value(our_commit)); /* We should have a random value. */ - tt_assert(!tor_mem_is_zero((char *) our_commit->random_number, + tt_assert(!fast_mem_is_zero((char *) our_commit->random_number, sizeof(our_commit->random_number))); /* Commit and reveal timestamp should be the same. */ tt_u64_op(our_commit->commit_ts, OP_EQ, our_commit->reveal_ts); /* We should have a hashed reveal. */ - tt_assert(!tor_mem_is_zero(our_commit->hashed_reveal, + tt_assert(!fast_mem_is_zero(our_commit->hashed_reveal, sizeof(our_commit->hashed_reveal))); /* Do we have a valid encoded commit and reveal. Note the following only * tests if the generated values are correct. Their could be a bug in @@ -1081,70 +1081,85 @@ test_sr_get_majority_srv_from_votes(void *arg) smartlist_free(votes); } -/* Test utils that don't depend on authority state */ +/* Testing sr_srv_dup(). */ static void -test_utils_general(void *arg) +test_sr_svr_dup(void *arg) { - (void) arg; + (void)arg; - /* Testing sr_srv_dup(). */ - { - sr_srv_t *srv = NULL, *dup_srv = NULL; - const char *srv_value = - "1BDB7C3E973936E4D13A49F37C859B3DC69C429334CF9412E3FEF6399C52D47A"; - srv = tor_malloc_zero(sizeof(*srv)); - srv->num_reveals = 42; - memcpy(srv->value, srv_value, sizeof(srv->value)); - dup_srv = sr_srv_dup(srv); - tt_assert(dup_srv); - tt_u64_op(dup_srv->num_reveals, OP_EQ, srv->num_reveals); - tt_mem_op(dup_srv->value, OP_EQ, srv->value, sizeof(srv->value)); - tor_free(srv); - tor_free(dup_srv); - } + sr_srv_t *srv = NULL, *dup_srv = NULL; + const char *srv_value = + "1BDB7C3E973936E4D13A49F37C859B3DC69C429334CF9412E3FEF6399C52D47A"; + srv = tor_malloc_zero(sizeof(*srv)); + srv->num_reveals = 42; + memcpy(srv->value, srv_value, sizeof(srv->value)); + dup_srv = sr_srv_dup(srv); + tt_assert(dup_srv); + tt_u64_op(dup_srv->num_reveals, OP_EQ, srv->num_reveals); + tt_mem_op(dup_srv->value, OP_EQ, srv->value, sizeof(srv->value)); - /* Testing commitments_are_the_same(). Currently, the check is to test the - * value of the encoded commit so let's make sure that actually works. */ - { - /* Payload of 57 bytes that is the length of sr_commit_t->encoded_commit. - * 56 bytes of payload and a NUL terminated byte at the end ('\x00') - * which comes down to SR_COMMIT_BASE64_LEN + 1. */ - const char *payload = - "\x5d\xb9\x60\xb6\xcc\x51\x68\x52\x31\xd9\x88\x88\x71\x71\xe0\x30" - "\x59\x55\x7f\xcd\x61\xc0\x4b\x05\xb8\xcd\xc1\x48\xe9\xcd\x16\x1f" - "\x70\x15\x0c\xfc\xd3\x1a\x75\xd0\x93\x6c\xc4\xe0\x5c\xbe\xe2\x18" - "\xc7\xaf\x72\xb6\x7c\x9b\x52\x00"; - sr_commit_t commit1, commit2; - memcpy(commit1.encoded_commit, payload, sizeof(commit1.encoded_commit)); - memcpy(commit2.encoded_commit, payload, sizeof(commit2.encoded_commit)); - tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 1); - /* Let's corrupt one of them. */ - memset(commit1.encoded_commit, 'A', sizeof(commit1.encoded_commit)); - tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 0); - } + done: + tor_free(srv); + tor_free(dup_srv); +} - /* Testing commit_is_authoritative(). */ - { - crypto_pk_t *k = crypto_pk_new(); - char digest[DIGEST_LEN]; - sr_commit_t commit; +/* Testing commitments_are_the_same(). Currently, the check is to test the + * value of the encoded commit so let's make sure that actually works. */ +static void +test_commitments_are_the_same(void *arg) +{ + (void)arg; - tt_assert(!crypto_pk_generate_key(k)); + /* Payload of 57 bytes that is the length of sr_commit_t->encoded_commit. + * 56 bytes of payload and a NUL terminated byte at the end ('\x00') + * which comes down to SR_COMMIT_BASE64_LEN + 1. */ + const char *payload = + "\x5d\xb9\x60\xb6\xcc\x51\x68\x52\x31\xd9\x88\x88\x71\x71\xe0\x30" + "\x59\x55\x7f\xcd\x61\xc0\x4b\x05\xb8\xcd\xc1\x48\xe9\xcd\x16\x1f" + "\x70\x15\x0c\xfc\xd3\x1a\x75\xd0\x93\x6c\xc4\xe0\x5c\xbe\xe2\x18" + "\xc7\xaf\x72\xb6\x7c\x9b\x52\x00"; + sr_commit_t commit1, commit2; + memcpy(commit1.encoded_commit, payload, sizeof(commit1.encoded_commit)); + memcpy(commit2.encoded_commit, payload, sizeof(commit2.encoded_commit)); + tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 1); + /* Let's corrupt one of them. */ + memset(commit1.encoded_commit, 'A', sizeof(commit1.encoded_commit)); + tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 0); - tt_int_op(0, OP_EQ, crypto_pk_get_digest(k, digest)); - memcpy(commit.rsa_identity, digest, sizeof(commit.rsa_identity)); - tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 1); - /* Change the pubkey. */ - memset(commit.rsa_identity, 0, sizeof(commit.rsa_identity)); - tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 0); - crypto_pk_free(k); - } + done: + return; +} - /* Testing get_phase_str(). */ - { - tt_str_op(get_phase_str(SR_PHASE_REVEAL), OP_EQ, "reveal"); - tt_str_op(get_phase_str(SR_PHASE_COMMIT), OP_EQ, "commit"); - } +/* Testing commit_is_authoritative(). */ +static void +test_commit_is_authoritative(void *arg) +{ + (void)arg; + + crypto_pk_t *k = crypto_pk_new(); + char digest[DIGEST_LEN]; + sr_commit_t commit; + + tt_assert(!crypto_pk_generate_key(k)); + + tt_int_op(0, OP_EQ, crypto_pk_get_digest(k, digest)); + memcpy(commit.rsa_identity, digest, sizeof(commit.rsa_identity)); + tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 1); + /* Change the pubkey. */ + memset(commit.rsa_identity, 0, sizeof(commit.rsa_identity)); + tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 0); + + done: + crypto_pk_free(k); +} + +static void +test_get_phase_str(void *arg) +{ + (void)arg; + + tt_str_op(get_phase_str(SR_PHASE_REVEAL), OP_EQ, "reveal"); + tt_str_op(get_phase_str(SR_PHASE_COMMIT), OP_EQ, "commit"); done: return; @@ -1352,7 +1367,7 @@ test_utils_auth(void *arg) sr_state_set_current_srv(sr_state_get_current_srv()); sr_state_set_previous_srv(sr_state_get_previous_srv()); } -#endif +#endif /* 0 */ done: sr_state_free_all(); @@ -1649,7 +1664,12 @@ struct testcase_t sr_tests[] = { { "sr_compute_srv", test_sr_compute_srv, TT_FORK, NULL, NULL }, { "sr_get_majority_srv_from_votes", test_sr_get_majority_srv_from_votes, TT_FORK, NULL, NULL }, - { "utils_general", test_utils_general, TT_FORK, NULL, NULL }, + { "sr_svr_dup", test_sr_svr_dup, TT_FORK, NULL, NULL }, + { "commitments_are_the_same", test_commitments_are_the_same, TT_FORK, NULL, + NULL }, + { "commit_is_authoritative", test_commit_is_authoritative, TT_FORK, NULL, + NULL }, + { "get_phase_str", test_get_phase_str, TT_FORK, NULL, NULL }, { "utils_auth", test_utils_auth, TT_FORK, NULL, NULL }, { "state_transition", test_state_transition, TT_FORK, NULL, NULL }, { "state_update", test_state_update, TT_FORK, diff --git a/src/test/test_slow.c b/src/test/test_slow.c index c3e7edd408..d4d5b755a5 100644 --- a/src/test/test_slow.c +++ b/src/test/test_slow.c @@ -22,6 +22,7 @@ struct testgroup_t testgroups[] = { { "slow/crypto/", slow_crypto_tests }, { "slow/process/", slow_process_tests }, { "slow/prob_distr/", slow_stochastic_prob_distr_tests }, + { "slow/ptr/", slow_ptr_tests }, END_OF_GROUPS }; diff --git a/src/test/test_status.c b/src/test/test_status.c index 9c47469975..2fb2a7b24f 100644 --- a/src/test/test_status.c +++ b/src/test/test_status.c @@ -404,7 +404,7 @@ NS(logv)(int severity, log_domain_mask_t domain, { case 0: tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_int_op(domain, OP_EQ, LD_HEARTBEAT); + tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); tt_ptr_op(suffix, OP_EQ, NULL); tt_str_op(format, OP_EQ, @@ -412,7 +412,7 @@ NS(logv)(int severity, log_domain_mask_t domain, break; case 1: tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_int_op(domain, OP_EQ, LD_HEARTBEAT); + tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); tt_ptr_op(suffix, OP_EQ, NULL); tt_str_op(format, OP_EQ, @@ -429,7 +429,7 @@ NS(logv)(int severity, log_domain_mask_t domain, break; case 3: tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_int_op(domain, OP_EQ, LD_HEARTBEAT); + tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); tt_ptr_op(strstr(funcname, "rep_hist_log_circuit_handshake_stats"), OP_NE, NULL); tt_ptr_op(suffix, OP_EQ, NULL); @@ -442,13 +442,13 @@ NS(logv)(int severity, log_domain_mask_t domain, break; case 4: tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_int_op(domain, OP_EQ, LD_HEARTBEAT); + tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); tt_ptr_op(strstr(funcname, "rep_hist_log_link_protocol_counts"), OP_NE, NULL); break; case 5: tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_int_op(domain, OP_EQ, LD_HEARTBEAT); + tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); tt_str_op(format, OP_EQ, "DoS mitigation since startup:%s%s%s%s"); tt_str_op(va_arg(ap, char *), OP_EQ, " 0 circuits killed with too many cells."); @@ -574,7 +574,7 @@ NS(logv)(int severity, log_domain_mask_t domain, const char *funcname, ++NS(n_msgs); tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_int_op(domain, OP_EQ, LD_HEARTBEAT); + tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); tt_ptr_op(suffix, OP_EQ, NULL); tt_str_op(format, OP_EQ, @@ -709,7 +709,7 @@ NS(logv)(int severity, log_domain_mask_t domain, { case 0: tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_int_op(domain, OP_EQ, LD_HEARTBEAT); + tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); tt_ptr_op(suffix, OP_EQ, NULL); tt_str_op(format, OP_EQ, @@ -723,7 +723,7 @@ NS(logv)(int severity, log_domain_mask_t domain, break; case 1: tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_int_op(domain, OP_EQ, LD_HEARTBEAT); + tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); tt_ptr_op(strstr(funcname, "log_accounting"), OP_NE, NULL); tt_ptr_op(suffix, OP_EQ, NULL); tt_str_op(format, OP_EQ, @@ -889,7 +889,7 @@ NS(logv)(int severity, log_domain_mask_t domain, const char *funcname, { case 0: tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_int_op(domain, OP_EQ, LD_HEARTBEAT); + tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); tt_ptr_op(suffix, OP_EQ, NULL); tt_str_op(format, OP_EQ, @@ -903,7 +903,7 @@ NS(logv)(int severity, log_domain_mask_t domain, const char *funcname, break; case 1: tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_int_op(domain, OP_EQ, LD_HEARTBEAT); + tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); tt_ptr_op(suffix, OP_EQ, NULL); tt_str_op(format, OP_EQ, @@ -1038,7 +1038,7 @@ NS(logv)(int severity, log_domain_mask_t domain, { case 0: tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_int_op(domain, OP_EQ, LD_HEARTBEAT); + tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); tt_ptr_op(suffix, OP_EQ, NULL); tt_str_op(format, OP_EQ, @@ -1052,7 +1052,7 @@ NS(logv)(int severity, log_domain_mask_t domain, break; case 1: tt_int_op(severity, OP_EQ, LOG_NOTICE); - tt_int_op(domain, OP_EQ, LD_HEARTBEAT); + tt_u64_op(domain, OP_EQ, LD_HEARTBEAT); tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL); tt_ptr_op(suffix, OP_EQ, NULL); tt_str_op(format, OP_EQ, diff --git a/src/test/test_switch_id.sh b/src/test/test_switch_id.sh index 79c44f2eb1..b13bf7602f 100755 --- a/src/test/test_switch_id.sh +++ b/src/test/test_switch_id.sh @@ -1,11 +1,11 @@ #!/bin/sh -if test "`id -u`" != '0'; then +if test "$(id -u)" != '0'; then echo "This test only works when run as root. Skipping." >&2 exit 77 fi -if test "`id -u nobody`" = ""; then +if test "$(id -u nobody)" = ""; then echo "This test requires that your system have a 'nobody' user. Sorry." >&2 exit 1 fi diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c index 11e35be2fa..5f87434f6a 100644 --- a/src/test/test_tortls.c +++ b/src/test/test_tortls.c @@ -219,7 +219,7 @@ test_tortls_tor_tls_get_error(void *data) crypto_pk_free(key2); tor_tls_free(tls); } -#endif +#endif /* defined(ENABLE_OPENSSL) */ static void test_tortls_x509_cert_get_id_digests(void *ignored) @@ -336,7 +336,7 @@ test_tortls_server_got_renegotiate(void *ignored) done: tor_free(tls); } -#endif +#endif /* defined(ENABLE_OPENSSL) */ static void test_tortls_evaluate_ecgroup_for_tls(void *ignored) @@ -526,7 +526,7 @@ struct testcase_t tortls_tests[] = { LOCAL_TEST_CASE(get_forced_write_size, 0), LOCAL_TEST_CASE(used_v1_handshake, TT_FORK), LOCAL_TEST_CASE(server_got_renegotiate, 0), -#endif +#endif /* defined(ENABLE_OPENSSL) */ LOCAL_TEST_CASE(evaluate_ecgroup_for_tls, 0), LOCAL_TEST_CASE(double_init, TT_FORK), LOCAL_TEST_CASE(address, TT_FORK), diff --git a/src/test/test_tortls.h b/src/test/test_tortls.h index 1a8b117d0f..4567b9f6a0 100644 --- a/src/test/test_tortls.h +++ b/src/test/test_tortls.h @@ -10,4 +10,4 @@ extern const char *notCompletelyValidCertString; extern const char *validCertString; extern const char *caCertString; -#endif +#endif /* !defined(TEST_TORTLS_H) */ diff --git a/src/test/test_tortls_openssl.c b/src/test/test_tortls_openssl.c index 73041a871c..81e2d3aa4f 100644 --- a/src/test/test_tortls_openssl.c +++ b/src/test/test_tortls_openssl.c @@ -133,7 +133,7 @@ library_init(void) #else SSL_library_init(); SSL_load_error_strings(); -#endif +#endif /* defined(OPENSSL_1_1_API) */ } static void @@ -477,7 +477,7 @@ fake_x509_free(X509 *cert) tor_free(cert); } } -#endif +#endif /* !defined(OPENSSL_OPAQUE) */ static tor_x509_cert_t *fixed_x509_cert = NULL; static tor_x509_cert_t * diff --git a/src/test/test_util.c b/src/test/test_util.c index f1ffae7af8..2faadd4e19 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -6,7 +6,6 @@ #include "orconfig.h" #define COMPAT_PRIVATE #define COMPAT_TIME_PRIVATE -#define CONTROL_PRIVATE #define UTIL_PRIVATE #define UTIL_MALLOC_PRIVATE #define SOCKET_PRIVATE @@ -16,6 +15,7 @@ #include "lib/buf/buffers.h" #include "app/config/config.h" #include "feature/control/control.h" +#include "feature/control/control_proto.h" #include "feature/client/transports.h" #include "lib/crypt_ops/crypto_format.h" #include "lib/crypt_ops/crypto_rand.h" @@ -2087,14 +2087,14 @@ test_util_strmisc(void *arg) /* Test mem_is_zero */ memset(buf,0,128); buf[128] = 'x'; - tt_assert(tor_mem_is_zero(buf, 10)); - tt_assert(tor_mem_is_zero(buf, 20)); - tt_assert(tor_mem_is_zero(buf, 128)); - tt_assert(!tor_mem_is_zero(buf, 129)); + tt_assert(fast_mem_is_zero(buf, 10)); + tt_assert(fast_mem_is_zero(buf, 20)); + tt_assert(fast_mem_is_zero(buf, 128)); + tt_assert(!fast_mem_is_zero(buf, 129)); buf[60] = (char)255; - tt_assert(!tor_mem_is_zero(buf, 128)); + tt_assert(!fast_mem_is_zero(buf, 128)); buf[0] = (char)1; - tt_assert(!tor_mem_is_zero(buf, 10)); + tt_assert(!fast_mem_is_zero(buf, 10)); /* Test 'escaped' */ tt_ptr_op(escaped(NULL), OP_EQ, NULL); @@ -3789,7 +3789,7 @@ test_util_memarea(void *arg) tt_int_op(((uintptr_t)p3) % sizeof(void*),OP_EQ, 0); tt_assert(!memarea_owns_ptr(area, p3+8192)); tt_assert(!memarea_owns_ptr(area, p3+30)); - tt_assert(tor_mem_is_zero(p2, 52)); + tt_assert(fast_mem_is_zero(p2, 52)); /* Make sure we don't overalign. */ p1 = memarea_alloc(area, 1); p2 = memarea_alloc(area, 1); @@ -6116,9 +6116,9 @@ test_util_log_mallinfo(void *arg) } else { tt_u64_op(mem1, OP_LT, mem2); } -#else +#else /* !(defined(HAVE_MALLINFO)) */ tt_skip(); -#endif +#endif /* defined(HAVE_MALLINFO) */ done: teardown_capture_of_logs(); tor_free(log1); @@ -6132,10 +6132,12 @@ test_util_map_anon(void *arg) (void)arg; char *ptr = NULL; size_t sz = 16384; + unsigned inherit=0; /* Basic checks. */ - ptr = tor_mmap_anonymous(sz, 0); + ptr = tor_mmap_anonymous(sz, 0, &inherit); tt_ptr_op(ptr, OP_NE, 0); + tt_int_op(inherit, OP_EQ, INHERIT_RES_KEEP); ptr[sz-1] = 3; tt_int_op(ptr[0], OP_EQ, 0); tt_int_op(ptr[sz-2], OP_EQ, 0); @@ -6143,8 +6145,9 @@ test_util_map_anon(void *arg) /* Try again, with a private (non-swappable) mapping. */ tor_munmap_anonymous(ptr, sz); - ptr = tor_mmap_anonymous(sz, ANONMAP_PRIVATE); + ptr = tor_mmap_anonymous(sz, ANONMAP_PRIVATE, &inherit); tt_ptr_op(ptr, OP_NE, 0); + tt_int_op(inherit, OP_EQ, INHERIT_RES_KEEP); ptr[sz-1] = 10; tt_int_op(ptr[0], OP_EQ, 0); tt_int_op(ptr[sz/2], OP_EQ, 0); @@ -6152,7 +6155,7 @@ test_util_map_anon(void *arg) /* Now let's test a drop-on-fork mapping. */ tor_munmap_anonymous(ptr, sz); - ptr = tor_mmap_anonymous(sz, ANONMAP_NOINHERIT); + ptr = tor_mmap_anonymous(sz, ANONMAP_NOINHERIT, &inherit); tt_ptr_op(ptr, OP_NE, 0); ptr[sz-1] = 10; tt_int_op(ptr[0], OP_EQ, 0); @@ -6167,12 +6170,12 @@ static void test_util_map_anon_nofork(void *arg) { (void)arg; -#if !defined(HAVE_MADVISE) && !defined(HAVE_MINHERIT) - /* The operating system doesn't support this. */ +#ifdef _WIN32 + /* The operating system doesn't support forking. */ tt_skip(); done: ; -#else +#else /* !(defined(_WIN32)) */ /* We have the right OS support. We're going to try marking the buffer as * either zero-on-fork or as drop-on-fork, whichever is supported. Then we * will fork and send a byte back to the parent process. This will either @@ -6181,9 +6184,10 @@ test_util_map_anon_nofork(void *arg) char *ptr = NULL; size_t sz = 16384; int pipefd[2] = {-1, -1}; + unsigned inherit=0; tor_munmap_anonymous(ptr, sz); - ptr = tor_mmap_anonymous(sz, ANONMAP_NOINHERIT); + ptr = tor_mmap_anonymous(sz, ANONMAP_NOINHERIT, &inherit); tt_ptr_op(ptr, OP_NE, 0); memset(ptr, 0xd0, sz); @@ -6204,15 +6208,36 @@ test_util_map_anon_nofork(void *arg) pipefd[1] = -1; char buf[1]; ssize_t r = read(pipefd[0], buf, 1); -#if defined(INHERIT_ZERO) || defined(MADV_WIPEONFORK) - tt_int_op((int)r, OP_EQ, 1); // child should send us a byte. - tt_int_op(buf[0], OP_EQ, 0); -#else - tt_int_op(r, OP_LE, 0); // child said nothing; it should have crashed. -#endif + + if (inherit == INHERIT_RES_ZERO) { + // We should be seeing clear-on-fork behavior. + tt_int_op((int)r, OP_EQ, 1); // child should send us a byte. + tt_int_op(buf[0], OP_EQ, 0); // that byte should be zero. + } else if (inherit == INHERIT_RES_DROP) { + // We should be seeing noinherit behavior. + tt_int_op(r, OP_LE, 0); // child said nothing; it should have crashed. + } else { + // noinherit isn't implemented. + tt_int_op(inherit, OP_EQ, INHERIT_RES_KEEP); + tt_int_op((int)r, OP_EQ, 1); // child should send us a byte. + tt_int_op(buf[0], OP_EQ, 0xd0); // that byte should what we set it to. + } + int ws; waitpid(child, &ws, 0); +#ifndef NOINHERIT_CAN_FAIL + /* Only if NOINHERIT_CAN_FAIL should it be possible for us to get + * INHERIT_KEEP behavior in this case. */ + tt_int_op(inherit, OP_NE, INHERIT_RES_KEEP); +#else + if (inherit == INHERIT_RES_KEEP) { + /* Call this test "skipped", not "passed", since noinherit wasn't + * implemented. */ + tt_skip(); + } +#endif /* !defined(NOINHERIT_CAN_FAIL) */ + done: tor_munmap_anonymous(ptr, sz); if (pipefd[0] >= 0) { @@ -6221,7 +6246,7 @@ test_util_map_anon_nofork(void *arg) if (pipefd[1] >= 0) { close(pipefd[1]); } -#endif +#endif /* defined(_WIN32) */ } #define UTIL_LEGACY(name) \ @@ -6362,6 +6387,6 @@ struct testcase_t util_tests[] = { UTIL_TEST(get_unquoted_path, 0), UTIL_TEST(log_mallinfo, 0), UTIL_TEST(map_anon, 0), - UTIL_TEST(map_anon_nofork, TT_SKIP /* See bug #29535 */), + UTIL_TEST(map_anon_nofork, 0), END_OF_TESTCASES }; diff --git a/src/test/test_util_format.c b/src/test/test_util_format.c index 3a0b41faa5..2859da66b2 100644 --- a/src/test/test_util_format.c +++ b/src/test/test_util_format.c @@ -346,7 +346,7 @@ test_util_format_base32_decode(void *arg) const char *src = "mjwgc2dcnrswqmjs"; ret = base32_decode(dst, strlen(expected), src, strlen(src)); - tt_int_op(ret, OP_EQ, 0); + tt_int_op(ret, OP_EQ, 10); tt_str_op(expected, OP_EQ, dst); } @@ -357,7 +357,7 @@ test_util_format_base32_decode(void *arg) const char *src = "mjwgc2dcnrswq"; ret = base32_decode(dst, strlen(expected), src, strlen(src)); - tt_int_op(ret, OP_EQ, 0); + tt_int_op(ret, OP_EQ, 8); tt_mem_op(expected, OP_EQ, dst, strlen(expected)); } @@ -367,7 +367,7 @@ test_util_format_base32_decode(void *arg) ret = base32_decode(dst, real_dstlen, "#abcde", 6); tt_int_op(ret, OP_EQ, -1); /* Make sure the destination buffer has been zeroed even on error. */ - tt_int_op(tor_mem_is_zero(dst, real_dstlen), OP_EQ, 1); + tt_int_op(fast_mem_is_zero(dst, real_dstlen), OP_EQ, 1); } done: diff --git a/src/test/test_voting_flags.c b/src/test/test_voting_flags.c index 5c9eebd00e..c8111ea5df 100644 --- a/src/test/test_voting_flags.c +++ b/src/test/test_voting_flags.c @@ -60,7 +60,7 @@ check_result(flag_vote_test_cfg_t *c) bool result = false; routerstatus_t rs; memset(&rs, 0, sizeof(rs)); - set_routerstatus_from_routerinfo(&rs, &c->node, &c->ri, c->now, 0); + dirauth_set_routerstatus_from_routerinfo(&rs, &c->node, &c->ri, c->now, 0); tt_i64_op(rs.published_on, OP_EQ, c->expected.published_on); tt_str_op(rs.nickname, OP_EQ, c->expected.nickname); diff --git a/src/test/test_workqueue_cancel.sh b/src/test/test_workqueue_cancel.sh index f7c663171e..e50b884f26 100755 --- a/src/test/test_workqueue_cancel.sh +++ b/src/test/test_workqueue_cancel.sh @@ -1,4 +1,4 @@ #!/bin/sh -${builddir:-.}/src/test/test_workqueue -C 1 +"${builddir:-.}/src/test/test_workqueue" -C 1 diff --git a/src/test/test_workqueue_efd.sh b/src/test/test_workqueue_efd.sh index 4d89396819..592841fc91 100755 --- a/src/test/test_workqueue_efd.sh +++ b/src/test/test_workqueue_efd.sh @@ -1,4 +1,4 @@ #!/bin/sh -${builddir:-.}/src/test/test_workqueue \ +"${builddir:-.}/src/test/test_workqueue" \ --no-eventfd2 --no-pipe2 --no-pipe --no-socketpair diff --git a/src/test/test_workqueue_efd2.sh b/src/test/test_workqueue_efd2.sh index 7cfff45ff3..4cf1b76cbe 100755 --- a/src/test/test_workqueue_efd2.sh +++ b/src/test/test_workqueue_efd2.sh @@ -1,4 +1,4 @@ #!/bin/sh -${builddir:-.}/src/test/test_workqueue \ +"${builddir:-.}/src/test/test_workqueue" \ --no-eventfd --no-pipe2 --no-pipe --no-socketpair diff --git a/src/test/test_workqueue_pipe.sh b/src/test/test_workqueue_pipe.sh index afcef87853..fc3ef34c6c 100755 --- a/src/test/test_workqueue_pipe.sh +++ b/src/test/test_workqueue_pipe.sh @@ -1,4 +1,4 @@ #!/bin/sh -${builddir:-.}/src/test/test_workqueue \ +"${builddir:-.}/src/test/test_workqueue" \ --no-eventfd2 --no-eventfd --no-pipe2 --no-socketpair diff --git a/src/test/test_workqueue_pipe2.sh b/src/test/test_workqueue_pipe2.sh index a20a1427e0..7f19ea880d 100755 --- a/src/test/test_workqueue_pipe2.sh +++ b/src/test/test_workqueue_pipe2.sh @@ -1,4 +1,4 @@ #!/bin/sh -${builddir:-.}/src/test/test_workqueue \ +"${builddir:-.}/src/test/test_workqueue" \ --no-eventfd2 --no-eventfd --no-pipe --no-socketpair diff --git a/src/test/test_workqueue_socketpair.sh b/src/test/test_workqueue_socketpair.sh index 76af79746d..1ee1776447 100755 --- a/src/test/test_workqueue_socketpair.sh +++ b/src/test/test_workqueue_socketpair.sh @@ -1,4 +1,4 @@ #!/bin/sh -${builddir:-.}/src/test/test_workqueue \ +"${builddir:-.}/src/test/test_workqueue" \ --no-eventfd2 --no-eventfd --no-pipe2 --no-pipe diff --git a/src/test/testing_common.c b/src/test/testing_common.c index 8fc8ef7830..ad22898ce5 100644 --- a/src/test/testing_common.c +++ b/src/test/testing_common.c @@ -12,6 +12,7 @@ #include "orconfig.h" #include "core/or/or.h" #include "feature/control/control.h" +#include "feature/control/control_events.h" #include "app/config/config.h" #include "lib/crypt_ops/crypto_dh.h" #include "lib/crypt_ops/crypto_ed25519.h" @@ -242,7 +243,7 @@ tinytest_postfork(void) } static void -log_callback_failure(int severity, uint32_t domain, const char *msg) +log_callback_failure(int severity, log_domain_mask_t domain, const char *msg) { (void)msg; if (severity == LOG_ERR || (domain & LD_BUG)) { diff --git a/src/test/testing_rsakeys.c b/src/test/testing_rsakeys.c index 0f22d4e01b..8ba6bf9fe4 100644 --- a/src/test/testing_rsakeys.c +++ b/src/test/testing_rsakeys.c @@ -448,7 +448,8 @@ static int next_key_idx_2048; static crypto_pk_t * pk_generate_internal(int bits) { - tor_assert(bits == 2048 || bits == 1024); + tor_assertf(bits == 2048 || bits == 1024, + "Wrong key size: %d", bits); #ifdef USE_PREGENERATED_RSA_KEYS int *idxp; diff --git a/src/test/zero_length_keys.sh b/src/test/zero_length_keys.sh index 5635bdfd89..1702d11245 100755 --- a/src/test/zero_length_keys.sh +++ b/src/test/zero_length_keys.sh @@ -19,7 +19,7 @@ # 3: a command failed - the test could not be completed # -if [ $# -eq 0 ] || [ ! -f ${1} ] || [ ! -x ${1} ]; then +if [ $# -eq 0 ] || [ ! -f "${1}" ] || [ ! -x "${1}" ]; then echo "Usage: ${0} PATH_TO_TOR [-z|-d|-e]" exit 1 elif [ $# -eq 1 ]; then @@ -31,7 +31,7 @@ else #[$# -gt 1 ]; then shift fi -DATA_DIR=`mktemp -d -t tor_zero_length_keys.XXXXXX` +DATA_DIR=$(mktemp -d -t tor_zero_length_keys.XXXXXX) if [ -z "$DATA_DIR" ]; then echo "Failure: mktemp invocation returned empty string" >&2 exit 3 @@ -40,7 +40,7 @@ if [ ! -d "$DATA_DIR" ]; then echo "Failure: mktemp invocation result doesn't point to directory" >&2 exit 3 fi -trap "rm -rf '$DATA_DIR'" 0 +trap 'rm -rf "$DATA_DIR"' 0 touch "$DATA_DIR"/empty_torrc touch "$DATA_DIR"/empty_defaults_torrc diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c index 25113420df..ea96f41dbf 100644 --- a/src/tools/tor-gencert.c +++ b/src/tools/tor-gencert.c @@ -31,7 +31,7 @@ DISABLE_GCC_WARNING(redundant-decls) #include ENABLE_GCC_WARNING(redundant-decls) -#endif +#endif /* defined(ENABLE_OPENSSL) */ #include diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c index 98b3a4a74c..5d97696c18 100644 --- a/src/tools/tor-resolve.c +++ b/src/tools/tor-resolve.c @@ -424,6 +424,7 @@ do_resolve(const char *hostname, if (parsed < 2) { log_err(LD_NET, "Failed to parse SOCKS5 method selection " "message"); + socks5_server_method_free(m); goto err; } diff --git a/src/trunnel/ed25519_cert.trunnel b/src/trunnel/ed25519_cert.trunnel index 8d6483d558..e424ce5464 100644 --- a/src/trunnel/ed25519_cert.trunnel +++ b/src/trunnel/ed25519_cert.trunnel @@ -28,12 +28,6 @@ const LS_IPV6 = 0x01; const LS_LEGACY_ID = 0x02; const LS_ED25519_ID = 0x03; -// XXX hs_link_specifier_dup() violates the opaqueness of link_specifier_t by -// taking its sizeof(). If we ever want to turn on TRUNNEL_OPAQUE, or -// if we ever make link_specifier contain other types, we will -// need to refactor that function to do the copy by encoding and decoding the -// object. - // amended from tor.trunnel struct link_specifier { u8 ls_type; diff --git a/src/trunnel/include.am b/src/trunnel/include.am index 4f4f1d3624..ce15570b15 100644 --- a/src/trunnel/include.am +++ b/src/trunnel/include.am @@ -11,6 +11,7 @@ TRUNNELINPUTS = \ src/trunnel/link_handshake.trunnel \ src/trunnel/pwbox.trunnel \ src/trunnel/channelpadding_negotiation.trunnel \ + src/trunnel/sendme.trunnel \ src/trunnel/socks5.trunnel \ src/trunnel/circpad_negotiation.trunnel @@ -24,6 +25,7 @@ TRUNNELSOURCES = \ src/trunnel/hs/cell_introduce1.c \ src/trunnel/hs/cell_rendezvous.c \ src/trunnel/channelpadding_negotiation.c \ + src/trunnel/sendme.c \ src/trunnel/socks5.c \ src/trunnel/netinfo.c \ src/trunnel/circpad_negotiation.c @@ -40,6 +42,7 @@ TRUNNELHEADERS = \ src/trunnel/hs/cell_introduce1.h \ src/trunnel/hs/cell_rendezvous.h \ src/trunnel/channelpadding_negotiation.h \ + src/trunnel/sendme.h \ src/trunnel/socks5.h \ src/trunnel/netinfo.h \ src/trunnel/circpad_negotiation.h diff --git a/src/trunnel/sendme.c b/src/trunnel/sendme.c new file mode 100644 index 0000000000..262b915234 --- /dev/null +++ b/src/trunnel/sendme.c @@ -0,0 +1,347 @@ +/* sendme.c -- generated by Trunnel v1.5.2. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#include +#include "trunnel-impl.h" + +#include "sendme.h" + +#define TRUNNEL_SET_ERROR_CODE(obj) \ + do { \ + (obj)->trunnel_error_code_ = 1; \ + } while (0) + +#if defined(__COVERITY__) || defined(__clang_analyzer__) +/* If we're running a static analysis tool, we don't want it to complain + * that some of our remaining-bytes checks are dead-code. */ +int sendme_deadcode_dummy__ = 0; +#define OR_DEADCODE_DUMMY || sendme_deadcode_dummy__ +#else +#define OR_DEADCODE_DUMMY +#endif + +#define CHECK_REMAINING(nbytes, label) \ + do { \ + if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ + goto label; \ + } \ + } while (0) + +sendme_cell_t * +sendme_cell_new(void) +{ + sendme_cell_t *val = trunnel_calloc(1, sizeof(sendme_cell_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +sendme_cell_clear(sendme_cell_t *obj) +{ + (void) obj; +} + +void +sendme_cell_free(sendme_cell_t *obj) +{ + if (obj == NULL) + return; + sendme_cell_clear(obj); + trunnel_memwipe(obj, sizeof(sendme_cell_t)); + trunnel_free_(obj); +} + +uint8_t +sendme_cell_get_version(const sendme_cell_t *inp) +{ + return inp->version; +} +int +sendme_cell_set_version(sendme_cell_t *inp, uint8_t val) +{ + if (! ((val == 0 || val == 1))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->version = val; + return 0; +} +uint16_t +sendme_cell_get_data_len(const sendme_cell_t *inp) +{ + return inp->data_len; +} +int +sendme_cell_set_data_len(sendme_cell_t *inp, uint16_t val) +{ + inp->data_len = val; + return 0; +} +size_t +sendme_cell_getlen_data_v1_digest(const sendme_cell_t *inp) +{ + (void)inp; return TRUNNEL_SENDME_V1_DIGEST_LEN; +} + +uint8_t +sendme_cell_get_data_v1_digest(sendme_cell_t *inp, size_t idx) +{ + trunnel_assert(idx < TRUNNEL_SENDME_V1_DIGEST_LEN); + return inp->data_v1_digest[idx]; +} + +uint8_t +sendme_cell_getconst_data_v1_digest(const sendme_cell_t *inp, size_t idx) +{ + return sendme_cell_get_data_v1_digest((sendme_cell_t*)inp, idx); +} +int +sendme_cell_set_data_v1_digest(sendme_cell_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < TRUNNEL_SENDME_V1_DIGEST_LEN); + inp->data_v1_digest[idx] = elt; + return 0; +} + +uint8_t * +sendme_cell_getarray_data_v1_digest(sendme_cell_t *inp) +{ + return inp->data_v1_digest; +} +const uint8_t * +sendme_cell_getconstarray_data_v1_digest(const sendme_cell_t *inp) +{ + return (const uint8_t *)sendme_cell_getarray_data_v1_digest((sendme_cell_t*)inp); +} +const char * +sendme_cell_check(const sendme_cell_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + if (! (obj->version == 0 || obj->version == 1)) + return "Integer out of bounds"; + switch (obj->version) { + + case 0: + break; + + case 1: + break; + + default: + return "Bad tag for union"; + break; + } + return NULL; +} + +ssize_t +sendme_cell_encoded_len(const sendme_cell_t *obj) +{ + ssize_t result = 0; + + if (NULL != sendme_cell_check(obj)) + return -1; + + + /* Length of u8 version IN [0, 1] */ + result += 1; + + /* Length of u16 data_len */ + result += 2; + switch (obj->version) { + + case 0: + break; + + case 1: + + /* Length of u8 data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN] */ + result += TRUNNEL_SENDME_V1_DIGEST_LEN; + break; + + default: + trunnel_assert(0); + break; + } + return result; +} +int +sendme_cell_clear_errors(sendme_cell_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +sendme_cell_encode(uint8_t *output, const size_t avail, const sendme_cell_t *obj) +{ + ssize_t result = 0; + size_t written = 0; + uint8_t *ptr = output; + const char *msg; +#ifdef TRUNNEL_CHECK_ENCODED_LEN + const ssize_t encoded_len = sendme_cell_encoded_len(obj); +#endif + + uint8_t *backptr_data_len = NULL; + + if (NULL != (msg = sendme_cell_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 version IN [0, 1] */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->version)); + written += 1; ptr += 1; + + /* Encode u16 data_len */ + backptr_data_len = ptr; + trunnel_assert(written <= avail); + if (avail - written < 2) + goto truncated; + trunnel_set_uint16(ptr, trunnel_htons(obj->data_len)); + written += 2; ptr += 2; + { + size_t written_before_union = written; + + /* Encode union data[version] */ + trunnel_assert(written <= avail); + switch (obj->version) { + + case 0: + break; + + case 1: + + /* Encode u8 data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN] */ + trunnel_assert(written <= avail); + if (avail - written < TRUNNEL_SENDME_V1_DIGEST_LEN) + goto truncated; + memcpy(ptr, obj->data_v1_digest, TRUNNEL_SENDME_V1_DIGEST_LEN); + written += TRUNNEL_SENDME_V1_DIGEST_LEN; ptr += TRUNNEL_SENDME_V1_DIGEST_LEN; + break; + + default: + trunnel_assert(0); + break; + } + /* Write the length field back to data_len */ + trunnel_assert(written >= written_before_union); +#if UINT16_MAX < SIZE_MAX + if (written - written_before_union > UINT16_MAX) + goto check_failed; +#endif + trunnel_set_uint16(backptr_data_len, trunnel_htons(written - written_before_union)); + } + + + trunnel_assert(ptr == output + written); +#ifdef TRUNNEL_CHECK_ENCODED_LEN + { + trunnel_assert(encoded_len >= 0); + trunnel_assert((size_t)encoded_len == written); + } + +#endif + + return written; + + truncated: + result = -2; + goto fail; + check_failed: + (void)msg; + result = -1; + goto fail; + fail: + trunnel_assert(result < 0); + return result; +} + +/** As sendme_cell_parse(), but do not allocate the output object. + */ +static ssize_t +sendme_cell_parse_into(sendme_cell_t *obj, const uint8_t *input, const size_t len_in) +{ + const uint8_t *ptr = input; + size_t remaining = len_in; + ssize_t result = 0; + (void)result; + + /* Parse u8 version IN [0, 1] */ + CHECK_REMAINING(1, truncated); + obj->version = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->version == 0 || obj->version == 1)) + goto fail; + + /* Parse u16 data_len */ + CHECK_REMAINING(2, truncated); + obj->data_len = trunnel_ntohs(trunnel_get_uint16(ptr)); + remaining -= 2; ptr += 2; + { + size_t remaining_after; + CHECK_REMAINING(obj->data_len, truncated); + remaining_after = remaining - obj->data_len; + remaining = obj->data_len; + + /* Parse union data[version] */ + switch (obj->version) { + + case 0: + /* Skip to end of union */ + ptr += remaining; remaining = 0; + break; + + case 1: + + /* Parse u8 data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN] */ + CHECK_REMAINING(TRUNNEL_SENDME_V1_DIGEST_LEN, fail); + memcpy(obj->data_v1_digest, ptr, TRUNNEL_SENDME_V1_DIGEST_LEN); + remaining -= TRUNNEL_SENDME_V1_DIGEST_LEN; ptr += TRUNNEL_SENDME_V1_DIGEST_LEN; + break; + + default: + goto fail; + break; + } + if (remaining != 0) + goto fail; + remaining = remaining_after; + } + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + fail: + result = -1; + return result; +} + +ssize_t +sendme_cell_parse(sendme_cell_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = sendme_cell_new(); + if (NULL == *output) + return -1; + result = sendme_cell_parse_into(*output, input, len_in); + if (result < 0) { + sendme_cell_free(*output); + *output = NULL; + } + return result; +} diff --git a/src/trunnel/sendme.h b/src/trunnel/sendme.h new file mode 100644 index 0000000000..f3c3dd78c4 --- /dev/null +++ b/src/trunnel/sendme.h @@ -0,0 +1,101 @@ +/* sendme.h -- generated by Trunnel v1.5.2. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#ifndef TRUNNEL_SENDME_H +#define TRUNNEL_SENDME_H + +#include +#include "trunnel.h" + +#define TRUNNEL_SENDME_V1_DIGEST_LEN 20 +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_SENDME_CELL) +struct sendme_cell_st { + uint8_t version; + uint16_t data_len; + uint8_t data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN]; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct sendme_cell_st sendme_cell_t; +/** Return a newly allocated sendme_cell with all elements set to + * zero. + */ +sendme_cell_t *sendme_cell_new(void); +/** Release all storage held by the sendme_cell in 'victim'. (Do + * nothing if 'victim' is NULL.) + */ +void sendme_cell_free(sendme_cell_t *victim); +/** Try to parse a sendme_cell from the buffer in 'input', using up to + * 'len_in' bytes from the input buffer. On success, return the number + * of bytes consumed and set *output to the newly allocated + * sendme_cell_t. On failure, return -2 if the input appears + * truncated, and -1 if the input is otherwise invalid. + */ +ssize_t sendme_cell_parse(sendme_cell_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * sendme_cell in 'obj'. On failure, return a negative value. Note + * that this value may be an overestimate, and can even be an + * underestimate for certain unencodeable objects. + */ +ssize_t sendme_cell_encoded_len(const sendme_cell_t *obj); +/** Try to encode the sendme_cell from 'input' into the buffer at + * 'output', using up to 'avail' bytes of the output buffer. On + * success, return the number of bytes used. On failure, return -2 if + * the buffer was not long enough, and -1 if the input was invalid. + */ +ssize_t sendme_cell_encode(uint8_t *output, size_t avail, const sendme_cell_t *input); +/** Check whether the internal state of the sendme_cell in 'obj' is + * consistent. Return NULL if it is, and a short message if it is not. + */ +const char *sendme_cell_check(const sendme_cell_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int sendme_cell_clear_errors(sendme_cell_t *obj); +/** Return the value of the version field of the sendme_cell_t in + * 'inp' + */ +uint8_t sendme_cell_get_version(const sendme_cell_t *inp); +/** Set the value of the version field of the sendme_cell_t in 'inp' + * to 'val'. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int sendme_cell_set_version(sendme_cell_t *inp, uint8_t val); +/** Return the value of the data_len field of the sendme_cell_t in + * 'inp' + */ +uint16_t sendme_cell_get_data_len(const sendme_cell_t *inp); +/** Set the value of the data_len field of the sendme_cell_t in 'inp' + * to 'val'. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int sendme_cell_set_data_len(sendme_cell_t *inp, uint16_t val); +/** Return the (constant) length of the array holding the + * data_v1_digest field of the sendme_cell_t in 'inp'. + */ +size_t sendme_cell_getlen_data_v1_digest(const sendme_cell_t *inp); +/** Return the element at position 'idx' of the fixed array field + * data_v1_digest of the sendme_cell_t in 'inp'. + */ +uint8_t sendme_cell_get_data_v1_digest(sendme_cell_t *inp, size_t idx); +/** As sendme_cell_get_data_v1_digest, but take and return a const + * pointer + */ +uint8_t sendme_cell_getconst_data_v1_digest(const sendme_cell_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * data_v1_digest of the sendme_cell_t in 'inp', so that it will hold + * the value 'elt'. + */ +int sendme_cell_set_data_v1_digest(sendme_cell_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the TRUNNEL_SENDME_V1_DIGEST_LEN-element array + * field data_v1_digest of 'inp'. + */ +uint8_t * sendme_cell_getarray_data_v1_digest(sendme_cell_t *inp); +/** As sendme_cell_get_data_v1_digest, but take and return a const + * pointer + */ +const uint8_t * sendme_cell_getconstarray_data_v1_digest(const sendme_cell_t *inp); + + +#endif diff --git a/src/trunnel/sendme.trunnel b/src/trunnel/sendme.trunnel new file mode 100644 index 0000000000..300963e679 --- /dev/null +++ b/src/trunnel/sendme.trunnel @@ -0,0 +1,19 @@ +/* This file contains the SENDME cell definition. */ + +/* v1 digest length in bytes. */ +const TRUNNEL_SENDME_V1_DIGEST_LEN = 20; + +/* SENDME cell declaration. */ +struct sendme_cell { + /* Version field. */ + u8 version IN [0x00, 0x01]; + + /* Length of data contained in this cell. */ + u16 data_len; + + /* The data content depends on the version. */ + union data[version] with length data_len { + 0x00: ignore; + 0x01: u8 v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN]; + }; +} diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h index adac422687..bb1f42ef19 100644 --- a/src/win32/orconfig.h +++ b/src/win32/orconfig.h @@ -218,7 +218,7 @@ #define USING_TWOS_COMPLEMENT /* Version number of package */ -#define VERSION "0.4.0.5-dev" +#define VERSION "0.4.1.5-dev" -- cgit v1.2.3-54-g00ecf From be4a60945d724ca964d9d53f57cad6190a500077 Mon Sep 17 00:00:00 2001 From: Neel Chauhan Date: Sun, 25 Aug 2019 20:22:57 -0400 Subject: Check IPv6 exit policies on microdescriptors in node_exit_policy_rejects_all() --- changes/bug27284 | 5 +++++ src/feature/dirparse/microdesc_parse.c | 11 +++++++++++ src/feature/nodelist/microdesc_st.h | 2 ++ src/feature/nodelist/nodelist.c | 3 +-- 4 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 changes/bug27284 (limited to 'changes') diff --git a/changes/bug27284 b/changes/bug27284 new file mode 100644 index 0000000000..14fc2082fe --- /dev/null +++ b/changes/bug27284 @@ -0,0 +1,5 @@ + o Minor bugfixes (ipv6): + - When parsing microdescriptors, we should check the IPv6 exit policy + alongside IPv4. Previously, we checked both exit policies for only + router info structures, while microdescriptors were IPv4-only. Fixes + bug 27284; bugfix on 0.2.3.1-alpha. Patch by Neel Chauhan. diff --git a/src/feature/dirparse/microdesc_parse.c b/src/feature/dirparse/microdesc_parse.c index 22cc1e272e..e02dfcf11a 100644 --- a/src/feature/dirparse/microdesc_parse.c +++ b/src/feature/dirparse/microdesc_parse.c @@ -92,6 +92,12 @@ find_start_of_next_microdesc(const char *s, const char *eos) #undef NEXT_LINE } +static inline int +policy_is_reject_star_or_null(struct short_policy_t *policy) +{ + return !policy || short_policy_is_reject_star(policy); +} + /** Parse as many microdescriptors as are found from the string starting at * s and ending at eos. If allow_annotations is set, read any * annotations we recognize and ignore ones we don't. @@ -250,6 +256,11 @@ microdescs_parse_from_string(const char *s, const char *eos, md->ipv6_exit_policy = parse_short_policy(tok->args[0]); } + if (policy_is_reject_star_or_null(md->exit_policy) && + policy_is_reject_star_or_null(md->ipv6_exit_policy)) { + md->policy_is_reject_star = 1; + } + smartlist_add(result, md); okay = 1; diff --git a/src/feature/nodelist/microdesc_st.h b/src/feature/nodelist/microdesc_st.h index c8265cb778..e017c46c79 100644 --- a/src/feature/nodelist/microdesc_st.h +++ b/src/feature/nodelist/microdesc_st.h @@ -33,6 +33,8 @@ struct microdesc_t { unsigned int no_save : 1; /** If true, this microdesc has an entry in the microdesc_map */ unsigned int held_in_map : 1; + /** True iff the exit policy for this router rejects everything. */ + unsigned int policy_is_reject_star : 1; /** Reference count: how many node_ts have a reference to this microdesc? */ unsigned int held_by_nodes; diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c index 21914c6c6d..6ae8d2bcb1 100644 --- a/src/feature/nodelist/nodelist.c +++ b/src/feature/nodelist/nodelist.c @@ -1424,8 +1424,7 @@ node_exit_policy_rejects_all(const node_t *node) if (node->ri) return node->ri->policy_is_reject_star; else if (node->md) - return node->md->exit_policy == NULL || - short_policy_is_reject_star(node->md->exit_policy); + return node->md->policy_is_reject_star; else return 1; } -- cgit v1.2.3-54-g00ecf From 380d178e53bf4389a4f3085aef73d23c4a6b447f Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 5 Sep 2019 16:20:31 -0400 Subject: changes file for ticket31477 --- changes/ticket31477 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket31477 (limited to 'changes') diff --git a/changes/ticket31477 b/changes/ticket31477 new file mode 100644 index 0000000000..5a0fdd1544 --- /dev/null +++ b/changes/ticket31477 @@ -0,0 +1,3 @@ + o Minor features (tests): + - Add integration tests to make sure that practracker gives the outputs + we expect. Closes ticket 31477. -- cgit v1.2.3-54-g00ecf From 612b0a41399d0ddf260f4f6dd989fcc97d069fbd Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 4 Sep 2019 15:40:57 +1000 Subject: subsys: Make the subsystem init order match the module dependencies Fix levels for subsystems that depend on log/err * winprocess (security) doesn't use err: * call windows process security APIs as early as possible * init err after winprocess * move wallclock so it's still after err * network and time depend on log: * make sure that network and time can use logging. * init network and time after log Add comments explaining the module init order. Fixes bug 31615; bugfix on 0.4.0.1-alpha. --- changes/bug31615 | 5 +++++ src/lib/err/torerr_sys.c | 5 ++++- src/lib/log/log_sys.c | 2 ++ src/lib/net/network_sys.c | 4 +++- src/lib/process/winprocess_sys.c | 2 ++ src/lib/thread/compat_threads.c | 2 ++ src/lib/time/time_sys.c | 4 +++- src/lib/wallclock/approx_time.c | 4 +++- 8 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 changes/bug31615 (limited to 'changes') diff --git a/changes/bug31615 b/changes/bug31615 new file mode 100644 index 0000000000..49b13bea95 --- /dev/null +++ b/changes/bug31615 @@ -0,0 +1,5 @@ + o Minor bugfixes (subsystems): + - Make the subsystem init order match the subsystem module dependencies. + Call windows process security APIs as early as possible. Init log before + network and time, so that network and time can use logging. + Fixes bug 31615; bugfix on 0.4.0.1-alpha. diff --git a/src/lib/err/torerr_sys.c b/src/lib/err/torerr_sys.c index 3ab1b3c4e1..34f70f1f0b 100644 --- a/src/lib/err/torerr_sys.c +++ b/src/lib/err/torerr_sys.c @@ -33,7 +33,10 @@ subsys_torerr_shutdown(void) const subsys_fns_t sys_torerr = { .name = "err", - .level = -100, + /* Low-level error handling is a diagnostic feature, we want it to init + * right after windows process security, and shutdown last. + * (Security never shuts down.) */ + .level = -99, .supported = true, .initialize = subsys_torerr_initialize, .shutdown = subsys_torerr_shutdown diff --git a/src/lib/log/log_sys.c b/src/lib/log/log_sys.c index d1080f2264..826358546a 100644 --- a/src/lib/log/log_sys.c +++ b/src/lib/log/log_sys.c @@ -29,6 +29,8 @@ subsys_logging_shutdown(void) const subsys_fns_t sys_logging = { .name = "log", .supported = true, + /* Logging depends on threads, approx time, raw logging, and security. + * Most other lib modules depend on logging. */ .level = -90, .initialize = subsys_logging_initialize, .shutdown = subsys_logging_shutdown, diff --git a/src/lib/net/network_sys.c b/src/lib/net/network_sys.c index 9dfdb2b45a..e0a2625d73 100644 --- a/src/lib/net/network_sys.c +++ b/src/lib/net/network_sys.c @@ -37,7 +37,9 @@ subsys_network_shutdown(void) const subsys_fns_t sys_network = { .name = "network", - .level = -90, + /* Network depends on logging, and a lot of other modules depend on network. + */ + .level = -80, .supported = true, .initialize = subsys_network_initialize, .shutdown = subsys_network_shutdown, diff --git a/src/lib/process/winprocess_sys.c b/src/lib/process/winprocess_sys.c index 1266babca8..407eeaaeed 100644 --- a/src/lib/process/winprocess_sys.c +++ b/src/lib/process/winprocess_sys.c @@ -58,6 +58,8 @@ subsys_winprocess_initialize(void) const subsys_fns_t sys_winprocess = { .name = "winprocess", + /* HeapEnableTerminationOnCorruption and setdeppolicy() are security + * features, we want them to run first. */ .level = -100, .supported = WINPROCESS_SYS_ENABLED, .initialize = subsys_winprocess_initialize, diff --git a/src/lib/thread/compat_threads.c b/src/lib/thread/compat_threads.c index 35cfeba64c..1c4a5c4e3f 100644 --- a/src/lib/thread/compat_threads.c +++ b/src/lib/thread/compat_threads.c @@ -122,6 +122,8 @@ subsys_threads_initialize(void) const subsys_fns_t sys_threads = { .name = "threads", .supported = true, + /* Threads is used by logging, which is a diagnostic feature, we want it to + * init right after low-level error handling and approx time. */ .level = -95, .initialize = subsys_threads_initialize, }; diff --git a/src/lib/time/time_sys.c b/src/lib/time/time_sys.c index b3feb7b46a..8b9aa2856c 100644 --- a/src/lib/time/time_sys.c +++ b/src/lib/time/time_sys.c @@ -20,7 +20,9 @@ subsys_time_initialize(void) const subsys_fns_t sys_time = { .name = "time", - .level = -90, + /* Monotonic time depends on logging, and a lot of other modules depend on + * monotonic time. */ + .level = -80, .supported = true, .initialize = subsys_time_initialize, }; diff --git a/src/lib/wallclock/approx_time.c b/src/lib/wallclock/approx_time.c index 7b32804026..77eeddaf56 100644 --- a/src/lib/wallclock/approx_time.c +++ b/src/lib/wallclock/approx_time.c @@ -54,6 +54,8 @@ subsys_wallclock_initialize(void) const subsys_fns_t sys_wallclock = { .name = "wallclock", .supported = true, - .level = -99, + /* Approximate time is a diagnostic feature, we want it to init right after + * low-level error handling. */ + .level = -98, .initialize = subsys_wallclock_initialize, }; -- cgit v1.2.3-54-g00ecf From ebce7059ffbc3a4a8b7ff7cf923b0e6a402f4f33 Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 9 Sep 2019 13:53:58 +1000 Subject: changes: file for 31594 --- changes/bug31594 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/bug31594 (limited to 'changes') diff --git a/changes/bug31594 b/changes/bug31594 new file mode 100644 index 0000000000..75e6ec33cc --- /dev/null +++ b/changes/bug31594 @@ -0,0 +1,5 @@ + o Minor bugfixes (error handling): + - When tor aborts due to an error, close log file descriptors before + aborting. Closing the logs makes some OSes flush log file buffers, + rather than deleting buffered log lines. Fixes bug 31594; + bugfix on 0.2.5.2-alpha. -- cgit v1.2.3-54-g00ecf From 51b792b000d8560cf5b61b887eadcd9aece27d04 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 10 Sep 2019 12:07:13 +1000 Subject: scripts: Allow git-push-all.sh to be run from any directory Closes 31678. --- changes/ticket31678 | 4 ++++ scripts/git/git-push-all.sh | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 changes/ticket31678 (limited to 'changes') diff --git a/changes/ticket31678 b/changes/ticket31678 new file mode 100644 index 0000000000..157f1db7f9 --- /dev/null +++ b/changes/ticket31678 @@ -0,0 +1,4 @@ + o Minor features (git scripts): + - Allow git-push-all.sh to be run from any directory. Previously, the + script only worked if run from an upstream worktree directory. + Closes ticket 31678. diff --git a/scripts/git/git-push-all.sh b/scripts/git/git-push-all.sh index 8e49e81b9d..701fea40f2 100755 --- a/scripts/git/git-push-all.sh +++ b/scripts/git/git-push-all.sh @@ -30,6 +30,13 @@ set -e # Don't change this configuration - set the env vars in your .profile # +# The tor master git repository directory from which all the worktree have +# been created. +TOR_MASTER_NAME=${TOR_MASTER_NAME:-"tor"} +# Which directory do we push from? +if [ "$TOR_FULL_GIT_PATH" ]; then + TOR_GIT_PUSH_PATH=${TOR_GIT_PUSH_PATH:-"$TOR_FULL_GIT_PATH/$TOR_MASTER_NAME"} +fi # git push command and default arguments GIT_PUSH=${TOR_GIT_PUSH:-"git push --atomic"} # The upstream remote which git.torproject.org/tor.git points to. @@ -91,8 +98,6 @@ if [ "$1" = "--" ]; then shift fi -echo "Calling $GIT_PUSH" "$@" "" - if [ "$TEST_BRANCH_PREFIX" ]; then if [ "$UPSTREAM_REMOTE" = "${TOR_UPSTREAM_REMOTE_NAME:-upstream}" ]; then echo "Pushing test branches ${TEST_BRANCH_PREFIX}_nnn to " \ @@ -102,6 +107,15 @@ if [ "$TEST_BRANCH_PREFIX" ]; then fi fi +if [ "$TOR_GIT_PUSH_PATH" ]; then + echo "Changing to $GIT_PUSH_PATH before pushing" + cd "$TOR_GIT_PUSH_PATH" +else + echo "Pushing from the current directory" +fi + +echo "Calling $GIT_PUSH" "$@" "" + ################################ # Git upstream remote branches # ################################ -- cgit v1.2.3-54-g00ecf From 9d604959036bd02e7ff0ca1bd33f842664610b82 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 10 Sep 2019 18:59:10 -0400 Subject: Use strtod, not atof, for parsing doubles in the configuration. This lets us detect erroneous doubles, which previously we could not do. Fixes bug 31475; bugfix on commit 00a9e3732e88, a.k.a svn:r136. --- changes/ticket31475 | 5 +++++ src/lib/confmgt/type_defs.c | 13 ++++++++++--- src/test/test_confparse.c | 4 ++++ 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 changes/ticket31475 (limited to 'changes') diff --git a/changes/ticket31475 b/changes/ticket31475 new file mode 100644 index 0000000000..e156c145a9 --- /dev/null +++ b/changes/ticket31475 @@ -0,0 +1,5 @@ + o Minor bugfixes (configuration): + - Invalid floating-point values in the configuration file are now + detected treated as errors in the configuration. Previously, they + were ignored and treated as zero. Fixes bug 31475; bugfix on + 0.0.1. diff --git a/src/lib/confmgt/type_defs.c b/src/lib/confmgt/type_defs.c index f8b2681aa0..137af4ed9e 100644 --- a/src/lib/confmgt/type_defs.c +++ b/src/lib/confmgt/type_defs.c @@ -283,9 +283,16 @@ double_parse(void *target, const char *value, char **errmsg, (void)params; (void)errmsg; double *v = (double*)target; - // XXXX This is the preexisting behavior, but we should detect errors here. - *v = atof(value); - return 0; + char *endptr=NULL; + *v = strtod(value, &endptr); + if (endptr == value || *endptr != '\0') { + // Either there are no converted characters, or there were some characters + // that didn't get converted. + tor_asprintf(errmsg, "Could not convert %s to a number.", escaped(value)); + return -1; + } else { + return 0; + } } static char * diff --git a/src/test/test_confparse.c b/src/test/test_confparse.c index bd2b5cdf1b..a4da6c7c9f 100644 --- a/src/test/test_confparse.c +++ b/src/test/test_confparse.c @@ -488,6 +488,8 @@ test_confparse_assign_badval(void *arg) static const badval_test_t bv_notint = { "pos X\n", "malformed" }; static const badval_test_t bv_negint = { "pos -10\n", "out of bounds" }; static const badval_test_t bv_badu64 = { "u64 u64\n", "malformed" }; +static const badval_test_t bv_dbl1 = { "dbl xxx\n", "Could not convert" }; +static const badval_test_t bv_dbl2 = { "dbl 1.0 xx\n", "Could not convert" }; static const badval_test_t bv_badcsvi1 = { "csv_interval 10 wl\n", "malformed" }; static const badval_test_t bv_badcsvi2 = @@ -1045,6 +1047,8 @@ struct testcase_t confparse_tests[] = { BADVAL_TEST(notint), BADVAL_TEST(negint), BADVAL_TEST(badu64), + BADVAL_TEST(dbl1), + BADVAL_TEST(dbl2), BADVAL_TEST(badcsvi1), BADVAL_TEST(badcsvi2), BADVAL_TEST(nonoption), -- cgit v1.2.3-54-g00ecf From 0891a31ad32d0567fbc8f73a0598925cb543d699 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 11 Sep 2019 09:13:50 -0400 Subject: madvise: tolerate EINVAL and ENOSYS when minherit fails These errors can occur if we are built on a system with support for madvise(MADV_NOFORK) but then we are run on a system whose kernel does not support that flag. If the error is something that we don't tolerate at all, we now log it before crashing. Fixes bug 31696. I am calling this a bugfix on 0.4.1.1-alpha, where we actually started using the map_anon code. This is similar to, but not the same as, the fix for #31570. --- changes/bug31696 | 5 +++++ src/lib/malloc/map_anon.c | 24 +++++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 changes/bug31696 (limited to 'changes') diff --git a/changes/bug31696 b/changes/bug31696 new file mode 100644 index 0000000000..b9d6c4130c --- /dev/null +++ b/changes/bug31696 @@ -0,0 +1,5 @@ + o Major bugfixes (crash, Linux): + - Tolerate systems (including some Linux installations) where madvise + and/or MADV_DONTFORK are available at build-time, but not at run time. + Previously, these systems would notice a failed syscall and abort. + Fixes bug 31696; bugfix on 0.4.1.1-alpha. diff --git a/src/lib/malloc/map_anon.c b/src/lib/malloc/map_anon.c index 0f6a4150c7..08b754540e 100644 --- a/src/lib/malloc/map_anon.c +++ b/src/lib/malloc/map_anon.c @@ -27,6 +27,9 @@ #include #endif +#include +#include + /** * Macro to get the high bytes of a size_t, if there are high bytes. * Windows needs this; other operating systems define a size_t that does @@ -136,18 +139,33 @@ noinherit_mem(void *mem, size_t sz, inherit_res_t *inherit_result_out) return 0; } #endif /* defined(FLAG_ZERO) */ + #ifdef FLAG_NOINHERIT int r2 = MINHERIT(mem, sz, FLAG_NOINHERIT); if (r2 == 0) { *inherit_result_out = INHERIT_RES_DROP; + return 0; } - return r2; -#else /* !(defined(FLAG_NOINHERIT)) */ +#endif /* defined(FLAG_NOINHERIT) */ + +#if defined(FLAG_ZERO) || defined(FLAG_NOINHERIT) + /* At least one operation was tried, and neither succeeded. */ + + if (errno == ENOSYS || errno == EINVAL) { + /* Syscall not supported, or flag not supported. */ + return 0; + } else { + tor_log_err_sigsafe("Unexpected error from minherit: ", + strerror(errno), + NULL); + return -1; + } +#else (void)inherit_result_out; (void)mem; (void)sz; return 0; -#endif /* defined(FLAG_NOINHERIT) */ +#endif } /** -- cgit v1.2.3-54-g00ecf From d545fe1992432004689c66372f1a61e7c3fb7899 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 5 Sep 2019 11:48:54 -0400 Subject: Changes file for 31625 (config flag refactor) --- changes/ticket31625 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket31625 (limited to 'changes') diff --git a/changes/ticket31625 b/changes/ticket31625 new file mode 100644 index 0000000000..822a921e4f --- /dev/null +++ b/changes/ticket31625 @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Replace our ad-hoc set of flags for configuration variables and + configuration variable types with fine-grained orthogonal flags + corresponding to the actual behavior we want. Closes ticket 31625. -- cgit v1.2.3-54-g00ecf From c7cbe64463cba30586e53e8e5dba9596aba3c67d Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 11 Sep 2019 10:25:27 -0400 Subject: Changes file for ticket31626 (confparse.[ch] move) --- changes/ticket31626 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket31626 (limited to 'changes') diff --git a/changes/ticket31626 b/changes/ticket31626 new file mode 100644 index 0000000000..443bc1eb87 --- /dev/null +++ b/changes/ticket31626 @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Move our backend logic for working with configuration and state + files into a lower-level library, since in no longer depends on + any tor-specific functionality. Closes ticket 31626. -- cgit v1.2.3-54-g00ecf From 98ab3817a86239f9c4888339625a55c55505ede2 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 12 Sep 2019 16:54:32 -0400 Subject: Add a changes file for ticket 31637. --- changes/ticket31637 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/ticket31637 (limited to 'changes') diff --git a/changes/ticket31637 b/changes/ticket31637 new file mode 100644 index 0000000000..b6ffa8b892 --- /dev/null +++ b/changes/ticket31637 @@ -0,0 +1,6 @@ + o Minor features (testing): + - Add a script to invoke "tor --dump-config" and "tor --verify-config" + with various configuration options, and see whether tor's resulting + configuration or error messages are what we expect. Use it for + integration testing of our +Option and /Option flags. + Closes ticket 31637. -- cgit v1.2.3-54-g00ecf From cbd3b01863ceeaad4c5dc89544037658f69e9403 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 16 Sep 2019 08:31:26 -0400 Subject: Start a changelog for 0.4.2.1-alpha This commit sorts the changes files using sortChanges, and inserts them into a changelog entry. --- ChangeLog | 402 +++++++++++++++++++++++++++++++++++++++++++ changes/bug12399 | 3 - changes/bug23507 | 5 - changes/bug23818_v2 | 6 - changes/bug23818_v3 | 6 - changes/bug27284 | 5 - changes/bug30455 | 5 - changes/bug30721 | 10 -- changes/bug30780 | 3 - changes/bug30799 | 4 - changes/bug30804 | 4 - changes/bug30840 | 4 - changes/bug30841 | 3 - changes/bug30958 | 5 - changes/bug31040 | 3 - changes/bug31088 | 5 - changes/bug31112 | 3 - changes/bug31113 | 3 - changes/bug31442 | 3 - changes/bug31462 | 4 - changes/bug31463 | 3 - changes/bug31490 | 6 - changes/bug31552 | 5 - changes/bug31570 | 5 - changes/bug31571 | 7 - changes/bug31594 | 5 - changes/bug31615 | 5 - changes/bug31657 | 5 - changes/bug31696 | 5 - changes/doc31089 | 4 - changes/ticket19381 | 4 - changes/ticket21003 | 3 - changes/ticket24963 | 5 - changes/ticket24964 | 4 - changes/ticket27530 | 4 - changes/ticket29533 | 3 - changes/ticket29738 | 6 - changes/ticket29746 | 4 - changes/ticket29879 | 7 - changes/ticket29976 | 3 - changes/ticket30102 | 4 - changes/ticket30550 | 2 - changes/ticket30687 | 3 - changes/ticket30752 | 6 - changes/ticket30769 | 4 - changes/ticket30806 | 3 - changes/ticket30864 | 3 - changes/ticket30871 | 6 - changes/ticket30889 | 3 - changes/ticket30893 | 3 - changes/ticket30914 | 4 - changes/ticket30921 | 5 - changes/ticket30924 | 6 - changes/ticket30935 | 6 - changes/ticket30955 | 3 - changes/ticket30956_refactor | 3 - changes/ticket30967 | 6 - changes/ticket30979 | 7 - changes/ticket31008 | 3 - changes/ticket31012 | 4 - changes/ticket31025 | 5 - changes/ticket31026 | 5 - changes/ticket31030 | 3 - changes/ticket31175 | 3 - changes/ticket31176 | 5 - changes/ticket31240 | 5 - changes/ticket31304 | 3 - changes/ticket31309 | 4 - changes/ticket31314 | 18 -- changes/ticket31320 | 3 - changes/ticket31451 | 4 - changes/ticket31475 | 5 - changes/ticket31477 | 3 - changes/ticket31529 | 5 - changes/ticket31532 | 4 - changes/ticket31545 | 5 - changes/ticket31554 | 4 - changes/ticket31578 | 6 - changes/ticket31625 | 4 - changes/ticket31626 | 4 - changes/ticket31637 | 6 - changes/ticket31673 | 3 - 82 files changed, 402 insertions(+), 368 deletions(-) delete mode 100644 changes/bug12399 delete mode 100644 changes/bug23507 delete mode 100644 changes/bug23818_v2 delete mode 100644 changes/bug23818_v3 delete mode 100644 changes/bug27284 delete mode 100644 changes/bug30455 delete mode 100644 changes/bug30721 delete mode 100644 changes/bug30780 delete mode 100644 changes/bug30799 delete mode 100644 changes/bug30804 delete mode 100644 changes/bug30840 delete mode 100644 changes/bug30841 delete mode 100644 changes/bug30958 delete mode 100644 changes/bug31040 delete mode 100644 changes/bug31088 delete mode 100644 changes/bug31112 delete mode 100644 changes/bug31113 delete mode 100644 changes/bug31442 delete mode 100644 changes/bug31462 delete mode 100644 changes/bug31463 delete mode 100644 changes/bug31490 delete mode 100644 changes/bug31552 delete mode 100644 changes/bug31570 delete mode 100644 changes/bug31571 delete mode 100644 changes/bug31594 delete mode 100644 changes/bug31615 delete mode 100644 changes/bug31657 delete mode 100644 changes/bug31696 delete mode 100644 changes/doc31089 delete mode 100644 changes/ticket19381 delete mode 100644 changes/ticket21003 delete mode 100644 changes/ticket24963 delete mode 100644 changes/ticket24964 delete mode 100644 changes/ticket27530 delete mode 100644 changes/ticket29533 delete mode 100644 changes/ticket29738 delete mode 100644 changes/ticket29746 delete mode 100644 changes/ticket29879 delete mode 100644 changes/ticket29976 delete mode 100644 changes/ticket30102 delete mode 100644 changes/ticket30550 delete mode 100644 changes/ticket30687 delete mode 100644 changes/ticket30752 delete mode 100644 changes/ticket30769 delete mode 100644 changes/ticket30806 delete mode 100644 changes/ticket30864 delete mode 100644 changes/ticket30871 delete mode 100644 changes/ticket30889 delete mode 100644 changes/ticket30893 delete mode 100644 changes/ticket30914 delete mode 100644 changes/ticket30921 delete mode 100644 changes/ticket30924 delete mode 100644 changes/ticket30935 delete mode 100644 changes/ticket30955 delete mode 100644 changes/ticket30956_refactor delete mode 100644 changes/ticket30967 delete mode 100644 changes/ticket30979 delete mode 100644 changes/ticket31008 delete mode 100644 changes/ticket31012 delete mode 100644 changes/ticket31025 delete mode 100644 changes/ticket31026 delete mode 100644 changes/ticket31030 delete mode 100644 changes/ticket31175 delete mode 100644 changes/ticket31176 delete mode 100644 changes/ticket31240 delete mode 100644 changes/ticket31304 delete mode 100644 changes/ticket31309 delete mode 100644 changes/ticket31314 delete mode 100644 changes/ticket31320 delete mode 100644 changes/ticket31451 delete mode 100644 changes/ticket31475 delete mode 100644 changes/ticket31477 delete mode 100644 changes/ticket31529 delete mode 100644 changes/ticket31532 delete mode 100644 changes/ticket31545 delete mode 100644 changes/ticket31554 delete mode 100644 changes/ticket31578 delete mode 100644 changes/ticket31625 delete mode 100644 changes/ticket31626 delete mode 100644 changes/ticket31637 delete mode 100644 changes/ticket31673 (limited to 'changes') diff --git a/ChangeLog b/ChangeLog index 637a1dfcd0..721604c65b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,405 @@ +Changes in version 0.4.2.1-alpha - 2019-09-?? + + o Major features (developer tools): + - Our best-practices tracker now integrates with our include-checker tool + to keep track of the layering violations that we have not yet fixed. + We hope to reduce this number over time to improve Tor's modularity. + Closes ticket 31176. + + o Major features (onion service v3, denial of service): + - Add onion service introduction denial of service defenses. They consist of + rate limiting client introduction at the intro point using parameters that + can be sent by the service within the ESTABLISH_INTRO cell. If the cell + extension for this is not used, the intro point will honor the consensus + parameters. Closes ticket 30924. + + o Major bugfixes (circuit build, guard): + - When considering upgrading circuits from "waiting for guard" to "open", + always ignore the ones that are mark for close. Else, we can end up in + the situation where a subsystem is notified of that circuit opening but + still marked for close leading to undesirable behavior. Fixes bug 30871; + bugfix on 0.3.0.1-alpha. + + o Major bugfixes (crash, android): + - Tolerate systems (including some Android installations) where madvise + and MADV_DONTDUMP are available at build-time, but not at run time. + Previously, these systems would notice a failed syscall and abort. + Fixes bug 31570; bugfix on 0.4.1.1-alpha. + + o Major bugfixes (crash, Linux): + - Tolerate systems (including some Linux installations) where madvise + and/or MADV_DONTFORK are available at build-time, but not at run time. + Previously, these systems would notice a failed syscall and abort. + Fixes bug 31696; bugfix on 0.4.1.1-alpha. + + o Minor feature (onion service v3): + - Do not allow single hop client to fetch or post an HS descriptor from an + HSDir. Closes ticket 24964; + + o Minor feature (onion service): + - Disallow single hop clients to introduce directly at the introduction + point. We've removed Tor2web a while back and rendezvous are blocked at + the relays. This is to remove load off the network from spammy clients. + Close ticket 24963. + + o Minor feature (token bucket): + - Implement a generic token bucket that uses a single counter. This will be + useful for the anti-DoS onion service work. Closes ticket 30687. + + o Minor features (best practices tracker): + - Add a TOR_PRACTRACKER_OPTIONS variable for passing arguments + to practracker from the environment. We may want this for + continuous integration. Closes ticket 31309. + - Give a warning rather than an error when a practracker exception is + violated by a small amount; add a --list-overbroad option to + practracker that lists exceptions that are stricter than they need to + be, and provide an environment variable for disabling + practracker. Closes ticekt 30752. + + o Minor features (build system): + - Add --disable-manpage and --disable-html-manual options to configure + script. This will enable shortening build times by not building + documentation. Resolves issue 19381. + + o Minor features (compilation): + - Log a more useful error message when we are compiling and one of the + compile-time hardening options we have selected can be linked but + not executed. Closes ticket 27530. + + o Minor features (configuration): + - The configuration code has been extended to allow splitting + configuration data across multiple objects. Previously, all + configuration data needed to be kept in a single object, which + tended to become bloated. Closes ticket 31240. + + o Minor features (continuous integration): + - When running CI builds on Travis, put some random data in ~/.torrc, + to make sure no tests are dependent on default Tor configuration. + Resolves issue 30102. + + o Minor features (debugging): + - Log a nonfatal assertion failure if we encounter a configuration + line whose command is "CLEAR" but which has a nonempty value. + This should be impossible, according to the rules of our + configuration line parsing. Closes ticket 31529. + + o Minor features (development tools): + - Our best-practices tracker now looks at headers as well as + C files. Closes ticket 31175. + + o Minor features (git hooks): + - Our pre-commit git hook now checks for a special file + before running practracker, so that practracker only runs on branches + that are based on master. Since the pre-push hook calls the pre-commit + hook, practracker will also only run before pushes of branches based + on master. + Closes ticket 30979. + + o Minor features (git scripts): + - Add a "--" command-line argument, to + separate git-push-all.sh script arguments from arguments that are passed + through to git push. Closes ticket 31314. + - Add a -r argument to git-push-all.sh, so the script can + push test branches to a personal remote. Closes ticket 31314. + - Add a -t argument to git-merge-forward.sh and + git-push-all.sh, which makes these scripts create, merge forward, and + push test branches. Closes ticket 31314. + - Add a -u argument to git-merge-forward.sh, so that the script can re-use + existing test branches after a merge failure and fix. + Closes ticket 31314. + - Add a TOR_GIT_PUSH env var, which sets the default git push command and + arguments for git-push-all.sh. Closes ticket 31314. + - Add a TOR_PUSH_DELAY variable to git-push-all.sh, which makes the script + push master and maint branches with a delay between each branch. These + delays trigger the CI jobs in a set order, which should show the most + likely failures first. Also make pushes atomic by default, and make + the script pass any command-line arguments to git push. + Closes ticket 29879. + - Call the shellcheck script from the pre-commit hook. + Closes ticket 30967. + - Skip pushing test branches that are the same as a remote + maint/release/master branch in git-push-all.sh by default. Add a -s + argument, so git-push-all.sh can push all test branches. + Closes ticket 31314. + + o Minor features (IPv6, logging): + - Log IPv6 addresses as well as IPv4 addresses, when describing + routerinfos, routerstatuses, and nodes. Closes ticket 21003. + + o Minor features (recommended packages): + - No longer include recommended packages in votes as detailed in proposal + 301. The RecommendedPackages torrc option is deprecated and will no + longer have any effect. "package" lines will still be considered when + computing consensuses for consensus methods that include them. Fixes + ticket 29738. + + o Minor features (stem tests): + - Change "make test-stem" so it only runs the stem tests that use tor. + This change makes test-stem faster and more reliable. + Closes ticket 31554. + + o Minor features (testing): + - Add a script to invoke "tor --dump-config" and "tor --verify-config" + with various configuration options, and see whether tor's resulting + configuration or error messages are what we expect. Use it for + integration testing of our +Option and /Option flags. + Closes ticket 31637. + - Improve test coverage for our existing configuration parsing and + management API. Closes ticket 30893. + + o Minor features (tests): + - Add integration tests to make sure that practracker gives the outputs + we expect. Closes ticket 31477. + - The practracker tests are now run as part of the Tor test suite. + Closes ticket 31304. + + o Minor bugfixes (best practices tracker): + - Fix a few issues in the best-practices script, including tests, tab + tolerance, error reporting, and directory-exclusion logic. Fixes bug + 29746; bugfix on 0.4.1.1-alpha. + + o Minor bugfixes (chutney, makefiles, documentation): + - "make test-network-all" shows the warnings from each test-network.sh + run on the console, so developers see new warnings early. Improve the + documentation for this feature, and rename a Makefile variable so the + code is self-documenting. Fixes bug 30455; bugfix on 0.3.0.4-rc. + + o Minor bugfixes (compilation): + - Add more stub functions to fix compilation on Android with LTO, when + --disable-module-dirauth is used. Previously, these compilation + settings would make the compiler look for functions that didn't exist. + Fixes bug 31552; bugfix on 0.4.1.1-alpha. + + o Minor bugfixes (configuration): + - Invalid floating-point values in the configuration file are now + detected treated as errors in the configuration. Previously, they + were ignored and treated as zero. Fixes bug 31475; bugfix on + 0.0.1. + + o Minor bugfixes (coverity compliance): + - Add an assertion when parsing a BEGIN cell so that coverity can be sure + that we are not about to dereference a NULL address. + Fixes bug 31026; bugfix on 0.2.4.7-alpha. This is CID + 1447296. + + o Minor bugfixes (coverity): + - In our siphash implementation, when building for coverity, use memcpy + in place of a switch statement, so that coverity can tell we are not + accessing out-of-bounds memory. Fixes bug 31025; bugfix on + 0.2.8.1-alpha. This is tracked as CID 1447293 and 1447295. + + o Minor bugfixes (coverity, tests): + - Fix several coverity warnings from our unit tests. Fixes bug 31030; + bugfix on 0.2.4.1-alpha, 0.3.2.1-alpha, and 0.4.0.1-alpha. + + o Minor bugfixes (developer tooling): + - Only log git script changes in post-merge script when merge was to the + master branch. Fixes bug 31040; bugfix on 0.4.1.1-alpha. + + o Minor bugfixes (directory authorities): + - Return a distinct status when formatting annotations fails. + Fixes bug 30780; bugfix on 0.2.0.8-alpha. + + o Minor bugfixes (error handling): + - On abort, try harder to flush the output buffers of log messages. On + some platforms (macOS), log messages can be discarded when the process + terminates. Fixes bug 31571; bugfix on 0.3.5.1-alpha. + - Report the tor version whenever an assertion fails. Previously, we only + reported the Tor version on some crashes, and some non-fatal assertions. + Fixes bug 31571; bugfix on 0.3.5.1-alpha. + - When tor aborts due to an error, close log file descriptors before + aborting. Closing the logs makes some OSes flush log file buffers, + rather than deleting buffered log lines. Fixes bug 31594; + bugfix on 0.2.5.2-alpha. + + o Minor bugfixes (git hooks): + - Remove a duplicate call to practracker from the pre-push hook. + The pre-push hook already calls the pre-commit hook, which calls + practracker. Fixes bug 31462; bugfix on 0.4.1.1-alpha. + + o Minor bugfixes (git scripts): + - Stop hard-coding the bash path in the git scripts. Some OSes don't + have bash in /usr/bin, others have an ancient bash at this path. + Fixes bug 30840; bugfix on 0.4.0.1-alpha. + - Stop hard-coding the tor master branch name and worktree path in the + git scripts. Fixes bug 30841; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (guards): + - When tor is missing descriptors for some primary entry guards, make the + log message less alarming. It's normal for descriptors to expire, as long + as tor fetches new ones soon after. Fixes bug 31657; + bugfix on 0.3.3.1-alpha. + + o Minor bugfixes (ipv6): + - We check for private IPv6 address alongside their IPv4 equivalents when + authorities check descriptors. Previously, we only checked for private + IPv4 addresses. Fixes bug 31088; bugfix on 0.2.3.21-rc. Patch by Neel + Chauhan. + - When parsing microdescriptors, we should check the IPv6 exit policy + alongside IPv4. Previously, we checked both exit policies for only + router info structures, while microdescriptors were IPv4-only. Fixes + bug 27284; bugfix on 0.2.3.1-alpha. Patch by Neel Chauhan. + + o Minor bugfixes (logging): + - Change log level of message "Hash of session info was not as expected" + to LOG_PROTOCOL_WARN. Fixes bug 12399; bugfix on 0.1.1.10-alpha. + - Fix a code issue that would have broken our parsing of log + domains as soon as we had 33 of them. Fortunately, we still + only have 29. Fixes bug 31451; bugfix on 0.4.1.4-rc. + + o Minor bugfixes (memory management): + - Stop leaking a small amount of memory in nt_service_install(), in + unreachable code. Fixes bug 30799; bugfix on 0.2.0.7-alpha. + Patch by Xiaoyin Liu. + + o Minor bugfixes (networking, IP addresses): + - When parsing addreses via Tor's internal DNS lookup API, reject IPv4 + addresses in square brackets, and accept IPv6 addresses in square + brackets. This change completes the work started in 23082, making + address parsing consistent between tor's internal DNS lookup and address + parsing APIs. Fixes bug 30721; bugfix on 0.2.1.5-alpha. + - When parsing addreses via Tor's internal address:port parsing and + DNS lookup APIs, require IPv6 addresses with ports to have square + brackets. But allow IPv6 addresses without ports, whether or not they + have square brackets. Fixes bug 30721; bugfix on 0.2.1.5-alpha. + + o Minor bugfixes (onion service v3): + - When purging the client descriptor cache, always also close any + introduction point circuits associated with it. This avoids picking those + when connecting to them later while not having the descriptor to complete + the introduction. Fixes bug 30921; bugfix on 0.3.2.1-alpha. + + o Minor bugfixes (onion services): + - In the hs_ident_circuit_t data structure, remove the unused field + circuit_type and the respective argument in hs_ident_circuit_new(). + This field is set by clients (for introduction) and services (for + introduction and rendezvous) but is never used afterwards. Fixes + bug 31490; bugfix on 0.3.2.1-alpha. Patch by Neel Chauhan. + + o Minor bugfixes (operator tools): + - Make tor-print-ed-signing-cert(1) print certificate expiration date in + RFC 1123 and UNIX timestamp formats, to make output machine readable. + Fixes bug 31012; bugfix on 0.3.5.1-alpha. + + o Minor bugfixes (practracker): + - When running check-best-practices, only consider files in the + src subdirectory. Previously we had recursively considered + all subdirectories, which made us get confused by the + temporary directories made by "make distcheck". Fixes bug + 31578; bugfix on 0.4.1.1-alpha. + + o Minor bugfixes (rust): + - Correctly exclude a redundant rust build job in Travis. Fixes bug 31463; + bugfix on 0.3.5.4-alpha. + - Raise the minimum rustc version to 1.31.0, as checked by configure + and CI. Fixes bug 31442; bugfix on 0.3.5.4-alpha. + + o Minor bugfixes (sendme, code structure): + - Rename the trunnel SENDME file definition from sendme.trunnel to + sendme_cell.trunnel to avoid having twice sendme.{c|h} in the repository. + Fixes bug 30769; bugfix on 0.4.1.1-alpha. + + o Minor bugfixes (statistics): + - Stop removing the ed25519 signature if the extra info file is too big. + If the signature data was removed, but the keyword was kept, this could + result in an unparseable extra info file. Fixes bug 30958; + bugfix on 0.2.7.2-alpha. + + o Minor bugfixes (subsystems): + - Make the subsystem init order match the subsystem module dependencies. + Call windows process security APIs as early as possible. Init log before + network and time, so that network and time can use logging. + Fixes bug 31615; bugfix on 0.4.0.1-alpha. + + o Minor bugfixes (testing): + - Teach the util/socketpair_ersatz test to work correctly when we + have no network stack configured. Fixes bug 30804; bugfix on + 0.2.5.1-alpha. + + o Minor bugfixes (v2 single onion services): + - Always retry v2 single onion service intro and rend circuits with a + 3-hop path. Previously, v2 single onion services used a 3-hop path + when rend circuits were retried after a remote or delayed failure, + but a 1-hop path for immediate retries. Fixes bug 23818; + bugfix on 0.2.9.3-alpha. + + o Minor bugfixes (v3 single onion services): + - Always retry v3 single onion service intro and rend circuits with a + 3-hop path. Previously, v3 single onion services used a 3-hop path + when rend circuits were retried after a remote or delayed failure, + but a 1-hop path for immediate retries. Fixes bug 23818; + bugfix on 0.3.2.1-alpha. + - Make v3 single onion services fall back to a 3-hop intro, when there + all intro points are unreachable via a 1-hop path. Previously, v3 + single onion services failed when all intro nodes were unreachable + via a 1-hop path. Fixes bug 23507; bugfix on 0.3.2.1-alpha. + + o Code simplification and refactoring: + - Eliminate some uses of lower-level control reply abstractions, + primarily in the onion_helper functions. Closes ticket 30889. + - Extract our variable manipulation code from confparse.c to a new + lower-level typedvar.h module. Closes ticket 30864. + - Improve documentation in circuit padding subsystem. Patch by Tobias + Pulls. Closes ticket 31113. + - Lower another layer of object management from confparse.c to + a more general tool. Now typed structure members are accessible + via an abstract type. Implements ticket 30914. + - Move our backend logic for working with configuration and state + files into a lower-level library, since in no longer depends on + any tor-specific functionality. Closes ticket 31626. + - Numerous simplifications in configuration-handling logic: + remove duplicated macro definitions, replace magical names + with flags, and refactor "TestingTorNetwork" to use the + same default-option logic as the rest of Tor. + Closes ticket 30935. + - Replace our ad-hoc set of flags for configuration variables and + configuration variable types with fine-grained orthogonal flags + corresponding to the actual behavior we want. Closes ticket 31625. + - Rework bootstrap tracking to use the new publish-subscribe + subsystem. Closes ticket 29976. + - Rewrite format_node_description() and router_get_verbose_nickname() to + use strlcpy() and strlcat(). The previous implementation used memcpy() + and pointer arithmetic, which was error-prone. + Closes ticket 31545. This is CID 1452819. + - Split extrainfo_dump_to_string() into smaller functions. + Closes ticket 30956. + - Use the ptrdiff_t type consistently for expressing variable offsets and + pointer differences. Previously we incorrectly (but harmlessly) used + int and sometimes off_t for these cases. Closes ticket 31532. + - Use the subsystems mechanism to manage the main event loop code. + Closes ticket 30806. + - Various simplifications and minor improvements to the circuit padding + machines. Patch by Tobias Pulls. Closes tickets 31112 and 31098. + + o Documentation (hard-coded directories): + - Improve the documentation for the DirAuthority and FallbackDir torrc + options. Closes ticket 30955. + + o Documentation (tor.1 man page): + - Fix typo -help to --help in tor.1 man page. Fixes bug 31008; bugfix on + 0.2.2.9-alpha. + + o Documentation: + - Include an example usage for IPv6 ORPort in our sample torrc. + Closes ticket 31320; patch from Ali Raheem. + - Use RFC 2397 data URL scheme to embed image into tor-exit-notice.html + so that operators would no longer have to host it themselves. + Closes ticket 31089. + + o New system requirements (build system): + - Do not include the deprecated on Linux or Windows system. + Closes 31673; + + o Removed features: + - Remove torctl.in from contrib/dist directory. Resolves ticket 30550. + + o Testing: + - Run shellcheck for all non-third-party shell scripts that are shipped + with Tor. Closes ticket 29533. + - When checking shell scripts, ignore any user-created directories. + Closes ticket 30967. + + Changes in version 0.4.1.5 - 2019-08-20 This is the first stable release in the 0.4.1.x series. This series adds experimental circuit-level padding, authenticated SENDME cells to diff --git a/changes/bug12399 b/changes/bug12399 deleted file mode 100644 index 922c08c5e3..0000000000 --- a/changes/bug12399 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (logging): - - Change log level of message "Hash of session info was not as expected" - to LOG_PROTOCOL_WARN. Fixes bug 12399; bugfix on 0.1.1.10-alpha. diff --git a/changes/bug23507 b/changes/bug23507 deleted file mode 100644 index de18273fdb..0000000000 --- a/changes/bug23507 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (v3 single onion services): - - Make v3 single onion services fall back to a 3-hop intro, when there - all intro points are unreachable via a 1-hop path. Previously, v3 - single onion services failed when all intro nodes were unreachable - via a 1-hop path. Fixes bug 23507; bugfix on 0.3.2.1-alpha. diff --git a/changes/bug23818_v2 b/changes/bug23818_v2 deleted file mode 100644 index 0219a20f49..0000000000 --- a/changes/bug23818_v2 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (v2 single onion services): - - Always retry v2 single onion service intro and rend circuits with a - 3-hop path. Previously, v2 single onion services used a 3-hop path - when rend circuits were retried after a remote or delayed failure, - but a 1-hop path for immediate retries. Fixes bug 23818; - bugfix on 0.2.9.3-alpha. diff --git a/changes/bug23818_v3 b/changes/bug23818_v3 deleted file mode 100644 index c430144d81..0000000000 --- a/changes/bug23818_v3 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (v3 single onion services): - - Always retry v3 single onion service intro and rend circuits with a - 3-hop path. Previously, v3 single onion services used a 3-hop path - when rend circuits were retried after a remote or delayed failure, - but a 1-hop path for immediate retries. Fixes bug 23818; - bugfix on 0.3.2.1-alpha. diff --git a/changes/bug27284 b/changes/bug27284 deleted file mode 100644 index 14fc2082fe..0000000000 --- a/changes/bug27284 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (ipv6): - - When parsing microdescriptors, we should check the IPv6 exit policy - alongside IPv4. Previously, we checked both exit policies for only - router info structures, while microdescriptors were IPv4-only. Fixes - bug 27284; bugfix on 0.2.3.1-alpha. Patch by Neel Chauhan. diff --git a/changes/bug30455 b/changes/bug30455 deleted file mode 100644 index aecbde5a33..0000000000 --- a/changes/bug30455 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (chutney, makefiles, documentation): - - "make test-network-all" shows the warnings from each test-network.sh - run on the console, so developers see new warnings early. Improve the - documentation for this feature, and rename a Makefile variable so the - code is self-documenting. Fixes bug 30455; bugfix on 0.3.0.4-rc. diff --git a/changes/bug30721 b/changes/bug30721 deleted file mode 100644 index 5ea4a14625..0000000000 --- a/changes/bug30721 +++ /dev/null @@ -1,10 +0,0 @@ - o Minor bugfixes (networking, IP addresses): - - When parsing addreses via Tor's internal DNS lookup API, reject IPv4 - addresses in square brackets, and accept IPv6 addresses in square - brackets. This change completes the work started in 23082, making - address parsing consistent between tor's internal DNS lookup and address - parsing APIs. Fixes bug 30721; bugfix on 0.2.1.5-alpha. - - When parsing addreses via Tor's internal address:port parsing and - DNS lookup APIs, require IPv6 addresses with ports to have square - brackets. But allow IPv6 addresses without ports, whether or not they - have square brackets. Fixes bug 30721; bugfix on 0.2.1.5-alpha. diff --git a/changes/bug30780 b/changes/bug30780 deleted file mode 100644 index 5731d201a2..0000000000 --- a/changes/bug30780 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (directory authorities): - - Return a distinct status when formatting annotations fails. - Fixes bug 30780; bugfix on 0.2.0.8-alpha. diff --git a/changes/bug30799 b/changes/bug30799 deleted file mode 100644 index b10420a953..0000000000 --- a/changes/bug30799 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (memory management): - - Stop leaking a small amount of memory in nt_service_install(), in - unreachable code. Fixes bug 30799; bugfix on 0.2.0.7-alpha. - Patch by Xiaoyin Liu. diff --git a/changes/bug30804 b/changes/bug30804 deleted file mode 100644 index ba4a3e8b8c..0000000000 --- a/changes/bug30804 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (testing): - - Teach the util/socketpair_ersatz test to work correctly when we - have no network stack configured. Fixes bug 30804; bugfix on - 0.2.5.1-alpha. diff --git a/changes/bug30840 b/changes/bug30840 deleted file mode 100644 index 562b0fbd93..0000000000 --- a/changes/bug30840 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (git scripts): - - Stop hard-coding the bash path in the git scripts. Some OSes don't - have bash in /usr/bin, others have an ancient bash at this path. - Fixes bug 30840; bugfix on 0.4.0.1-alpha. diff --git a/changes/bug30841 b/changes/bug30841 deleted file mode 100644 index c6d1c51469..0000000000 --- a/changes/bug30841 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (git scripts): - - Stop hard-coding the tor master branch name and worktree path in the - git scripts. Fixes bug 30841; bugfix on 0.4.0.1-alpha. diff --git a/changes/bug30958 b/changes/bug30958 deleted file mode 100644 index 374c8e46f7..0000000000 --- a/changes/bug30958 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (statistics): - - Stop removing the ed25519 signature if the extra info file is too big. - If the signature data was removed, but the keyword was kept, this could - result in an unparseable extra info file. Fixes bug 30958; - bugfix on 0.2.7.2-alpha. diff --git a/changes/bug31040 b/changes/bug31040 deleted file mode 100644 index 81f6d7e795..0000000000 --- a/changes/bug31040 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (developer tooling): - - Only log git script changes in post-merge script when merge was to the - master branch. Fixes bug 31040; bugfix on 0.4.1.1-alpha. diff --git a/changes/bug31088 b/changes/bug31088 deleted file mode 100644 index c258d1bada..0000000000 --- a/changes/bug31088 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (ipv6): - - We check for private IPv6 address alongside their IPv4 equivalents when - authorities check descriptors. Previously, we only checked for private - IPv4 addresses. Fixes bug 31088; bugfix on 0.2.3.21-rc. Patch by Neel - Chauhan. diff --git a/changes/bug31112 b/changes/bug31112 deleted file mode 100644 index 882efaad59..0000000000 --- a/changes/bug31112 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Various simplifications and minor improvements to the circuit padding - machines. Patch by Tobias Pulls. Closes tickets 31112 and 31098. diff --git a/changes/bug31113 b/changes/bug31113 deleted file mode 100644 index f48328f0fe..0000000000 --- a/changes/bug31113 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Improve documentation in circuit padding subsystem. Patch by Tobias - Pulls. Closes ticket 31113. diff --git a/changes/bug31442 b/changes/bug31442 deleted file mode 100644 index 4df9fc6dfb..0000000000 --- a/changes/bug31442 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (rust): - - Raise the minimum rustc version to 1.31.0, as checked by configure - and CI. Fixes bug 31442; bugfix on 0.3.5.4-alpha. diff --git a/changes/bug31462 b/changes/bug31462 deleted file mode 100644 index 54ab990bb8..0000000000 --- a/changes/bug31462 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (git hooks): - - Remove a duplicate call to practracker from the pre-push hook. - The pre-push hook already calls the pre-commit hook, which calls - practracker. Fixes bug 31462; bugfix on 0.4.1.1-alpha. diff --git a/changes/bug31463 b/changes/bug31463 deleted file mode 100644 index d85c0887c3..0000000000 --- a/changes/bug31463 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (rust): - - Correctly exclude a redundant rust build job in Travis. Fixes bug 31463; - bugfix on 0.3.5.4-alpha. diff --git a/changes/bug31490 b/changes/bug31490 deleted file mode 100644 index 24782be3ec..0000000000 --- a/changes/bug31490 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (onion services): - - In the hs_ident_circuit_t data structure, remove the unused field - circuit_type and the respective argument in hs_ident_circuit_new(). - This field is set by clients (for introduction) and services (for - introduction and rendezvous) but is never used afterwards. Fixes - bug 31490; bugfix on 0.3.2.1-alpha. Patch by Neel Chauhan. diff --git a/changes/bug31552 b/changes/bug31552 deleted file mode 100644 index fb33e14429..0000000000 --- a/changes/bug31552 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (compilation): - - Add more stub functions to fix compilation on Android with LTO, when - --disable-module-dirauth is used. Previously, these compilation - settings would make the compiler look for functions that didn't exist. - Fixes bug 31552; bugfix on 0.4.1.1-alpha. diff --git a/changes/bug31570 b/changes/bug31570 deleted file mode 100644 index f70b577b4c..0000000000 --- a/changes/bug31570 +++ /dev/null @@ -1,5 +0,0 @@ - o Major bugfixes (crash, android): - - Tolerate systems (including some Android installations) where madvise - and MADV_DONTDUMP are available at build-time, but not at run time. - Previously, these systems would notice a failed syscall and abort. - Fixes bug 31570; bugfix on 0.4.1.1-alpha. diff --git a/changes/bug31571 b/changes/bug31571 deleted file mode 100644 index 86de3537ba..0000000000 --- a/changes/bug31571 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor bugfixes (error handling): - - Report the tor version whenever an assertion fails. Previously, we only - reported the Tor version on some crashes, and some non-fatal assertions. - Fixes bug 31571; bugfix on 0.3.5.1-alpha. - - On abort, try harder to flush the output buffers of log messages. On - some platforms (macOS), log messages can be discarded when the process - terminates. Fixes bug 31571; bugfix on 0.3.5.1-alpha. diff --git a/changes/bug31594 b/changes/bug31594 deleted file mode 100644 index 75e6ec33cc..0000000000 --- a/changes/bug31594 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (error handling): - - When tor aborts due to an error, close log file descriptors before - aborting. Closing the logs makes some OSes flush log file buffers, - rather than deleting buffered log lines. Fixes bug 31594; - bugfix on 0.2.5.2-alpha. diff --git a/changes/bug31615 b/changes/bug31615 deleted file mode 100644 index 49b13bea95..0000000000 --- a/changes/bug31615 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (subsystems): - - Make the subsystem init order match the subsystem module dependencies. - Call windows process security APIs as early as possible. Init log before - network and time, so that network and time can use logging. - Fixes bug 31615; bugfix on 0.4.0.1-alpha. diff --git a/changes/bug31657 b/changes/bug31657 deleted file mode 100644 index 08e9d95fdf..0000000000 --- a/changes/bug31657 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (guards): - - When tor is missing descriptors for some primary entry guards, make the - log message less alarming. It's normal for descriptors to expire, as long - as tor fetches new ones soon after. Fixes bug 31657; - bugfix on 0.3.3.1-alpha. diff --git a/changes/bug31696 b/changes/bug31696 deleted file mode 100644 index b9d6c4130c..0000000000 --- a/changes/bug31696 +++ /dev/null @@ -1,5 +0,0 @@ - o Major bugfixes (crash, Linux): - - Tolerate systems (including some Linux installations) where madvise - and/or MADV_DONTFORK are available at build-time, but not at run time. - Previously, these systems would notice a failed syscall and abort. - Fixes bug 31696; bugfix on 0.4.1.1-alpha. diff --git a/changes/doc31089 b/changes/doc31089 deleted file mode 100644 index 2fc0ba4f7d..0000000000 --- a/changes/doc31089 +++ /dev/null @@ -1,4 +0,0 @@ - o Documentation: - - Use RFC 2397 data URL scheme to embed image into tor-exit-notice.html - so that operators would no longer have to host it themselves. - Closes ticket 31089. diff --git a/changes/ticket19381 b/changes/ticket19381 deleted file mode 100644 index ee51e2a3e2..0000000000 --- a/changes/ticket19381 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (build system): - - Add --disable-manpage and --disable-html-manual options to configure - script. This will enable shortening build times by not building - documentation. Resolves issue 19381. diff --git a/changes/ticket21003 b/changes/ticket21003 deleted file mode 100644 index 896d7493eb..0000000000 --- a/changes/ticket21003 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (IPv6, logging): - - Log IPv6 addresses as well as IPv4 addresses, when describing - routerinfos, routerstatuses, and nodes. Closes ticket 21003. diff --git a/changes/ticket24963 b/changes/ticket24963 deleted file mode 100644 index 50adcfaaf4..0000000000 --- a/changes/ticket24963 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor feature (onion service): - - Disallow single hop clients to introduce directly at the introduction - point. We've removed Tor2web a while back and rendezvous are blocked at - the relays. This is to remove load off the network from spammy clients. - Close ticket 24963. diff --git a/changes/ticket24964 b/changes/ticket24964 deleted file mode 100644 index 171c86eb1d..0000000000 --- a/changes/ticket24964 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor feature (onion service v3): - - Do not allow single hop client to fetch or post an HS descriptor from an - HSDir. Closes ticket 24964; - diff --git a/changes/ticket27530 b/changes/ticket27530 deleted file mode 100644 index 8ae4f52668..0000000000 --- a/changes/ticket27530 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (compilation): - - Log a more useful error message when we are compiling and one of the - compile-time hardening options we have selected can be linked but - not executed. Closes ticket 27530. diff --git a/changes/ticket29533 b/changes/ticket29533 deleted file mode 100644 index 27ef681218..0000000000 --- a/changes/ticket29533 +++ /dev/null @@ -1,3 +0,0 @@ - o Testing: - - Run shellcheck for all non-third-party shell scripts that are shipped - with Tor. Closes ticket 29533. diff --git a/changes/ticket29738 b/changes/ticket29738 deleted file mode 100644 index 9217cc9a5f..0000000000 --- a/changes/ticket29738 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor features (recommended packages): - - No longer include recommended packages in votes as detailed in proposal - 301. The RecommendedPackages torrc option is deprecated and will no - longer have any effect. "package" lines will still be considered when - computing consensuses for consensus methods that include them. Fixes - ticket 29738. diff --git a/changes/ticket29746 b/changes/ticket29746 deleted file mode 100644 index 63b9edb391..0000000000 --- a/changes/ticket29746 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (best practices tracker): - - Fix a few issues in the best-practices script, including tests, tab - tolerance, error reporting, and directory-exclusion logic. Fixes bug - 29746; bugfix on 0.4.1.1-alpha. diff --git a/changes/ticket29879 b/changes/ticket29879 deleted file mode 100644 index c37bdd3f62..0000000000 --- a/changes/ticket29879 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (git scripts): - - Add a TOR_PUSH_DELAY variable to git-push-all.sh, which makes the script - push master and maint branches with a delay between each branch. These - delays trigger the CI jobs in a set order, which should show the most - likely failures first. Also make pushes atomic by default, and make - the script pass any command-line arguments to git push. - Closes ticket 29879. diff --git a/changes/ticket29976 b/changes/ticket29976 deleted file mode 100644 index 9991bfb1ff..0000000000 --- a/changes/ticket29976 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Rework bootstrap tracking to use the new publish-subscribe - subsystem. Closes ticket 29976. diff --git a/changes/ticket30102 b/changes/ticket30102 deleted file mode 100644 index c8b1148da3..0000000000 --- a/changes/ticket30102 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (continuous integration): - - When running CI builds on Travis, put some random data in ~/.torrc, - to make sure no tests are dependent on default Tor configuration. - Resolves issue 30102. diff --git a/changes/ticket30550 b/changes/ticket30550 deleted file mode 100644 index f356c4048e..0000000000 --- a/changes/ticket30550 +++ /dev/null @@ -1,2 +0,0 @@ - o Removed features: - - Remove torctl.in from contrib/dist directory. Resolves ticket 30550. diff --git a/changes/ticket30687 b/changes/ticket30687 deleted file mode 100644 index c3124eb64b..0000000000 --- a/changes/ticket30687 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor feature (token bucket): - - Implement a generic token bucket that uses a single counter. This will be - useful for the anti-DoS onion service work. Closes ticket 30687. diff --git a/changes/ticket30752 b/changes/ticket30752 deleted file mode 100644 index 044c7c7d93..0000000000 --- a/changes/ticket30752 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor features (best practices tracker): - - Give a warning rather than an error when a practracker exception is - violated by a small amount; add a --list-overbroad option to - practracker that lists exceptions that are stricter than they need to - be, and provide an environment variable for disabling - practracker. Closes ticekt 30752. diff --git a/changes/ticket30769 b/changes/ticket30769 deleted file mode 100644 index 74f63a1465..0000000000 --- a/changes/ticket30769 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (sendme, code structure): - - Rename the trunnel SENDME file definition from sendme.trunnel to - sendme_cell.trunnel to avoid having twice sendme.{c|h} in the repository. - Fixes bug 30769; bugfix on 0.4.1.1-alpha. diff --git a/changes/ticket30806 b/changes/ticket30806 deleted file mode 100644 index 4f09ea2af3..0000000000 --- a/changes/ticket30806 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Use the subsystems mechanism to manage the main event loop code. - Closes ticket 30806. diff --git a/changes/ticket30864 b/changes/ticket30864 deleted file mode 100644 index b8fb571300..0000000000 --- a/changes/ticket30864 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Extract our variable manipulation code from confparse.c to a new - lower-level typedvar.h module. Closes ticket 30864. diff --git a/changes/ticket30871 b/changes/ticket30871 deleted file mode 100644 index 81c076bb02..0000000000 --- a/changes/ticket30871 +++ /dev/null @@ -1,6 +0,0 @@ - o Major bugfixes (circuit build, guard): - - When considering upgrading circuits from "waiting for guard" to "open", - always ignore the ones that are mark for close. Else, we can end up in - the situation where a subsystem is notified of that circuit opening but - still marked for close leading to undesirable behavior. Fixes bug 30871; - bugfix on 0.3.0.1-alpha. diff --git a/changes/ticket30889 b/changes/ticket30889 deleted file mode 100644 index 8582e2bcac..0000000000 --- a/changes/ticket30889 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Eliminate some uses of lower-level control reply abstractions, - primarily in the onion_helper functions. Closes ticket 30889. diff --git a/changes/ticket30893 b/changes/ticket30893 deleted file mode 100644 index 638b99a9f7..0000000000 --- a/changes/ticket30893 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (testing): - - Improve test coverage for our existing configuration parsing and - management API. Closes ticket 30893. diff --git a/changes/ticket30914 b/changes/ticket30914 deleted file mode 100644 index c8c008b3d1..0000000000 --- a/changes/ticket30914 +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring: - - Lower another layer of object management from confparse.c to - a more general tool. Now typed structure members are accessible - via an abstract type. Implements ticket 30914. diff --git a/changes/ticket30921 b/changes/ticket30921 deleted file mode 100644 index 50ec570ffe..0000000000 --- a/changes/ticket30921 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (onion service v3): - - When purging the client descriptor cache, always also close any - introduction point circuits associated with it. This avoids picking those - when connecting to them later while not having the descriptor to complete - the introduction. Fixes bug 30921; bugfix on 0.3.2.1-alpha. diff --git a/changes/ticket30924 b/changes/ticket30924 deleted file mode 100644 index 832c377972..0000000000 --- a/changes/ticket30924 +++ /dev/null @@ -1,6 +0,0 @@ - o Major features (onion service v3, denial of service): - - Add onion service introduction denial of service defenses. They consist of - rate limiting client introduction at the intro point using parameters that - can be sent by the service within the ESTABLISH_INTRO cell. If the cell - extension for this is not used, the intro point will honor the consensus - parameters. Closes ticket 30924. diff --git a/changes/ticket30935 b/changes/ticket30935 deleted file mode 100644 index 5a7e918895..0000000000 --- a/changes/ticket30935 +++ /dev/null @@ -1,6 +0,0 @@ - o Code simplification and refactoring: - - Numerous simplifications in configuration-handling logic: - remove duplicated macro definitions, replace magical names - with flags, and refactor "TestingTorNetwork" to use the - same default-option logic as the rest of Tor. - Closes ticket 30935. diff --git a/changes/ticket30955 b/changes/ticket30955 deleted file mode 100644 index 7715a07569..0000000000 --- a/changes/ticket30955 +++ /dev/null @@ -1,3 +0,0 @@ - o Documentation (hard-coded directories): - - Improve the documentation for the DirAuthority and FallbackDir torrc - options. Closes ticket 30955. diff --git a/changes/ticket30956_refactor b/changes/ticket30956_refactor deleted file mode 100644 index 81151c6cc9..0000000000 --- a/changes/ticket30956_refactor +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Split extrainfo_dump_to_string() into smaller functions. - Closes ticket 30956. diff --git a/changes/ticket30967 b/changes/ticket30967 deleted file mode 100644 index 5fe9c980b6..0000000000 --- a/changes/ticket30967 +++ /dev/null @@ -1,6 +0,0 @@ - o Testing: - - When checking shell scripts, ignore any user-created directories. - Closes ticket 30967. - o Minor features (git scripts): - - Call the shellcheck script from the pre-commit hook. - Closes ticket 30967. diff --git a/changes/ticket30979 b/changes/ticket30979 deleted file mode 100644 index ffe1bfb4ab..0000000000 --- a/changes/ticket30979 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (git hooks): - - Our pre-commit git hook now checks for a special file - before running practracker, so that practracker only runs on branches - that are based on master. Since the pre-push hook calls the pre-commit - hook, practracker will also only run before pushes of branches based - on master. - Closes ticket 30979. diff --git a/changes/ticket31008 b/changes/ticket31008 deleted file mode 100644 index c7077de6c6..0000000000 --- a/changes/ticket31008 +++ /dev/null @@ -1,3 +0,0 @@ - o Documentation (tor.1 man page): - - Fix typo -help to --help in tor.1 man page. Fixes bug 31008; bugfix on - 0.2.2.9-alpha. diff --git a/changes/ticket31012 b/changes/ticket31012 deleted file mode 100644 index 61ea30d8da..0000000000 --- a/changes/ticket31012 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (operator tools): - - Make tor-print-ed-signing-cert(1) print certificate expiration date in - RFC 1123 and UNIX timestamp formats, to make output machine readable. - Fixes bug 31012; bugfix on 0.3.5.1-alpha. diff --git a/changes/ticket31025 b/changes/ticket31025 deleted file mode 100644 index c572288239..0000000000 --- a/changes/ticket31025 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (coverity): - - In our siphash implementation, when building for coverity, use memcpy - in place of a switch statement, so that coverity can tell we are not - accessing out-of-bounds memory. Fixes bug 31025; bugfix on - 0.2.8.1-alpha. This is tracked as CID 1447293 and 1447295. diff --git a/changes/ticket31026 b/changes/ticket31026 deleted file mode 100644 index 6f6abcffba..0000000000 --- a/changes/ticket31026 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (coverity compliance): - - Add an assertion when parsing a BEGIN cell so that coverity can be sure - that we are not about to dereference a NULL address. - Fixes bug 31026; bugfix on 0.2.4.7-alpha. This is CID - 1447296. diff --git a/changes/ticket31030 b/changes/ticket31030 deleted file mode 100644 index 4d99323b4e..0000000000 --- a/changes/ticket31030 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (coverity, tests): - - Fix several coverity warnings from our unit tests. Fixes bug 31030; - bugfix on 0.2.4.1-alpha, 0.3.2.1-alpha, and 0.4.0.1-alpha. diff --git a/changes/ticket31175 b/changes/ticket31175 deleted file mode 100644 index cff13761a4..0000000000 --- a/changes/ticket31175 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (development tools): - - Our best-practices tracker now looks at headers as well as - C files. Closes ticket 31175. diff --git a/changes/ticket31176 b/changes/ticket31176 deleted file mode 100644 index 5fcdeab3af..0000000000 --- a/changes/ticket31176 +++ /dev/null @@ -1,5 +0,0 @@ - o Major features (developer tools): - - Our best-practices tracker now integrates with our include-checker tool - to keep track of the layering violations that we have not yet fixed. - We hope to reduce this number over time to improve Tor's modularity. - Closes ticket 31176. diff --git a/changes/ticket31240 b/changes/ticket31240 deleted file mode 100644 index 0fe37ff44b..0000000000 --- a/changes/ticket31240 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (configuration): - - The configuration code has been extended to allow splitting - configuration data across multiple objects. Previously, all - configuration data needed to be kept in a single object, which - tended to become bloated. Closes ticket 31240. diff --git a/changes/ticket31304 b/changes/ticket31304 deleted file mode 100644 index ca60148b0c..0000000000 --- a/changes/ticket31304 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (tests): - - The practracker tests are now run as part of the Tor test suite. - Closes ticket 31304. diff --git a/changes/ticket31309 b/changes/ticket31309 deleted file mode 100644 index 8e1c9f27ea..0000000000 --- a/changes/ticket31309 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (best practices tracker): - - Add a TOR_PRACTRACKER_OPTIONS variable for passing arguments - to practracker from the environment. We may want this for - continuous integration. Closes ticket 31309. diff --git a/changes/ticket31314 b/changes/ticket31314 deleted file mode 100644 index 7ce96e96cf..0000000000 --- a/changes/ticket31314 +++ /dev/null @@ -1,18 +0,0 @@ - o Minor features (git scripts): - - Add a -t argument to git-merge-forward.sh and - git-push-all.sh, which makes these scripts create, merge forward, and - push test branches. Closes ticket 31314. - - Add a -r argument to git-push-all.sh, so the script can - push test branches to a personal remote. Closes ticket 31314. - - Add a -u argument to git-merge-forward.sh, so that the script can re-use - existing test branches after a merge failure and fix. - Closes ticket 31314. - - Add a TOR_GIT_PUSH env var, which sets the default git push command and - arguments for git-push-all.sh. Closes ticket 31314. - - Add a "--" command-line argument, to - separate git-push-all.sh script arguments from arguments that are passed - through to git push. Closes ticket 31314. - - Skip pushing test branches that are the same as a remote - maint/release/master branch in git-push-all.sh by default. Add a -s - argument, so git-push-all.sh can push all test branches. - Closes ticket 31314. diff --git a/changes/ticket31320 b/changes/ticket31320 deleted file mode 100644 index 07847e5624..0000000000 --- a/changes/ticket31320 +++ /dev/null @@ -1,3 +0,0 @@ - o Documentation: - - Include an example usage for IPv6 ORPort in our sample torrc. - Closes ticket 31320; patch from Ali Raheem. diff --git a/changes/ticket31451 b/changes/ticket31451 deleted file mode 100644 index 773d665957..0000000000 --- a/changes/ticket31451 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (logging): - - Fix a code issue that would have broken our parsing of log - domains as soon as we had 33 of them. Fortunately, we still - only have 29. Fixes bug 31451; bugfix on 0.4.1.4-rc. diff --git a/changes/ticket31475 b/changes/ticket31475 deleted file mode 100644 index e156c145a9..0000000000 --- a/changes/ticket31475 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (configuration): - - Invalid floating-point values in the configuration file are now - detected treated as errors in the configuration. Previously, they - were ignored and treated as zero. Fixes bug 31475; bugfix on - 0.0.1. diff --git a/changes/ticket31477 b/changes/ticket31477 deleted file mode 100644 index 5a0fdd1544..0000000000 --- a/changes/ticket31477 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features (tests): - - Add integration tests to make sure that practracker gives the outputs - we expect. Closes ticket 31477. diff --git a/changes/ticket31529 b/changes/ticket31529 deleted file mode 100644 index 84f982214c..0000000000 --- a/changes/ticket31529 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (debugging): - - Log a nonfatal assertion failure if we encounter a configuration - line whose command is "CLEAR" but which has a nonempty value. - This should be impossible, according to the rules of our - configuration line parsing. Closes ticket 31529. diff --git a/changes/ticket31532 b/changes/ticket31532 deleted file mode 100644 index 95bcbc517c..0000000000 --- a/changes/ticket31532 +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring: - - Use the ptrdiff_t type consistently for expressing variable offsets and - pointer differences. Previously we incorrectly (but harmlessly) used - int and sometimes off_t for these cases. Closes ticket 31532. diff --git a/changes/ticket31545 b/changes/ticket31545 deleted file mode 100644 index 58921c2ad8..0000000000 --- a/changes/ticket31545 +++ /dev/null @@ -1,5 +0,0 @@ - o Code simplification and refactoring: - - Rewrite format_node_description() and router_get_verbose_nickname() to - use strlcpy() and strlcat(). The previous implementation used memcpy() - and pointer arithmetic, which was error-prone. - Closes ticket 31545. This is CID 1452819. diff --git a/changes/ticket31554 b/changes/ticket31554 deleted file mode 100644 index 73f4159ff3..0000000000 --- a/changes/ticket31554 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (stem tests): - - Change "make test-stem" so it only runs the stem tests that use tor. - This change makes test-stem faster and more reliable. - Closes ticket 31554. diff --git a/changes/ticket31578 b/changes/ticket31578 deleted file mode 100644 index 220efffa63..0000000000 --- a/changes/ticket31578 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (practracker): - - When running check-best-practices, only consider files in the - src subdirectory. Previously we had recursively considered - all subdirectories, which made us get confused by the - temporary directories made by "make distcheck". Fixes bug - 31578; bugfix on 0.4.1.1-alpha. diff --git a/changes/ticket31625 b/changes/ticket31625 deleted file mode 100644 index 822a921e4f..0000000000 --- a/changes/ticket31625 +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring: - - Replace our ad-hoc set of flags for configuration variables and - configuration variable types with fine-grained orthogonal flags - corresponding to the actual behavior we want. Closes ticket 31625. diff --git a/changes/ticket31626 b/changes/ticket31626 deleted file mode 100644 index 443bc1eb87..0000000000 --- a/changes/ticket31626 +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring: - - Move our backend logic for working with configuration and state - files into a lower-level library, since in no longer depends on - any tor-specific functionality. Closes ticket 31626. diff --git a/changes/ticket31637 b/changes/ticket31637 deleted file mode 100644 index b6ffa8b892..0000000000 --- a/changes/ticket31637 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor features (testing): - - Add a script to invoke "tor --dump-config" and "tor --verify-config" - with various configuration options, and see whether tor's resulting - configuration or error messages are what we expect. Use it for - integration testing of our +Option and /Option flags. - Closes ticket 31637. diff --git a/changes/ticket31673 b/changes/ticket31673 deleted file mode 100644 index 3b2bb4a46e..0000000000 --- a/changes/ticket31673 +++ /dev/null @@ -1,3 +0,0 @@ - o New system requirements (build system): - - Do not include the deprecated on Linux or Windows system. - Closes 31673; -- cgit v1.2.3-54-g00ecf From 7cd68b04def1c0256b98248d18680e4e4ed92071 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 16 Sep 2019 12:50:56 -0400 Subject: Fold one more entry into changelog. --- ChangeLog | 3 +++ changes/ticket31678 | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 changes/ticket31678 (limited to 'changes') diff --git a/ChangeLog b/ChangeLog index 01d6c26e1d..8bec28b35a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -219,6 +219,9 @@ Changes in version 0.4.2.1-alpha - 2019-09-?? Fixes bug 30840; bugfix on 0.4.0.1-alpha. - Stop hard-coding the tor master branch name and worktree path in the git scripts. Fixes bug 30841; bugfix on 0.4.0.1-alpha. + - Allow git-push-all.sh to be run from any directory. Previously, + the script only worked if run from an upstream worktree directory. + Closes ticket 31678. o Minor bugfixes (guards): - When tor is missing descriptors for some primary entry guards, diff --git a/changes/ticket31678 b/changes/ticket31678 deleted file mode 100644 index 157f1db7f9..0000000000 --- a/changes/ticket31678 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (git scripts): - - Allow git-push-all.sh to be run from any directory. Previously, the - script only worked if run from an upstream worktree directory. - Closes ticket 31678. -- cgit v1.2.3-54-g00ecf From 1f0848e0b6674e8c8f3379440c91428bf550dddb Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 17 Sep 2019 08:00:24 -0400 Subject: Fold new entries into 0.4.2.1-alpha changelog --- ChangeLog | 9 +++++++++ changes/ticket31687_1 | 4 ---- changes/ticket31687_2 | 5 ----- 3 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 changes/ticket31687_1 delete mode 100644 changes/ticket31687_2 (limited to 'changes') diff --git a/ChangeLog b/ChangeLog index 8bec28b35a..d604af54e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -170,6 +170,9 @@ Changes in version 0.4.2.1-alpha - 2019-09-?? Previously, these compilation settings would make the compiler look for functions that didn't exist. Fixes bug 31552; bugfix on 0.4.1.1-alpha. + - Suppress spurious float-conversion warnings from GCC when calling + floating-point classifier functions on FreeBSD. Fixes part of bug + 31687; bugfix on 0.3.1.5-alpha. o Minor bugfixes (configuration): - Invalid floating-point values in the configuration file are now @@ -208,6 +211,12 @@ Changes in version 0.4.2.1-alpha - 2019-09-?? rather than deleting buffered log lines. Fixes bug 31594; bugfix on 0.2.5.2-alpha. + o Minor bugfixes (FreeBSD, PF-based proxy, IPv6): + - When extracting an IPv6 address from a PF-based proxy, verify + that we are actually configured to receive an IPv6 address, + and log an internal error if not. Fixes part of bug 31687; + bugfix on 0.2.3.4-alpha. + o Minor bugfixes (git hooks): - Remove a duplicate call to practracker from the pre-push hook. The pre-push hook already calls the pre-commit hook, which calls diff --git a/changes/ticket31687_1 b/changes/ticket31687_1 deleted file mode 100644 index 2f4d440974..0000000000 --- a/changes/ticket31687_1 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (compilation): - - Suppress spurious float-conversion warnings from GCC when calling - floating-point classifier functions on FreeBSD. Fixes part of bug - 31687; bugfix on 0.3.1.5-alpha. diff --git a/changes/ticket31687_2 b/changes/ticket31687_2 deleted file mode 100644 index eadc698275..0000000000 --- a/changes/ticket31687_2 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (FreeBSD, PF-based proxy, IPv6): - - When extracting an IPv6 address from a PF-based proxy, verify - that we are actually configured to receive an IPv6 address, - and log an internal error if not. Fixes part of bug 31687; - bugfix on 0.2.3.4-alpha. -- cgit v1.2.3-54-g00ecf From 25af8ada30b84a0df19763bbc226ae209c38a1a0 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 17 Sep 2019 19:26:45 -0400 Subject: Correct the syntax description for the MAPADDRESS command. In 0.4.1.1-alpha I introduced a bug where we would require and ignore a single positional argument. Fixes bug 31772. --- changes/ticket31772 | 4 ++++ src/feature/control/control_cmd.c | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 changes/ticket31772 (limited to 'changes') diff --git a/changes/ticket31772 b/changes/ticket31772 new file mode 100644 index 0000000000..7847b3f746 --- /dev/null +++ b/changes/ticket31772 @@ -0,0 +1,4 @@ + o Minor bugfixes (controller protocol): + - Fix the MAPADDRESS controller command to accept one or more + arguments. Previously, it required two or more arguments, and ignored + the first. Fixes bug 31772; bugfix on 0.4.1.1-alpha. diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c index abb579bd43..e0706ee4c8 100644 --- a/src/feature/control/control_cmd.c +++ b/src/feature/control/control_cmd.c @@ -639,7 +639,9 @@ address_is_invalid_mapaddress_target(const char *addr) } static const control_cmd_syntax_t mapaddress_syntax = { - .max_args=1, + // no positional arguments are expected + .max_args=0, + // an arbitrary number of K=V entries are supported. .accept_keywords=true, }; -- cgit v1.2.3-54-g00ecf From 82ad63ef404c4634ea98352febe70296918df28d Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 18 Sep 2019 08:56:47 -0400 Subject: changes file for 31338 --- changes/ticket31338 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket31338 (limited to 'changes') diff --git a/changes/ticket31338 b/changes/ticket31338 new file mode 100644 index 0000000000..b76add635d --- /dev/null +++ b/changes/ticket31338 @@ -0,0 +1,4 @@ + o Minor bugfixes (best practices tracker): + - When listing overbroad exceptions, do not also list problems, + and do not list insufficiently broad exceptions. Fixes bug 31338; + bugfix on 0.4.2.1-alpha. -- cgit v1.2.3-54-g00ecf From 387cfccee47394adeba8cbf49c130cc9b332b025 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 11 Sep 2019 18:53:16 -0400 Subject: Add a coccinelle script to look for {inc,dec}rements in log_debug We want to forbid this pattern since, unlike the other log_*() macros, log_debug() conditionally evaluates its arguments only if debug-level logging is enabled. Thus, a call to log_debug("%d", x++); will only increment x if debugging logs are enabled, which is probably not what the programmer intended. One bug caused by this pattern was #30628. This script detects log_debug( ) calls with any of E++, E--, ++E, or --E in their arguments, where E is an arbitrary expression. Closes ticket 30743. --- changes/ticket30743 | 7 +++++++ scripts/coccinelle/debugmm.cocci | 29 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 changes/ticket30743 create mode 100644 scripts/coccinelle/debugmm.cocci (limited to 'changes') diff --git a/changes/ticket30743 b/changes/ticket30743 new file mode 100644 index 0000000000..4f029717db --- /dev/null +++ b/changes/ticket30743 @@ -0,0 +1,7 @@ + o Minor features (maintenance scripts): + - Add a coccinelle script to detect bugs caused by incrementing or + decrementing a variable inside a call to log_debug(). Since + log_debug() is a macro whose arguments are conditionally evaluated, it + is usually an error to do this. One such bug was 30628, in which SENDME + cells were miscounted by a decrement operator inside a log_debug() + call. Closes ticket 30743. diff --git a/scripts/coccinelle/debugmm.cocci b/scripts/coccinelle/debugmm.cocci new file mode 100644 index 0000000000..dbd308df33 --- /dev/null +++ b/scripts/coccinelle/debugmm.cocci @@ -0,0 +1,29 @@ +// Look for use of expressions with side-effects inside of debug logs. +// +// This script detects expressions like ++E, --E, E++, and E-- inside of +// calls to log_debug(). +// +// The log_debug() macro exits early if debug logging is not enabled, +// potentially causing problems if its arguments have side-effects. + +@@ +expression E; +@@ +*log_debug(... , <+... --E ...+>, ... ); + + +@@ +expression E; +@@ +*log_debug(... , <+... ++E ...+>, ... ); + +@@ +expression E; +@@ +*log_debug(... , <+... E-- ...+>, ... ); + + +@@ +expression E; +@@ +*log_debug(... , <+... E++ ...+>, ... ); -- cgit v1.2.3-54-g00ecf From 6100378c29072dda5264d9e88993133f484df168 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 9 Sep 2019 15:48:58 -0400 Subject: changes file for microdesc_parse refactoring. --- changes/ticket31675 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket31675 (limited to 'changes') diff --git a/changes/ticket31675 b/changes/ticket31675 new file mode 100644 index 0000000000..2b426948f3 --- /dev/null +++ b/changes/ticket31675 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Refactor the microdescs_parse_from_string() function into smaller + pieces, for better comprehensibility. Closes ticket 31675. -- cgit v1.2.3-54-g00ecf From 3e45260594d3b1c84a88e509f138dab4590903fd Mon Sep 17 00:00:00 2001 From: AmreshVenugopal Date: Tue, 10 Sep 2019 01:48:14 +0530 Subject: fix: Ticket #31589 - The function `decrypt_desc_layer` has a cleaner interface. - `is_superencrypted_layer` changed from `int` -> `bool` [ticket details](https://trac.torproject.org/projects/tor/ticket/31589) add(changes/*): changes file fix(src/features/hs): is_superencrypted changed from `int` -> `bool` fix(changes/ticket31589): header add(changes/ticket31589): subsystem(onion services) to change --- changes/ticket31589 | 2 ++ scripts/maint/practracker/exceptions.txt | 2 +- src/feature/hs/hs_descriptor.c | 21 ++++++++++++--------- src/feature/hs/hs_descriptor.h | 5 ++--- src/test/fuzz/fuzz_hsdescv3.c | 11 ++++++++--- 5 files changed, 25 insertions(+), 16 deletions(-) create mode 100644 changes/ticket31589 (limited to 'changes') diff --git a/changes/ticket31589 b/changes/ticket31589 new file mode 100644 index 0000000000..673ab653e2 --- /dev/null +++ b/changes/ticket31589 @@ -0,0 +1,2 @@ + o Code simplification and refactoring (onion services): + - Interface for function `decrypt_desc_layer` cleaned up. Closes ticket 31589. diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index 4201282bad..44b22c7a24 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -244,7 +244,7 @@ problem function-size /src/feature/hs/hs_common.c:hs_get_responsible_hsdirs() 10 problem function-size /src/feature/hs/hs_config.c:config_service_v3() 107 problem function-size /src/feature/hs/hs_config.c:config_generic_service() 138 problem function-size /src/feature/hs/hs_descriptor.c:desc_encode_v3() 101 -problem function-size /src/feature/hs/hs_descriptor.c:decrypt_desc_layer() 105 +problem function-size /src/feature/hs/hs_descriptor.c:decrypt_desc_layer() 111 problem function-size /src/feature/hs/hs_descriptor.c:decode_introduction_point() 122 problem function-size /src/feature/hs/hs_descriptor.c:desc_decode_superencrypted_v3() 107 problem function-size /src/feature/hs/hs_descriptor.c:desc_decode_encrypted_v3() 107 diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c index a8796c0029..924ab3115e 100644 --- a/src/feature/hs/hs_descriptor.c +++ b/src/feature/hs/hs_descriptor.c @@ -1477,10 +1477,8 @@ decrypt_descriptor_cookie(const hs_descriptor_t *desc, */ MOCK_IMPL(STATIC size_t, decrypt_desc_layer,(const hs_descriptor_t *desc, - const uint8_t *encrypted_blob, - size_t encrypted_blob_size, const uint8_t *descriptor_cookie, - int is_superencrypted_layer, + bool is_superencrypted_layer, char **decrypted_out)) { uint8_t *decrypted = NULL; @@ -1490,6 +1488,12 @@ decrypt_desc_layer,(const hs_descriptor_t *desc, uint8_t mac_key[DIGEST256_LEN], our_mac[DIGEST256_LEN]; const uint8_t *salt, *encrypted, *desc_mac; size_t encrypted_len, result_len = 0; + const uint8_t *encrypted_blob = (is_superencrypted_layer) + ? desc->plaintext_data.superencrypted_blob + : desc->superencrypted_data.encrypted_blob; + size_t encrypted_blob_size = (is_superencrypted_layer) + ? desc->plaintext_data.superencrypted_blob_size + : desc->superencrypted_data.encrypted_blob_size; tor_assert(decrypted_out); tor_assert(desc); @@ -1603,9 +1607,8 @@ desc_decrypt_superencrypted(const hs_descriptor_t *desc, char **decrypted_out) tor_assert(decrypted_out); superencrypted_len = decrypt_desc_layer(desc, - desc->plaintext_data.superencrypted_blob, - desc->plaintext_data.superencrypted_blob_size, - NULL, 1, &superencrypted_plaintext); + NULL, + true, &superencrypted_plaintext); if (!superencrypted_len) { log_warn(LD_REND, "Decrypting superencrypted desc failed."); @@ -1654,9 +1657,9 @@ desc_decrypt_encrypted(const hs_descriptor_t *desc, } encrypted_len = decrypt_desc_layer(desc, - desc->superencrypted_data.encrypted_blob, - desc->superencrypted_data.encrypted_blob_size, - descriptor_cookie, 0, &encrypted_plaintext); + descriptor_cookie, + false, &encrypted_plaintext); + if (!encrypted_len) { goto err; } diff --git a/src/feature/hs/hs_descriptor.h b/src/feature/hs/hs_descriptor.h index dbe0cb1c94..0a843f4f3c 100644 --- a/src/feature/hs/hs_descriptor.h +++ b/src/feature/hs/hs_descriptor.h @@ -276,6 +276,7 @@ void hs_desc_authorized_client_free_(hs_desc_authorized_client_t *client); hs_desc_authorized_client_free_, (client)) hs_desc_authorized_client_t *hs_desc_build_fake_authorized_client(void); + void hs_desc_build_authorized_client(const uint8_t *subcredential, const curve25519_public_key_t * client_auth_pk, @@ -308,10 +309,8 @@ STATIC int desc_sig_is_valid(const char *b64_sig, const char *encoded_desc, size_t encoded_len); MOCK_DECL(STATIC size_t, decrypt_desc_layer,(const hs_descriptor_t *desc, - const uint8_t *encrypted_blob, - size_t encrypted_blob_size, const uint8_t *descriptor_cookie, - int is_superencrypted_layer, + bool is_superencrypted_layer, char **decrypted_out)); #endif /* defined(HS_DESCRIPTOR_PRIVATE) */ diff --git a/src/test/fuzz/fuzz_hsdescv3.c b/src/test/fuzz/fuzz_hsdescv3.c index 2cbd655898..9d4a6dbb55 100644 --- a/src/test/fuzz/fuzz_hsdescv3.c +++ b/src/test/fuzz/fuzz_hsdescv3.c @@ -35,16 +35,21 @@ mock_rsa_ed25519_crosscert_check(const uint8_t *crosscert, static size_t mock_decrypt_desc_layer(const hs_descriptor_t *desc, - const uint8_t *encrypted_blob, - size_t encrypted_blob_size, const uint8_t *descriptor_cookie, - int is_superencrypted_layer, + bool is_superencrypted_layer, char **decrypted_out) { (void)is_superencrypted_layer; (void)desc; (void)descriptor_cookie; const size_t overhead = HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN; + const uint8_t *encrypted_blob = (is_superencrypted_layer) + ? desc->plaintext_data.superencrypted_blob + : desc->superencrypted_data.encrypted_blob; + size_t encrypted_blob_size = (is_superencrypted_layer) + ? desc->plaintext_data.superencrypted_blob_size + : desc->superencrypted_data.encrypted_blob_size; + if (encrypted_blob_size < overhead) return 0; *decrypted_out = tor_memdup_nulterm( -- cgit v1.2.3-54-g00ecf From c7c849bba82f9a47f404882348dd00f22492f310 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 24 Sep 2019 11:29:22 +1000 Subject: configure: Explain --disable-module-dirauth better Explain what the optional Directory Authority module is, and what happens when it is disabled. Fixes bug 31825; bugfix on 0.3.4.1-alpha. --- changes/bug31825 | 3 +++ configure.ac | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/bug31825 (limited to 'changes') diff --git a/changes/bug31825 b/changes/bug31825 new file mode 100644 index 0000000000..fe90acf299 --- /dev/null +++ b/changes/bug31825 @@ -0,0 +1,3 @@ + o Minor bugfixes (modules): + - Explain what the optional Directory Authority module is, and what + happens when it is disabled. Fixes bug 31825; bugfix on 0.3.4.1-alpha. diff --git a/configure.ac b/configure.ac index a639ffaf33..bd12e61671 100644 --- a/configure.ac +++ b/configure.ac @@ -251,7 +251,7 @@ m4_define(MODULES, dirauth) dnl Directory Authority module. AC_ARG_ENABLE([module-dirauth], AS_HELP_STRING([--disable-module-dirauth], - [Do not build tor with the dirauth module]), + [Build tor without the Directory Authority module: tor can not run as an authority]), [], dnl Action if-given AC_DEFINE([HAVE_MODULE_DIRAUTH], [1], [Compile with Directory Authority feature support])) -- cgit v1.2.3-54-g00ecf From 0c07cd24d43a19c02333eb5a031df80ef00c891a Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 24 Sep 2019 15:22:57 +1000 Subject: changes: file for 31839 --- changes/ticket31839 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changes/ticket31839 (limited to 'changes') diff --git a/changes/ticket31839 b/changes/ticket31839 new file mode 100644 index 0000000000..d7da40f530 --- /dev/null +++ b/changes/ticket31839 @@ -0,0 +1,3 @@ + o Documentation: + - Document the signal-safe logging behaviour in the tor man page. Also + add some comments to the relevant functions. Closes ticket 31839. -- cgit v1.2.3-54-g00ecf From b03cb0cc269548f103c2fc3ff611ea3cf90437a5 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 24 Sep 2019 19:35:42 -0400 Subject: Add a changes file about the introduction of doc/HACKING/design. --- changes/ticket31849 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/ticket31849 (limited to 'changes') diff --git a/changes/ticket31849 b/changes/ticket31849 new file mode 100644 index 0000000000..9d12d938c4 --- /dev/null +++ b/changes/ticket31849 @@ -0,0 +1,5 @@ + o Documentation: + - The Tor source code repository now includes a (somewhat dated) + description of Tor's modular architecture, in doc/HACKING/design. + This is based on the old "tor-guts.git" repository, which we are + adopting and superseding. Closes ticket 31849. -- cgit v1.2.3-54-g00ecf From d30a042fa8348028e0bea6f3e46cba1ffbe5adcc Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 25 Sep 2019 16:35:02 +1000 Subject: test: Use SEVERITY_MASK_IDX() to find the LOG_* mask indexes In the unit tests and fuzzers. Fixes bug 31334; bugfix on 0.2.5.2-alpha. --- changes/bug31334 | 4 ++++ src/test/fuzz/fuzzing_common.c | 2 +- src/test/test_logging.c | 2 +- src/test/test_options.c | 6 +++--- src/test/testing_common.c | 4 ++-- 5 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 changes/bug31334 (limited to 'changes') diff --git a/changes/bug31334 b/changes/bug31334 new file mode 100644 index 0000000000..dfc9cc530e --- /dev/null +++ b/changes/bug31334 @@ -0,0 +1,4 @@ + o Code simplification and refactoring: + - Use SEVERITY_MASK_IDX() to find the LOG_* mask indexes in the unit + tests and fuzzers, rather than using hard-coded values. + Closes ticket 31334. diff --git a/src/test/fuzz/fuzzing_common.c b/src/test/fuzz/fuzzing_common.c index 862acb2b35..e269c36b42 100644 --- a/src/test/fuzz/fuzzing_common.c +++ b/src/test/fuzz/fuzzing_common.c @@ -167,7 +167,7 @@ main(int argc, char **argv) memset(&s, 0, sizeof(s)); set_log_severity_config(loglevel, LOG_ERR, &s); /* ALWAYS log bug warnings. */ - s.masks[LOG_WARN-LOG_ERR] |= LD_BUG; + s.masks[SEVERITY_MASK_IDX(LOG_WARN)] |= LD_BUG; add_stream_log(&s, "", fileno(stdout)); } diff --git a/src/test/test_logging.c b/src/test/test_logging.c index bb7018fe1c..203ce64e32 100644 --- a/src/test/test_logging.c +++ b/src/test/test_logging.c @@ -35,7 +35,7 @@ test_get_sigsafe_err_fds(void *arg) set_log_severity_config(LOG_WARN, LOG_ERR, &include_bug); set_log_severity_config(LOG_WARN, LOG_ERR, &no_bug); - no_bug.masks[0] &= ~(LD_BUG|LD_GENERAL); + no_bug.masks[SEVERITY_MASK_IDX(LOG_ERR)] &= ~(LD_BUG|LD_GENERAL); set_log_severity_config(LOG_INFO, LOG_NOTICE, &no_bug2); /* Add some logs; make sure the output is as expected. */ diff --git a/src/test/test_options.c b/src/test/test_options.c index 0747a2e062..b3654ede7d 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -54,9 +54,9 @@ setup_log_callback(void) { log_severity_list_t lst; memset(&lst, 0, sizeof(lst)); - lst.masks[LOG_ERR - LOG_ERR] = ~0; - lst.masks[LOG_WARN - LOG_ERR] = ~0; - lst.masks[LOG_NOTICE - LOG_ERR] = ~0; + lst.masks[SEVERITY_MASK_IDX(LOG_ERR)] = ~0; + lst.masks[SEVERITY_MASK_IDX(LOG_WARN)] = ~0; + lst.masks[SEVERITY_MASK_IDX(LOG_NOTICE)] = ~0; add_callback_log(&lst, log_cback); mark_logs_temp(); } diff --git a/src/test/testing_common.c b/src/test/testing_common.c index ad22898ce5..9e7d83dcdc 100644 --- a/src/test/testing_common.c +++ b/src/test/testing_common.c @@ -295,7 +295,7 @@ main(int c, const char **v) memset(&s, 0, sizeof(s)); set_log_severity_config(loglevel, LOG_ERR, &s); /* ALWAYS log bug warnings. */ - s.masks[LOG_WARN-LOG_ERR] |= LD_BUG; + s.masks[SEVERITY_MASK_IDX(LOG_WARN)] |= LD_BUG; add_stream_log(&s, "", fileno(stdout)); } { @@ -303,7 +303,7 @@ main(int c, const char **v) log_severity_list_t s; memset(&s, 0, sizeof(s)); set_log_severity_config(LOG_ERR, LOG_ERR, &s); - s.masks[LOG_WARN-LOG_ERR] |= LD_BUG; + s.masks[SEVERITY_MASK_IDX(LOG_WARN)] |= LD_BUG; add_callback_log(&s, log_callback_failure); } flush_log_messages_from_startup(); -- cgit v1.2.3-54-g00ecf From c9c046c365f10f5cbffada921931413edc690dbe Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 26 Sep 2019 12:09:56 +1000 Subject: changes: file for 31614 --- changes/bug31614 | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 changes/bug31614 (limited to 'changes') diff --git a/changes/bug31614 b/changes/bug31614 new file mode 100644 index 0000000000..c425a9fcd4 --- /dev/null +++ b/changes/bug31614 @@ -0,0 +1,9 @@ + o Minor bugfixes (logging): + - Disable backtrace signal handlers when shutting down tor. + Fixes bug 31614; bugfix on 0.2.5.2-alpha. + - Add a missing check for HAVE_PTHREAD_H, because the backtrace code uses + mutexes. Fixes bug 31614; bugfix on 0.2.5.2-alpha. + o Documentation: + - Explain why we can't destroy the backtrace buffer mutex. Explain why + we don't need to destroy the log mutex. + Closes ticket 31736. -- cgit v1.2.3-54-g00ecf From d1eab05834566f998721d3a16107767885711c57 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 20 Sep 2019 11:27:05 +1000 Subject: lock: Avoid some undefined behaviour when freeing mutexes. Fixes bug 31736; bugfix on 0.0.7. --- changes/bug31736 | 3 +++ src/app/config/config.c | 6 +++++- src/feature/relay/router.c | 4 ++++ src/lib/crypt_ops/crypto_openssl_mgt.c | 4 ++++ src/lib/lock/compat_mutex.c | 10 +++++++++- src/lib/lock/compat_mutex_pthreads.c | 16 +++++++++++++++- src/lib/thread/compat_threads.c | 10 +++++++++- src/lib/thread/threads.h | 12 +++++++++++- 8 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 changes/bug31736 (limited to 'changes') diff --git a/changes/bug31736 b/changes/bug31736 new file mode 100644 index 0000000000..beb09e5069 --- /dev/null +++ b/changes/bug31736 @@ -0,0 +1,3 @@ + o Minor bugfixes (multithreading): + - Avoid some undefined behaviour when freeing mutexes. + Fixes bug 31736; bugfix on 0.0.7. diff --git a/src/app/config/config.c b/src/app/config/config.c index 0b1b758d96..2416da2b26 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -1187,7 +1187,11 @@ init_protocol_warning_severity_level(void) static void cleanup_protocol_warning_severity_level(void) { - atomic_counter_destroy(&protocol_warning_severity_level); + /* Destroying a locked mutex is undefined behaviour. This mutex may be + * locked, because multiple threads can access it. But we need to destroy + * it, otherwise re-initialisation will trigger undefined behaviour. + * See #31735 for details. */ + atomic_counter_destroy(&protocol_warning_severity_level); } /** List of default directory authorities */ diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index dad2c6a50f..af47e79d28 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -3072,6 +3072,10 @@ router_free_all(void) crypto_pk_free(server_identitykey); crypto_pk_free(client_identitykey); + /* Destroying a locked mutex is undefined behaviour. This mutex may be + * locked, because multiple threads can access it. But we need to destroy + * it, otherwise re-initialisation will trigger undefined behaviour. + * See #31735 for details. */ tor_mutex_free(key_lock); routerinfo_free(desc_routerinfo); extrainfo_free(desc_extrainfo); diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.c b/src/lib/crypt_ops/crypto_openssl_mgt.c index c97815f9a4..a245ef3810 100644 --- a/src/lib/crypt_ops/crypto_openssl_mgt.c +++ b/src/lib/crypt_ops/crypto_openssl_mgt.c @@ -176,6 +176,10 @@ crypto_openssl_free_all(void) tor_free(crypto_openssl_version_str); tor_free(crypto_openssl_header_version_str); + /* Destroying a locked mutex is undefined behaviour. This mutex may be + * locked, because multiple threads can access it. But we need to destroy + * it, otherwise re-initialisation will trigger undefined behaviour. + * See #31735 for details. */ #ifndef NEW_THREAD_API if (n_openssl_mutexes_) { int n = n_openssl_mutexes_; diff --git a/src/lib/lock/compat_mutex.c b/src/lib/lock/compat_mutex.c index 4ad5929715..670bd0174c 100644 --- a/src/lib/lock/compat_mutex.c +++ b/src/lib/lock/compat_mutex.c @@ -29,7 +29,15 @@ tor_mutex_new_nonrecursive(void) tor_mutex_init_nonrecursive(m); return m; } -/** Release all storage and system resources held by m. */ +/** Release all storage and system resources held by m. + * + * Destroying a locked mutex is undefined behaviour. Global mutexes may be + * locked when they are passed to this function, because multiple threads can + * still access them. So we can either: + * - destroy on shutdown, and re-initialise when tor re-initialises, or + * - skip destroying and re-initialisation, using a sentinel variable. + * See #31735 for details. + */ void tor_mutex_free_(tor_mutex_t *m) { diff --git a/src/lib/lock/compat_mutex_pthreads.c b/src/lib/lock/compat_mutex_pthreads.c index ee5f520cd0..f82ad9f0e8 100644 --- a/src/lib/lock/compat_mutex_pthreads.c +++ b/src/lib/lock/compat_mutex_pthreads.c @@ -88,12 +88,26 @@ tor_mutex_release(tor_mutex_t *m) } /** Clean up the mutex m so that it no longer uses any system * resources. Does not free m. This function must only be called on - * mutexes from tor_mutex_init(). */ + * mutexes from tor_mutex_init(). + * + * Destroying a locked mutex is undefined behaviour. Global mutexes may be + * locked when they are passed to this function, because multiple threads can + * still access them. So we can either: + * - destroy on shutdown, and re-initialise when tor re-initialises, or + * - skip destroying and re-initialisation, using a sentinel variable. + * See #31735 for details. + */ void tor_mutex_uninit(tor_mutex_t *m) { int err; raw_assert(m); + /* If the mutex is already locked, wait until after it is unlocked to destroy + * it. Locking and releasing the mutex makes undefined behaviour less likely, + * but does not prevent it. Another thread can lock the mutex between release + * and destroy. */ + tor_mutex_acquire(m); + tor_mutex_release(m); err = pthread_mutex_destroy(&m->mutex); if (PREDICT_UNLIKELY(err)) { // LCOV_EXCL_START diff --git a/src/lib/thread/compat_threads.c b/src/lib/thread/compat_threads.c index 94ab021c52..16cece6125 100644 --- a/src/lib/thread/compat_threads.c +++ b/src/lib/thread/compat_threads.c @@ -65,7 +65,15 @@ atomic_counter_init(atomic_counter_t *counter) memset(counter, 0, sizeof(*counter)); tor_mutex_init_nonrecursive(&counter->mutex); } -/** Clean up all resources held by an atomic counter. */ +/** Clean up all resources held by an atomic counter. + * + * Destroying a locked mutex is undefined behaviour. Global mutexes may be + * locked when they are passed to this function, because multiple threads can + * still access them. So we can either: + * - destroy on shutdown, and re-initialise when tor re-initialises, or + * - skip destroying and re-initialisation, using a sentinel variable. + * See #31735 for details. + */ void atomic_counter_destroy(atomic_counter_t *counter) { diff --git a/src/lib/thread/threads.h b/src/lib/thread/threads.h index ecf60641b5..de3da6a585 100644 --- a/src/lib/thread/threads.h +++ b/src/lib/thread/threads.h @@ -131,7 +131,17 @@ atomic_counter_init(atomic_counter_t *counter) { atomic_init(&counter->val, 0); } -/** Clean up all resources held by an atomic counter. */ +/** Clean up all resources held by an atomic counter. + * + * This usage note applies to the compat_threads implementation of + * atomic_counter_destroy(): + * Destroying a locked mutex is undefined behaviour. Global mutexes may be + * locked when they are passed to this function, because multiple threads can + * still access them. So we can either: + * - destroy on shutdown, and re-initialise when tor re-initialises, or + * - skip destroying and re-initialisation, using a sentinel variable. + * See #31735 for details. + */ static inline void atomic_counter_destroy(atomic_counter_t *counter) { -- cgit v1.2.3-54-g00ecf From 3283fd7e79913e25cd5e626d6bb3a12a05b2f3fc Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 18 Sep 2019 11:06:54 -0400 Subject: Changes file for 31759 and 31779 --- changes/ticket31759 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/ticket31759 (limited to 'changes') diff --git a/changes/ticket31759 b/changes/ticket31759 new file mode 100644 index 0000000000..f7428f711c --- /dev/null +++ b/changes/ticket31759 @@ -0,0 +1,5 @@ + o Minor features (auto-formatting scripts): + - When annotating C macros, never generate a line that our check-spaces + script would reject. Closes ticket 31759. + - When annotating C macros, try to remove cases of double-negation. + Closes ticket 31779. -- cgit v1.2.3-54-g00ecf From 2420c8c9366e498dfaf3b4b6389ece9dc27ca537 Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 30 Sep 2019 14:54:56 +1000 Subject: test: Avoid a map_anon_nofork test failure on SunOS This test failure happened due to a signed/unsigned integer comparison. This bug occurred on SunOS, it may also occur on other systems that use signed char as the default. (And cast 1-byte integer constants to an unsigned integer.) Fixes bug 31897; bugfix on 0.4.1.1-alpha. --- changes/bug31897 | 3 +++ src/test/test_util.c | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 changes/bug31897 (limited to 'changes') diff --git a/changes/bug31897 b/changes/bug31897 new file mode 100644 index 0000000000..81c63e704e --- /dev/null +++ b/changes/bug31897 @@ -0,0 +1,3 @@ + o Minor bugfixes (tests, SunOS): + - Avoid a map_anon_nofork test failure due to a signed/unsigned integer + comparison. Fixes bug 31897; bugfix on 0.4.1.1-alpha. diff --git a/src/test/test_util.c b/src/test/test_util.c index 2faadd4e19..6ecff6f1c3 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -6182,6 +6182,7 @@ test_util_map_anon_nofork(void *arg) * crash, or send zero. */ char *ptr = NULL; + const char TEST_VALUE = 0xd0; size_t sz = 16384; int pipefd[2] = {-1, -1}; unsigned inherit=0; @@ -6189,7 +6190,7 @@ test_util_map_anon_nofork(void *arg) tor_munmap_anonymous(ptr, sz); ptr = tor_mmap_anonymous(sz, ANONMAP_NOINHERIT, &inherit); tt_ptr_op(ptr, OP_NE, 0); - memset(ptr, 0xd0, sz); + memset(ptr, TEST_VALUE, sz); tt_int_op(0, OP_EQ, pipe(pipefd)); pid_t child = fork(); @@ -6220,7 +6221,7 @@ test_util_map_anon_nofork(void *arg) // noinherit isn't implemented. tt_int_op(inherit, OP_EQ, INHERIT_RES_KEEP); tt_int_op((int)r, OP_EQ, 1); // child should send us a byte. - tt_int_op(buf[0], OP_EQ, 0xd0); // that byte should what we set it to. + tt_int_op(buf[0], OP_EQ, TEST_VALUE); // that byte should be TEST_VALUE. } int ws; -- cgit v1.2.3-54-g00ecf From db329522ef6f0d0971111cbd07f35d54e0c7eced Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 26 Sep 2019 13:37:06 +1000 Subject: log: When initialising log domain masks, only set known log domains And add a runtime test that checks for unknown domains and flags. Fixes bug 31854; bugfix on 0.2.1.1-alpha. --- changes/bug31854 | 3 +++ src/lib/log/log.c | 12 ++++++++---- src/test/test_options.c | 6 +++--- 3 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 changes/bug31854 (limited to 'changes') diff --git a/changes/bug31854 b/changes/bug31854 new file mode 100644 index 0000000000..692a192fd9 --- /dev/null +++ b/changes/bug31854 @@ -0,0 +1,3 @@ + o Minor bugfixes (logging): + - When initialising log domain masks, only set known log domains. + Fixes bug 31854; bugfix on 0.2.1.1-alpha. diff --git a/src/lib/log/log.c b/src/lib/log/log.c index db4f154418..7c18bea0d9 100644 --- a/src/lib/log/log.c +++ b/src/lib/log/log.c @@ -628,6 +628,10 @@ void tor_log(int severity, log_domain_mask_t domain, const char *format, ...) { va_list ap; + + /* check that domain is composed of known domains and flags */ + raw_assert((domain & (LD_ALL_DOMAINS|LD_ALL_FLAGS)) == domain); + if (severity > log_global_min_severity_) return; va_start(ap,format); @@ -927,7 +931,7 @@ set_log_severity_config(int loglevelMin, int loglevelMax, raw_assert(loglevelMax >= LOG_ERR && loglevelMax <= LOG_DEBUG); memset(severity_out, 0, sizeof(log_severity_list_t)); for (i = loglevelMin; i >= loglevelMax; --i) { - severity_out->masks[SEVERITY_MASK_IDX(i)] = ~0u; + severity_out->masks[SEVERITY_MASK_IDX(i)] = LD_ALL_DOMAINS; } } @@ -1421,7 +1425,7 @@ parse_log_severity_config(const char **cfg_ptr, const char *dash, *space; char *sev_lo, *sev_hi; int low, high, i; - log_domain_mask_t domains = ~0u; + log_domain_mask_t domains = LD_ALL_DOMAINS; if (*cfg == '[') { int err = 0; @@ -1439,7 +1443,7 @@ parse_log_severity_config(const char **cfg_ptr, tor_free(domains_str); SMARTLIST_FOREACH_BEGIN(domains_list, const char *, domain) { if (!strcmp(domain, "*")) { - domains = ~0u; + domains = LD_ALL_DOMAINS; } else { log_domain_mask_t d; int negate=0; @@ -1535,7 +1539,7 @@ switch_logs_debug(void) LOCK_LOGS(); for (lf = logfiles; lf; lf=lf->next) { for (i = LOG_DEBUG; i >= LOG_ERR; --i) - lf->severities->masks[SEVERITY_MASK_IDX(i)] = ~0u; + lf->severities->masks[SEVERITY_MASK_IDX(i)] = LD_ALL_DOMAINS; } log_global_min_severity_ = get_min_log_level(); UNLOCK_LOGS(); diff --git a/src/test/test_options.c b/src/test/test_options.c index b3654ede7d..9eb5a43924 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -54,9 +54,9 @@ setup_log_callback(void) { log_severity_list_t lst; memset(&lst, 0, sizeof(lst)); - lst.masks[SEVERITY_MASK_IDX(LOG_ERR)] = ~0; - lst.masks[SEVERITY_MASK_IDX(LOG_WARN)] = ~0; - lst.masks[SEVERITY_MASK_IDX(LOG_NOTICE)] = ~0; + lst.masks[SEVERITY_MASK_IDX(LOG_ERR)] = LD_ALL_DOMAINS; + lst.masks[SEVERITY_MASK_IDX(LOG_WARN)] = LD_ALL_DOMAINS; + lst.masks[SEVERITY_MASK_IDX(LOG_NOTICE)] = LD_ALL_DOMAINS; add_callback_log(&lst, log_cback); mark_logs_temp(); } -- cgit v1.2.3-54-g00ecf From c23986246b970bd01d887fa151a5312a6dc7db04 Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 30 Sep 2019 23:12:54 +1000 Subject: err: Always lock the backtrace buffer before it is used Fixes bug 31734; bugfix on 0.2.5.3-alpha. --- changes/bug31734 | 3 +++ src/lib/err/backtrace.c | 47 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 changes/bug31734 (limited to 'changes') diff --git a/changes/bug31734 b/changes/bug31734 new file mode 100644 index 0000000000..ce989ea5db --- /dev/null +++ b/changes/bug31734 @@ -0,0 +1,3 @@ + o Minor bugfixes (error handling): + - Always lock the backtrace buffer before it is used. + Fixes bug 31734; bugfix on 0.2.5.3-alpha. diff --git a/src/lib/err/backtrace.c b/src/lib/err/backtrace.c index 8bc7e6965c..4e881b979e 100644 --- a/src/lib/err/backtrace.c +++ b/src/lib/err/backtrace.c @@ -52,6 +52,8 @@ #include #endif +#include "lib/cc/ctassert.h" + #define EXPOSE_CLEAN_BACKTRACE #include "lib/err/backtrace.h" #include "lib/err/torerr.h" @@ -73,15 +75,40 @@ static char bt_version[128] = ""; #ifdef USE_BACKTRACE + /** Largest stack depth to try to dump. */ #define MAX_DEPTH 256 -/** Static allocation of stack to dump. This is static so we avoid stack - * pressure. */ -static void *cb_buf[MAX_DEPTH]; +/** The size of the callback buffer, so we can clear it in unlock_cb_buf(). */ +#define SIZEOF_CB_BUF (MAX_DEPTH * sizeof(void *)) /** Protects cb_buf from concurrent access. Pthreads, since this code * is Unix-only, and since this code needs to be lowest-level. */ static pthread_mutex_t cb_buf_mutex = PTHREAD_MUTEX_INITIALIZER; +/** Lock and return a static stack pointer buffer that can hold up to + * MAX_DEPTH function pointers. */ +static void * +lock_cb_buf(void) +{ + /* Lock the mutex first, before even declaring the buffer. */ + pthread_mutex_lock(&cb_buf_mutex); + + /** Static allocation of stack to dump. This is static so we avoid stack + * pressure. */ + static void *cb_buf[MAX_DEPTH]; + CTASSERT(SIZEOF_CB_BUF == sizeof(cb_buf)); + memset(cb_buf, 0, SIZEOF_CB_BUF); + + return cb_buf; +} + +/** Unlock the static stack pointer buffer. */ +static void +unlock_cb_buf(void *cb_buf) +{ + memset(cb_buf, 0, SIZEOF_CB_BUF); + pthread_mutex_unlock(&cb_buf_mutex); +} + /** Change a stacktrace in stack of depth depth so that it will * log the correct function from which a signal was received with context * ctx. (When we get a signal, the current function will not have @@ -123,7 +150,7 @@ log_backtrace_impl(int severity, log_domain_mask_t domain, const char *msg, char **symbols; size_t i; - pthread_mutex_lock(&cb_buf_mutex); + void *cb_buf = lock_cb_buf(); depth = backtrace(cb_buf, MAX_DEPTH); symbols = backtrace_symbols(cb_buf, (int)depth); @@ -141,7 +168,7 @@ log_backtrace_impl(int severity, log_domain_mask_t domain, const char *msg, raw_free(symbols); done: - pthread_mutex_unlock(&cb_buf_mutex); + unlock_cb_buf(cb_buf); } static void crash_handler(int sig, siginfo_t *si, void *ctx_) @@ -157,6 +184,8 @@ crash_handler(int sig, siginfo_t *si, void *ctx_) int n_fds, i; const int *fds = NULL; + void *cb_buf = lock_cb_buf(); + (void) si; depth = backtrace(cb_buf, MAX_DEPTH); @@ -173,6 +202,8 @@ crash_handler(int sig, siginfo_t *si, void *ctx_) for (i=0; i < n_fds; ++i) backtrace_symbols_fd(cb_buf, (int)depth, fds[i]); + unlock_cb_buf(cb_buf); + tor_raw_abort_(); } @@ -184,11 +215,15 @@ dump_stack_symbols_to_error_fds(void) const int *fds = NULL; size_t depth; + void *cb_buf = lock_cb_buf(); + depth = backtrace(cb_buf, MAX_DEPTH); n_fds = tor_log_get_sigsafe_err_fds(&fds); for (i=0; i < n_fds; ++i) backtrace_symbols_fd(cb_buf, (int)depth, fds[i]); + + unlock_cb_buf(cb_buf); } /* The signals that we want our backtrace handler to trap */ @@ -222,10 +257,12 @@ install_bt_handler(void) * libc has pre-loaded the symbols we need to dump things, so that later * reads won't be denied by the sandbox code */ char **symbols; + void *cb_buf = lock_cb_buf(); size_t depth = backtrace(cb_buf, MAX_DEPTH); symbols = backtrace_symbols(cb_buf, (int) depth); if (symbols) raw_free(symbols); + unlock_cb_buf(cb_buf); } return rv; -- cgit v1.2.3-54-g00ecf From 6581f3e2faf412357212b2ee2cec0db5410d3761 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 30 Sep 2019 14:50:57 -0400 Subject: Fix the documentation for GuardLifetime. --- changes/ticket31189 | 3 +++ doc/tor.1.txt | 7 +++---- 2 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 changes/ticket31189 (limited to 'changes') diff --git a/changes/ticket31189 b/changes/ticket31189 new file mode 100644 index 0000000000..318941c794 --- /dev/null +++ b/changes/ticket31189 @@ -0,0 +1,3 @@ + o Documentation: + - Correct the description of "GuardLifetime". Fixes bug 31189; bugfix on + 0.3.0.1-alpha. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 21b482802e..98ef7c7334 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -1395,10 +1395,9 @@ The following options are useful only for clients (that is, if default to 3 if the consensus parameter isn't set. (Default: 0) [[GuardLifetime]] **GuardLifetime** __N__ **days**|**weeks**|**months**:: - If nonzero, and UseEntryGuards is set, minimum time to keep a guard before - picking a new one. If zero, we use the GuardLifetime parameter from the - consensus directory. No value here may be less than 1 month or greater - than 5 years; out-of-range values are clamped. (Default: 0) + If UseEntryGuards is set, minimum time to keep a guard on our guard list + before picking a new one. If less than one day, we use defaults from the + consensus directory. (Default: 0) [[SafeSocks]] **SafeSocks** **0**|**1**:: When this option is enabled, Tor will reject application connections that -- cgit v1.2.3-54-g00ecf From e8e42f4af97190d5df0b5fa1895f74194650df0b Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 1 Oct 2019 13:40:04 +0300 Subject: Help users who try to use v2 client auth in v3 onions. --- changes/bug28966 | 4 ++++ src/feature/hs/hs_config.c | 10 ++++++++++ 2 files changed, 14 insertions(+) create mode 100644 changes/bug28966 (limited to 'changes') diff --git a/changes/bug28966 b/changes/bug28966 new file mode 100644 index 0000000000..61123a21eb --- /dev/null +++ b/changes/bug28966 @@ -0,0 +1,4 @@ + o Minor features (onion services v3): + - Assist users who try to setup v2 client authorization in v3 onion + services by pointing them to the right documentation. Closes ticket + 28966. diff --git a/src/feature/hs/hs_config.c b/src/feature/hs/hs_config.c index 7424d7d3ce..3b6caaec6a 100644 --- a/src/feature/hs/hs_config.c +++ b/src/feature/hs/hs_config.c @@ -253,6 +253,16 @@ config_has_invalid_options(const config_line_t *line_, "version %" PRIu32 " of service in %s", opt, service->config.version, service->config.directory_path); + + if (!strcasecmp(line->key, "HiddenServiceAuthorizeClient")) { + /* Special case this v2 option so that we can offer alternatives. + * If more such special cases appear, it would be good to + * generalize the exception mechanism here. */ + log_warn(LD_CONFIG, "For v3 onion service client authorization, " + "please read the 'CLIENT AUTHORIZATION' section in the " + "manual."); + } + ret = 1; /* Continue the loop so we can find all possible options. */ continue; -- cgit v1.2.3-54-g00ecf From 2b825a1a2e6e79fa71b0e038241d2107aaf30d4b Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 1 Oct 2019 12:55:42 -0400 Subject: Fix a crash bug in max_u16_in_sl() The documentation for this function says that the smartlist can contain NULLs, but the code only handled NULLs if they were at the start of the list. We didn't notice this for a long time, because when Tor is run normally, the sequence of msg_id_t is densely packed, and so this list (mapping msg_id_t to channel_id_t) contains no NULL elements. We could only run into this bug: * when Tor was running in embedded mode, and starting more than once. * when Tor ran first with more pubsub messages enabled, and then later with fewer. * When the second run (the one with fewer enabled pubsub messages) had at least some messages enabled, and those messages were not the ones with numerically highest msg_id_t values. Fixes bug 31898; bugfix on 47de9c7b0a828de7fb8129413db70bc4e4ecac6d in 0.4.1.1-alpha. --- changes/bug31898 | 4 ++++ src/lib/dispatch/dispatch_new.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 changes/bug31898 (limited to 'changes') diff --git a/changes/bug31898 b/changes/bug31898 new file mode 100644 index 0000000000..6f3e0a5465 --- /dev/null +++ b/changes/bug31898 @@ -0,0 +1,4 @@ + o Major bugfixes (embedded Tor): + - Avoid a possible crash when restarting Tor in embedded mode and + enabling a different set of publish/subscribe messages. Fixes bug + 31898; bugfix on 0.4.1.1-alpha. diff --git a/src/lib/dispatch/dispatch_new.c b/src/lib/dispatch/dispatch_new.c index 4467813064..d8e59d610a 100644 --- a/src/lib/dispatch/dispatch_new.c +++ b/src/lib/dispatch/dispatch_new.c @@ -34,7 +34,7 @@ max_in_u16_sl(const smartlist_t *sl, int dflt) SMARTLIST_FOREACH_BEGIN(sl, uint16_t *, u) { if (!maxptr) maxptr = u; - else if (*u > *maxptr) + else if (u && *u > *maxptr) maxptr = u; } SMARTLIST_FOREACH_END(u); -- cgit v1.2.3-54-g00ecf From 3d17fafa04baf23d124edf56560abf3b19ad4425 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 6 Aug 2019 00:18:41 +1000 Subject: control/control: Refactor some error handling code Split some protocol error handling out of connection_control_process_inbuf(). This refactor reduces the size of a practracker exception. Closes 31840. --- changes/ticket31840 | 3 ++ scripts/maint/practracker/exceptions.txt | 2 +- src/feature/control/control.c | 79 ++++++++++++++++++++++---------- 3 files changed, 59 insertions(+), 25 deletions(-) create mode 100644 changes/ticket31840 (limited to 'changes') diff --git a/changes/ticket31840 b/changes/ticket31840 new file mode 100644 index 0000000000..c75c5629f9 --- /dev/null +++ b/changes/ticket31840 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Refactor connection_control_process_inbuf() to reduce the size of a + practracker exception. Closes ticket 31840. diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index 2e676d9045..88b34b21f6 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -186,7 +186,7 @@ problem file-size /src/feature/client/entrynodes.h 639 problem function-size /src/feature/client/transports.c:handle_proxy_line() 108 problem function-size /src/feature/client/transports.c:parse_method_line_helper() 110 problem function-size /src/feature/client/transports.c:create_managed_proxy_environment() 109 -problem function-size /src/feature/control/control.c:connection_control_process_inbuf() 136 +problem function-size /src/feature/control/control.c:connection_control_process_inbuf() 113 problem function-size /src/feature/control/control_auth.c:handle_control_authenticate() 186 problem function-size /src/feature/control/control_cmd.c:handle_control_extendcircuit() 150 problem function-size /src/feature/control/control_cmd.c:handle_control_add_onion() 256 diff --git a/src/feature/control/control.c b/src/feature/control/control.c index 436bf423cf..d6581808c0 100644 --- a/src/feature/control/control.c +++ b/src/feature/control/control.c @@ -339,6 +339,60 @@ static const char CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG[] = "\n" "\n"; +/** Return an error on a control connection that tried to use the v0 protocol. + */ +static void +control_send_v0_reject(control_connection_t *conn) +{ + size_t body_len; + char buf[128]; + set_uint16(buf+2, htons(0x0000)); /* type == error */ + set_uint16(buf+4, htons(0x0001)); /* code == internal error */ + strlcpy(buf+6, "The v0 control protocol is not supported by Tor 0.1.2.17 " + "and later; upgrade your controller.", + sizeof(buf)-6); + body_len = 2+strlen(buf+6)+2; /* code, msg, nul. */ + set_uint16(buf+0, htons(body_len)); + connection_buf_add(buf, 4+body_len, TO_CONN(conn)); + + connection_mark_and_flush(TO_CONN(conn)); +} + +/** Return an error on a control connection that tried to use HTTP. + */ +static void +control_send_http_reject(control_connection_t *conn) +{ + connection_write_str_to_buf(CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG, conn); + log_notice(LD_CONTROL, "Received HTTP request on ControlPort"); + connection_mark_and_flush(TO_CONN(conn)); +} + +/** Check if a control connection has tried to use a known invalid protocol. + * If it has, then: + * - send a reject response, + * - log a notice-level message, and + * - return false. */ +static bool +control_protocol_is_valid(control_connection_t *conn) +{ + /* Detect v0 commands and send a "no more v0" message. */ + if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && + peek_connection_has_control0_command(TO_CONN(conn))) { + control_send_v0_reject(conn); + return 0; + } + + /* If the user has the HTTP proxy port and the control port confused. */ + if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && + peek_connection_has_http_command(TO_CONN(conn))) { + control_send_http_reject(conn); + return 0; + } + + return 1; +} + /** Called when data has arrived on a v1 control connection: Try to fetch * commands from conn->inbuf, and execute them. */ @@ -359,30 +413,7 @@ connection_control_process_inbuf(control_connection_t *conn) conn->incoming_cmd_cur_len = 0; } - if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && - peek_connection_has_control0_command(TO_CONN(conn))) { - /* Detect v0 commands and send a "no more v0" message. */ - size_t body_len; - char buf[128]; - set_uint16(buf+2, htons(0x0000)); /* type == error */ - set_uint16(buf+4, htons(0x0001)); /* code == internal error */ - strlcpy(buf+6, "The v0 control protocol is not supported by Tor 0.1.2.17 " - "and later; upgrade your controller.", - sizeof(buf)-6); - body_len = 2+strlen(buf+6)+2; /* code, msg, nul. */ - set_uint16(buf+0, htons(body_len)); - connection_buf_add(buf, 4+body_len, TO_CONN(conn)); - - connection_mark_and_flush(TO_CONN(conn)); - return 0; - } - - /* If the user has the HTTP proxy port and the control port confused. */ - if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && - peek_connection_has_http_command(TO_CONN(conn))) { - connection_write_str_to_buf(CONTROLPORT_IS_NOT_AN_HTTP_PROXY_MSG, conn); - log_notice(LD_CONTROL, "Received HTTP request on ControlPort"); - connection_mark_and_flush(TO_CONN(conn)); + if (!control_protocol_is_valid(conn)) { return 0; } -- cgit v1.2.3-54-g00ecf From f0993d3831b6132e342fb192820fc04902c98b38 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 3 Oct 2019 16:31:20 +1000 Subject: configure: Give a more useful message when pkg-config fails When pkg-config is not installed, or a library that depends on pkg-config is not found, tell the user what to do to fix the problem. Fixes bug 31922; bugfix on 0.3.1.1-alpha. --- changes/bug31922 | 4 ++++ configure.ac | 19 +++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 changes/bug31922 (limited to 'changes') diff --git a/changes/bug31922 b/changes/bug31922 new file mode 100644 index 0000000000..e6f31ce66a --- /dev/null +++ b/changes/bug31922 @@ -0,0 +1,4 @@ + o Minor bugfixes (configuration): + - When pkg-config is not installed, or a library that depends on + pkg-config is not found, tell the user what to do to fix the + problem. Fixes bug 31922; bugfix on 0.3.1.1-alpha. diff --git a/configure.ac b/configure.ac index bd12e61671..dbcb51d47f 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,13 @@ AC_USE_SYSTEM_EXTENSIONS AC_CANONICAL_HOST PKG_PROG_PKG_CONFIG +if test "x$PKG_CONFIG" = "x" ; then + pkg_config_user_action="install pkg-config, and check the PKG_CONFIG_PATH environment variable." + AC_MSG_NOTICE([Some libraries need pkg-config, including systemd, nss, lzma, zstd, and custom mallocs.]) + AC_MSG_NOTICE([To use those libraries, $pkg_config_user_action]) +else + pkg_config_user_action="check the PKG_CONFIG_PATH environment variable." +fi AC_ARG_ENABLE(openbsd-malloc, AS_HELP_STRING(--enable-openbsd-malloc, [use malloc code from OpenBSD. Linux only. Deprecated: see --with-malloc])) @@ -166,7 +173,7 @@ AC_SUBST(TOR_SYSTEMD_CFLAGS) AC_SUBST(TOR_SYSTEMD_LIBS) if test "x$enable_systemd" = "xyes" -a "x$have_systemd" != "xyes" ; then - AC_MSG_ERROR([Explicitly requested systemd support, but systemd not found]) + AC_MSG_ERROR([Explicitly requested systemd support, but systemd not found, $pkg_config_user_action]) fi case "$host" in @@ -870,7 +877,7 @@ if test "x$enable_nss" = "xyes"; then PKG_CHECK_MODULES(NSS, [nss], [have_nss=yes], - [have_nss=no; AC_MSG_ERROR([You asked for NSS but I can't find it.])]) + [have_nss=no; AC_MSG_ERROR([You asked for NSS but I can't find it, $pkg_config_user_action])]) AC_SUBST(NSS_CFLAGS) AC_SUBST(NSS_LIBS) fi @@ -1076,7 +1083,7 @@ else have_lzma=no) if test "x$have_lzma" = "xno" ; then - AC_MSG_WARN([Unable to find liblzma.]) + AC_MSG_WARN([Unable to find liblzma, $pkg_config_user_action]) fi fi @@ -1108,7 +1115,7 @@ else have_zstd=no) if test "x$have_zstd" = "xno" ; then - AC_MSG_WARN([Unable to find libzstd.]) + AC_MSG_WARN([Unable to find libzstd, $pkg_config_user_action]) fi fi @@ -1915,7 +1922,7 @@ AS_CASE([$malloc], have_tcmalloc=no) if test "x$have_tcmalloc" = "xno" ; then - AC_MSG_ERROR([Unable to find tcmalloc requested by --with-malloc.]) + AC_MSG_ERROR([Unable to find tcmalloc requested by --with-malloc, $pkg_config_user_action]) fi CFLAGS="$CFLAGS $TCMALLOC_CFLAGS" @@ -1929,7 +1936,7 @@ AS_CASE([$malloc], have_jemalloc=no) if test "x$have_tcmalloc" = "xno" ; then - AC_MSG_ERROR([Unable to find jemalloc requested by --with-malloc.]) + AC_MSG_ERROR([Unable to find jemalloc requested by --with-malloc, $pkg_config_user_action]) fi CFLAGS="$CFLAGS $JEMALLOC_CFLAGS" -- cgit v1.2.3-54-g00ecf From 4d4e2abd2f961e735b9b8d93e9e09695515b8ac8 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 29 Aug 2019 11:43:43 -0400 Subject: Authorities reject relays running unsupported Tor release series. Our minimum version is now 0.2.9.5-alpha. Series 0.3.0, 0.3.1, 0.3.2, 0.3.3, and 0.3.4 are now rejected. Also, extract this version-checking code into a new function, so we can test it. Closes ticket 31549. Also reject 0.3.5.0 through 0.3.5.6-rc as unstable. --- changes/ticket31549 | 4 +++ src/feature/dirauth/process_descs.c | 59 +++++++++++++++++++++++++++---------- src/feature/dirauth/process_descs.h | 2 ++ 3 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 changes/ticket31549 (limited to 'changes') diff --git a/changes/ticket31549 b/changes/ticket31549 new file mode 100644 index 0000000000..2c27aca4fb --- /dev/null +++ b/changes/ticket31549 @@ -0,0 +1,4 @@ + o Minor features (authority): + - Directory authorities now reject relays running all currently + deprecated release series. The currently supported release series + are: 0.2.9, 0.3.5, 0.4.0, 0.4.1, and 0.4.2. Closes ticket 31549. diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c index e1a02179b0..74a2cde1bd 100644 --- a/src/feature/dirauth/process_descs.c +++ b/src/feature/dirauth/process_descs.c @@ -315,6 +315,47 @@ dirserv_would_reject_router(const routerstatus_t *rs) return (res & FP_REJECT) != 0; } +/** + * Check whether the platform string in platform describes a platform + * that, as a directory authority, we want to reject. If it does, return + * true, and set *msg (if present) to a rejection message. Otherwise + * return false. + */ +STATIC bool +dirserv_rejects_tor_version(const char *platform, + const char **msg) +{ + if (!platform) + return false; + + static const char please_upgrade_string[] = + "Tor version is insecure or unsupported. Please upgrade!"; + + /* Versions before Tor 0.2.9 are unsupported. Versions between 0.2.9.0 and + * 0.2.9.4 suffer from bug #20499, where relays don't keep their consensus + * up to date */ + if (!tor_version_as_new_as(platform,"0.2.9.5-alpha")) { + if (msg) + *msg = please_upgrade_string; + return true; + } + + /* Series between Tor 0.3.0 and 0.3.4 inclusive are unsupported, and some + * have bug #27841, which makes them broken as intro points. Reject them. + * + * Also reject unstable versions of 0.3.5, since (as of this writing) + * they are almost none of the network. */ + if (tor_version_as_new_as(platform,"0.3.0.0-alpha-dev") && + !tor_version_as_new_as(platform,"0.3.5.7")) { + if (msg) { + *msg = please_upgrade_string; + } + return true; + } + + return false; +} + /** Helper: As dirserv_router_get_status, but takes the router fingerprint * (hex, no spaces), nickname, address (used for logging only), IP address, OR * port and platform (logging only) as arguments. @@ -347,22 +388,8 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname, } } - /* Versions before Tor 0.2.4.18-rc are too old to support, and are - * missing some important security fixes too. Disable them. */ - if (platform && !tor_version_as_new_as(platform,"0.2.4.18-rc")) { - if (msg) - *msg = "Tor version is insecure or unsupported. Please upgrade!"; - return FP_REJECT; - } - - /* Tor 0.2.9.x where x<5 suffers from bug #20499, where relays don't - * keep their consensus up to date so they make bad guards. - * The simple fix is to just drop them from the network. */ - if (platform && - tor_version_as_new_as(platform,"0.2.9.0-alpha") && - !tor_version_as_new_as(platform,"0.2.9.5-alpha")) { - if (msg) - *msg = "Tor version contains bug 20499. Please upgrade!"; + /* Check whether the version is obsolete, broken, insecure, etc... */ + if (platform && dirserv_rejects_tor_version(platform, msg)) { return FP_REJECT; } diff --git a/src/feature/dirauth/process_descs.h b/src/feature/dirauth/process_descs.h index 1d4085b091..0203cebfa9 100644 --- a/src/feature/dirauth/process_descs.h +++ b/src/feature/dirauth/process_descs.h @@ -38,6 +38,8 @@ int dirserv_would_reject_router(const routerstatus_t *rs); #ifdef TOR_UNIT_TESTS STATIC int dirserv_router_has_valid_address(routerinfo_t *ri); +STATIC bool dirserv_rejects_tor_version(const char *platform, + const char **msg); #endif /* defined(TOR_UNIT_TESTS) */ #endif /* !defined(TOR_RECV_UPLOADS_H) */ -- cgit v1.2.3-54-g00ecf From 519afb0ece2485eb20450d0508637cf5632ce75d Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 3 Oct 2019 12:22:46 -0400 Subject: Sort changes entries into a changelog for 0.4.2.2-alpha --- ChangeLog | 122 +++++++++++++++++++++++++++++++++++++++++++ changes/bug28966 | 4 -- changes/bug30916 | 4 -- changes/bug31107 | 4 -- changes/bug31334 | 4 -- changes/bug31408 | 5 -- changes/bug31614 | 9 ---- changes/bug31736 | 3 -- changes/bug31825 | 3 -- changes/bug31854 | 3 -- changes/bug31884 | 3 -- changes/bug31897 | 3 -- changes/bug31898 | 4 -- changes/geoip-2019-10-01 | 4 -- changes/ticket30743 | 7 --- changes/ticket31338 | 4 -- changes/ticket31372_appveyor | 4 -- changes/ticket31372_travis | 4 -- changes/ticket31466 | 5 -- changes/ticket31549 | 4 -- changes/ticket31589 | 2 - changes/ticket31675 | 3 -- changes/ticket31759 | 5 -- changes/ticket31772 | 4 -- changes/ticket31839 | 3 -- changes/ticket31840 | 3 -- changes/ticket31849 | 5 -- 27 files changed, 122 insertions(+), 106 deletions(-) delete mode 100644 changes/bug28966 delete mode 100644 changes/bug30916 delete mode 100644 changes/bug31107 delete mode 100644 changes/bug31334 delete mode 100644 changes/bug31408 delete mode 100644 changes/bug31614 delete mode 100644 changes/bug31736 delete mode 100644 changes/bug31825 delete mode 100644 changes/bug31854 delete mode 100644 changes/bug31884 delete mode 100644 changes/bug31897 delete mode 100644 changes/bug31898 delete mode 100644 changes/geoip-2019-10-01 delete mode 100644 changes/ticket30743 delete mode 100644 changes/ticket31338 delete mode 100644 changes/ticket31372_appveyor delete mode 100644 changes/ticket31372_travis delete mode 100644 changes/ticket31466 delete mode 100644 changes/ticket31549 delete mode 100644 changes/ticket31589 delete mode 100644 changes/ticket31675 delete mode 100644 changes/ticket31759 delete mode 100644 changes/ticket31772 delete mode 100644 changes/ticket31839 delete mode 100644 changes/ticket31840 delete mode 100644 changes/ticket31849 (limited to 'changes') diff --git a/ChangeLog b/ChangeLog index 938e91545e..f69bc8c39c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,125 @@ +Changes in version 0.4.2.2-alpha - 2019-10-0? + This release fixes several bugs from the previous alpha release. + + o Major bugfixes (embedded Tor): + - Avoid a possible crash when restarting Tor in embedded mode and + enabling a different set of publish/subscribe messages. Fixes bug + 31898; bugfix on 0.4.1.1-alpha. + + o Major bugfixes (torrc): + - Stop ignoring torrc options after an %include directive, when the + included directory ends with a file that does not contain any config + options. (But does contain comments or whitespace.) + Fixes bug 31408; bugfix on 0.3.1.1-alpha. + + o Minor features (authority): + - Directory authorities now reject relays running all currently + deprecated release series. The currently supported release series + are: 0.2.9, 0.3.5, 0.4.0, 0.4.1, and 0.4.2. Closes ticket 31549. + + o Minor features (auto-formatting scripts): + - When annotating C macros, never generate a line that our check-spaces + script would reject. Closes ticket 31759. + - When annotating C macros, try to remove cases of double-negation. + Closes ticket 31779. + + o Minor features (continuous integration): + - When building on Appveyor, pass the "-k" flag to make, so that + we are informed of all compilation failures, not just the first + one or two. Closes part of ticket 31372. + - When building on Travis, pass the "-k" flag to make, so that + we are informed of all compilation failures, not just the first + one or two. Closes part of ticket 31372. + + o Minor features (geoip): + - Update geoip and geoip6 to the October 1 2019 Maxmind GeoLite2 + Country database. Closes ticket 31931. + + o Minor features (maintenance scripts): + - Add a coccinelle script to detect bugs caused by incrementing or + decrementing a variable inside a call to log_debug(). Since + log_debug() is a macro whose arguments are conditionally evaluated, it + is usually an error to do this. One such bug was 30628, in which SENDME + cells were miscounted by a decrement operator inside a log_debug() + call. Closes ticket 30743. + + o Minor features (onion services v3): + - Assist users who try to setup v2 client authorization in v3 onion + services by pointing them to the right documentation. Closes ticket + 28966. + + o Minor bugfixes (Appveyor CI): + - Avoid spurious errors when Appveyor CI fails before the install step. + Fixes bug 31884; bugfix on 0.3.4.2-alpha. + + o Minor bugfixes (best practices tracker): + - When listing overbroad exceptions, do not also list problems, + and do not list insufficiently broad exceptions. Fixes bug 31338; + bugfix on 0.4.2.1-alpha. + + o Minor bugfixes (controller protocol): + - Fix the MAPADDRESS controller command to accept one or more + arguments. Previously, it required two or more arguments, and ignored + the first. Fixes bug 31772; bugfix on 0.4.1.1-alpha. + + o Minor bugfixes (logging): + - Add a missing check for HAVE_PTHREAD_H, because the backtrace code uses + mutexes. Fixes bug 31614; bugfix on 0.2.5.2-alpha. + - Disable backtrace signal handlers when shutting down tor. + Fixes bug 31614; bugfix on 0.2.5.2-alpha. + - Rate-limit our the logging message about the obsolete .exit notation. + Previously, there was no limit on this warning, which could potentially + be triggered many times by a hostile website. Fixes bug 31466; + bugfix on 0.2.2.1-alpha. + - When initialising log domain masks, only set known log domains. + Fixes bug 31854; bugfix on 0.2.1.1-alpha. + + o Minor bugfixes (logging, protocol violations): + - Do not log a nonfatal assertion failure when receiving a VERSIONS + cell on a connection using the obsolete v1 link protocol. Log a + protocol_warn instead. Fixes bug 31107; bugfix on 0.2.4.4-alpha. + + o Minor bugfixes (modules): + - Explain what the optional Directory Authority module is, and what + happens when it is disabled. Fixes bug 31825; bugfix on 0.3.4.1-alpha. + + o Minor bugfixes (multithreading): + - Avoid some undefined behaviour when freeing mutexes. + Fixes bug 31736; bugfix on 0.0.7. + + o Minor bugfixes (relay): + - Avoid crashing when starting with a corrupt keys directory where + the old ntor key and the new ntor key are identical. Fixes bug 30916; + bugfix on 0.2.4.8-alpha. + + o Minor bugfixes (tests, SunOS): + - Avoid a map_anon_nofork test failure due to a signed/unsigned integer + comparison. Fixes bug 31897; bugfix on 0.4.1.1-alpha. + + o Code simplification and refactoring (onion services): + - Interface for function `decrypt_desc_layer` cleaned up. Closes ticket 31589. + + o Code simplification and refactoring: + - Refactor connection_control_process_inbuf() to reduce the size of a + practracker exception. Closes ticket 31840. + - Refactor the microdescs_parse_from_string() function into smaller + pieces, for better comprehensibility. Closes ticket 31675. + - Use SEVERITY_MASK_IDX() to find the LOG_* mask indexes in the unit + tests and fuzzers, rather than using hard-coded values. + Closes ticket 31334. + + o Documentation: + - Document the signal-safe logging behaviour in the tor man page. Also + add some comments to the relevant functions. Closes ticket 31839. + - Explain why we can't destroy the backtrace buffer mutex. Explain why + we don't need to destroy the log mutex. + Closes ticket 31736. + - The Tor source code repository now includes a (somewhat dated) + description of Tor's modular architecture, in doc/HACKING/design. + This is based on the old "tor-guts.git" repository, which we are + adopting and superseding. Closes ticket 31849. + + Changes in version 0.4.1.6 - 2019-09-19 This release backports several bugfixes to improve stability and correctness. Anyone experiencing build problems or crashes with 0.4.1.5, diff --git a/changes/bug28966 b/changes/bug28966 deleted file mode 100644 index 61123a21eb..0000000000 --- a/changes/bug28966 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (onion services v3): - - Assist users who try to setup v2 client authorization in v3 onion - services by pointing them to the right documentation. Closes ticket - 28966. diff --git a/changes/bug30916 b/changes/bug30916 deleted file mode 100644 index b006bfc75d..0000000000 --- a/changes/bug30916 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (relay): - - Avoid crashing when starting with a corrupt keys directory where - the old ntor key and the new ntor key are identical. Fixes bug 30916; - bugfix on 0.2.4.8-alpha. diff --git a/changes/bug31107 b/changes/bug31107 deleted file mode 100644 index 9652927c30..0000000000 --- a/changes/bug31107 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (logging, protocol violations): - - Do not log a nonfatal assertion failure when receiving a VERSIONS - cell on a connection using the obsolete v1 link protocol. Log a - protocol_warn instead. Fixes bug 31107; bugfix on 0.2.4.4-alpha. diff --git a/changes/bug31334 b/changes/bug31334 deleted file mode 100644 index dfc9cc530e..0000000000 --- a/changes/bug31334 +++ /dev/null @@ -1,4 +0,0 @@ - o Code simplification and refactoring: - - Use SEVERITY_MASK_IDX() to find the LOG_* mask indexes in the unit - tests and fuzzers, rather than using hard-coded values. - Closes ticket 31334. diff --git a/changes/bug31408 b/changes/bug31408 deleted file mode 100644 index 3e4ffa927d..0000000000 --- a/changes/bug31408 +++ /dev/null @@ -1,5 +0,0 @@ - o Major bugfixes (torrc): - - Stop ignoring torrc options after an %include directive, when the - included directory ends with a file that does not contain any config - options. (But does contain comments or whitespace.) - Fixes bug 31408; bugfix on 0.3.1.1-alpha. diff --git a/changes/bug31614 b/changes/bug31614 deleted file mode 100644 index c425a9fcd4..0000000000 --- a/changes/bug31614 +++ /dev/null @@ -1,9 +0,0 @@ - o Minor bugfixes (logging): - - Disable backtrace signal handlers when shutting down tor. - Fixes bug 31614; bugfix on 0.2.5.2-alpha. - - Add a missing check for HAVE_PTHREAD_H, because the backtrace code uses - mutexes. Fixes bug 31614; bugfix on 0.2.5.2-alpha. - o Documentation: - - Explain why we can't destroy the backtrace buffer mutex. Explain why - we don't need to destroy the log mutex. - Closes ticket 31736. diff --git a/changes/bug31736 b/changes/bug31736 deleted file mode 100644 index beb09e5069..0000000000 --- a/changes/bug31736 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (multithreading): - - Avoid some undefined behaviour when freeing mutexes. - Fixes bug 31736; bugfix on 0.0.7. diff --git a/changes/bug31825 b/changes/bug31825 deleted file mode 100644 index fe90acf299..0000000000 --- a/changes/bug31825 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (modules): - - Explain what the optional Directory Authority module is, and what - happens when it is disabled. Fixes bug 31825; bugfix on 0.3.4.1-alpha. diff --git a/changes/bug31854 b/changes/bug31854 deleted file mode 100644 index 692a192fd9..0000000000 --- a/changes/bug31854 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (logging): - - When initialising log domain masks, only set known log domains. - Fixes bug 31854; bugfix on 0.2.1.1-alpha. diff --git a/changes/bug31884 b/changes/bug31884 deleted file mode 100644 index ddb6c50d74..0000000000 --- a/changes/bug31884 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (Appveyor CI): - - Avoid spurious errors when Appveyor CI fails before the install step. - Fixes bug 31884; bugfix on 0.3.4.2-alpha. diff --git a/changes/bug31897 b/changes/bug31897 deleted file mode 100644 index 81c63e704e..0000000000 --- a/changes/bug31897 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (tests, SunOS): - - Avoid a map_anon_nofork test failure due to a signed/unsigned integer - comparison. Fixes bug 31897; bugfix on 0.4.1.1-alpha. diff --git a/changes/bug31898 b/changes/bug31898 deleted file mode 100644 index 6f3e0a5465..0000000000 --- a/changes/bug31898 +++ /dev/null @@ -1,4 +0,0 @@ - o Major bugfixes (embedded Tor): - - Avoid a possible crash when restarting Tor in embedded mode and - enabling a different set of publish/subscribe messages. Fixes bug - 31898; bugfix on 0.4.1.1-alpha. diff --git a/changes/geoip-2019-10-01 b/changes/geoip-2019-10-01 deleted file mode 100644 index c7ed17b5c4..0000000000 --- a/changes/geoip-2019-10-01 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (geoip): - - Update geoip and geoip6 to the October 1 2019 Maxmind GeoLite2 - Country database. Closes ticket 31931. - diff --git a/changes/ticket30743 b/changes/ticket30743 deleted file mode 100644 index 4f029717db..0000000000 --- a/changes/ticket30743 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features (maintenance scripts): - - Add a coccinelle script to detect bugs caused by incrementing or - decrementing a variable inside a call to log_debug(). Since - log_debug() is a macro whose arguments are conditionally evaluated, it - is usually an error to do this. One such bug was 30628, in which SENDME - cells were miscounted by a decrement operator inside a log_debug() - call. Closes ticket 30743. diff --git a/changes/ticket31338 b/changes/ticket31338 deleted file mode 100644 index b76add635d..0000000000 --- a/changes/ticket31338 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (best practices tracker): - - When listing overbroad exceptions, do not also list problems, - and do not list insufficiently broad exceptions. Fixes bug 31338; - bugfix on 0.4.2.1-alpha. diff --git a/changes/ticket31372_appveyor b/changes/ticket31372_appveyor deleted file mode 100644 index e7bb03182e..0000000000 --- a/changes/ticket31372_appveyor +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (continuous integration): - - When building on Appveyor, pass the "-k" flag to make, so that - we are informed of all compilation failures, not just the first - one or two. Closes part of ticket 31372. diff --git a/changes/ticket31372_travis b/changes/ticket31372_travis deleted file mode 100644 index 403869b2ed..0000000000 --- a/changes/ticket31372_travis +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (continuous integration): - - When building on Travis, pass the "-k" flag to make, so that - we are informed of all compilation failures, not just the first - one or two. Closes part of ticket 31372. diff --git a/changes/ticket31466 b/changes/ticket31466 deleted file mode 100644 index e535b4502e..0000000000 --- a/changes/ticket31466 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (logging): - - Rate-limit our the logging message about the obsolete .exit notation. - Previously, there was no limit on this warning, which could potentially - be triggered many times by a hostile website. Fixes bug 31466; - bugfix on 0.2.2.1-alpha. diff --git a/changes/ticket31549 b/changes/ticket31549 deleted file mode 100644 index 2c27aca4fb..0000000000 --- a/changes/ticket31549 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (authority): - - Directory authorities now reject relays running all currently - deprecated release series. The currently supported release series - are: 0.2.9, 0.3.5, 0.4.0, 0.4.1, and 0.4.2. Closes ticket 31549. diff --git a/changes/ticket31589 b/changes/ticket31589 deleted file mode 100644 index 673ab653e2..0000000000 --- a/changes/ticket31589 +++ /dev/null @@ -1,2 +0,0 @@ - o Code simplification and refactoring (onion services): - - Interface for function `decrypt_desc_layer` cleaned up. Closes ticket 31589. diff --git a/changes/ticket31675 b/changes/ticket31675 deleted file mode 100644 index 2b426948f3..0000000000 --- a/changes/ticket31675 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Refactor the microdescs_parse_from_string() function into smaller - pieces, for better comprehensibility. Closes ticket 31675. diff --git a/changes/ticket31759 b/changes/ticket31759 deleted file mode 100644 index f7428f711c..0000000000 --- a/changes/ticket31759 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (auto-formatting scripts): - - When annotating C macros, never generate a line that our check-spaces - script would reject. Closes ticket 31759. - - When annotating C macros, try to remove cases of double-negation. - Closes ticket 31779. diff --git a/changes/ticket31772 b/changes/ticket31772 deleted file mode 100644 index 7847b3f746..0000000000 --- a/changes/ticket31772 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (controller protocol): - - Fix the MAPADDRESS controller command to accept one or more - arguments. Previously, it required two or more arguments, and ignored - the first. Fixes bug 31772; bugfix on 0.4.1.1-alpha. diff --git a/changes/ticket31839 b/changes/ticket31839 deleted file mode 100644 index d7da40f530..0000000000 --- a/changes/ticket31839 +++ /dev/null @@ -1,3 +0,0 @@ - o Documentation: - - Document the signal-safe logging behaviour in the tor man page. Also - add some comments to the relevant functions. Closes ticket 31839. diff --git a/changes/ticket31840 b/changes/ticket31840 deleted file mode 100644 index c75c5629f9..0000000000 --- a/changes/ticket31840 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Refactor connection_control_process_inbuf() to reduce the size of a - practracker exception. Closes ticket 31840. diff --git a/changes/ticket31849 b/changes/ticket31849 deleted file mode 100644 index 9d12d938c4..0000000000 --- a/changes/ticket31849 +++ /dev/null @@ -1,5 +0,0 @@ - o Documentation: - - The Tor source code repository now includes a (somewhat dated) - description of Tor's modular architecture, in doc/HACKING/design. - This is based on the old "tor-guts.git" repository, which we are - adopting and superseding. Closes ticket 31849. -- cgit v1.2.3-54-g00ecf From 52b7ae71b31671c758a2798e8c98abb720ac22f5 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 11 Sep 2019 08:46:31 -0400 Subject: hs: ADD_ONION NEW:BEST now defaults to ED25519-V3 From RSA1024 (v2) to v3 now. Closes #29669 Signed-off-by: David Goulet --- changes/ticket29669 | 3 +++ src/feature/control/control_cmd.c | 7 ++++--- src/test/test_controller.c | 28 +++++++++++++++------------- 3 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 changes/ticket29669 (limited to 'changes') diff --git a/changes/ticket29669 b/changes/ticket29669 new file mode 100644 index 0000000000..f7e98a16ce --- /dev/null +++ b/changes/ticket29669 @@ -0,0 +1,3 @@ + o Minor feature (hidden service, control port): + - The ADD_ONION key blob keyword "BEST" now defaults from RSA1024 (v2) to + ED25519-V3 (v3). Closes ticket 29669. diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c index f804ceafbc..de1bef7e59 100644 --- a/src/feature/control/control_cmd.c +++ b/src/feature/control/control_cmd.c @@ -1982,8 +1982,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk, *hs_version = HS_VERSION_THREE; } else if (!strcasecmp(key_type_new, key_type)) { /* "NEW:" - Generating a new key, blob as algorithm. */ - if (!strcasecmp(key_type_rsa1024, key_blob) || - !strcasecmp(key_type_best, key_blob)) { + if (!strcasecmp(key_type_rsa1024, key_blob)) { /* "RSA1024", RSA 1024 bit, also currently "BEST" by default. */ pk = crypto_pk_new(); if (crypto_pk_generate_key(pk)) { @@ -2002,7 +2001,9 @@ add_onion_helper_keyarg(const char *arg, int discard_pk, } decoded_key->v2 = pk; *hs_version = HS_VERSION_TWO; - } else if (!strcasecmp(key_type_ed25519_v3, key_blob)) { + } else if (!strcasecmp(key_type_ed25519_v3, key_blob) || + !strcasecmp(key_type_best, key_blob)) { + /* "ED25519-V3", ed25519 key, also currently "BEST" by default. */ ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk)); if (ed25519_secret_key_generate(sk, 1) < 0) { tor_free(sk); diff --git a/src/test/test_controller.c b/src/test/test_controller.c index b9cbe0a14d..55eb79e448 100644 --- a/src/test/test_controller.c +++ b/src/test/test_controller.c @@ -243,8 +243,22 @@ test_add_onion_helper_keyarg_v3(void *arg) tor_free(pk.v3); pk.v3 = NULL; tor_free(key_new_blob); + /* Test "BEST" key generation (Assumes BEST = ED25519-V3). */ + tor_free(pk.v3); pk.v3 = NULL; + tor_free(key_new_blob); + ret = add_onion_helper_keyarg("NEW:BEST", 0, &key_new_alg, &key_new_blob, + &pk, &hs_version, NULL); + tt_int_op(ret, OP_EQ, 0); + tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE); + tt_assert(pk.v3); + tt_str_op(key_new_alg, OP_EQ, "ED25519-V3"); + tt_assert(key_new_blob); + tt_ptr_op(reply_str, OP_EQ, NULL); + /* Test discarding the private key. */ tor_free(reply_str); + tor_free(pk.v3); pk.v3 = NULL; + tor_free(key_new_blob); ret = add_onion_helper_keyarg("NEW:ED25519-V3", 1, &key_new_alg, &key_new_blob, &pk, &hs_version, NULL); @@ -323,22 +337,10 @@ test_add_onion_helper_keyarg_v2(void *arg) tt_assert(key_new_blob); tt_ptr_op(reply_str, OP_EQ, NULL); - /* Test "BEST" key generation (Assumes BEST = RSA1024). */ - crypto_pk_free(pk.v2); pk.v2 = NULL; - tor_free(key_new_blob); - ret = add_onion_helper_keyarg("NEW:BEST", 0, &key_new_alg, &key_new_blob, - &pk, &hs_version, NULL); - tt_int_op(ret, OP_EQ, 0); - tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); - tt_assert(pk.v2); - tt_str_op(key_new_alg, OP_EQ, "RSA1024"); - tt_assert(key_new_blob); - tt_ptr_op(reply_str, OP_EQ, NULL); - /* Test discarding the private key. */ crypto_pk_free(pk.v2); pk.v2 = NULL; tor_free(key_new_blob); - ret = add_onion_helper_keyarg("NEW:BEST", 1, &key_new_alg, &key_new_blob, + ret = add_onion_helper_keyarg("NEW:RSA1024", 1, &key_new_alg, &key_new_blob, &pk, &hs_version, NULL); tt_int_op(ret, OP_EQ, 0); tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO); -- cgit v1.2.3-54-g00ecf From fdfb4b196b7c38f45f2d37f73fcc96d746816cc3 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 3 Oct 2019 08:57:14 -0400 Subject: Use {mock,unmock}_hostname_resolver() in relevant tests These tests all invoke the hostname resolver in one way or another, and therefore potentially block if our DNS server is missing, absent, or extremely slow. Closes ticket 31841. --- changes/ticket31841 | 5 +++++ src/test/test_addr.c | 6 +++++- src/test/test_config.c | 4 ++++ src/test/test_hs_config.c | 8 +++++--- src/test/test_options.c | 3 +++ 5 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 changes/ticket31841 (limited to 'changes') diff --git a/changes/ticket31841 b/changes/ticket31841 new file mode 100644 index 0000000000..6e7fbc1da1 --- /dev/null +++ b/changes/ticket31841 @@ -0,0 +1,5 @@ + o Minor features (testing): + - When running tests that attempt to look up hostname, replace the libc + name lookup functions with ones that do not actually touch the network. + This way, the tests complete more quickly in the presence of a slow or + missing DNS resolver. Closes ticket 31841. diff --git a/src/test/test_addr.c b/src/test/test_addr.c index f99e3be8f5..c89c6e78d4 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -12,6 +12,7 @@ #include "test/log_test_helpers.h" #include "lib/net/resolve.h" #include "test/rng_test_helpers.h" +#include "test/resolve_test_helpers.h" #ifdef HAVE_SYS_UN_H #include @@ -1160,6 +1161,7 @@ test_addr_parse_canonical(void *arg) static void test_addr_parse(void *arg) { + int r; tor_addr_t addr; uint16_t port; @@ -1169,6 +1171,8 @@ test_addr_parse(void *arg) (void)arg; + mock_hostname_resolver(); + /* IPv6-mapped IPv4 addresses. Tor doesn't really use these. */ TEST_ADDR_V6_PARSE("11:22:33:44:55:66:1.2.3.4", 0, "11:22:33:44:55:66:102:304"); @@ -1273,7 +1277,7 @@ test_addr_parse(void *arg) "11:22::88",99); done: - ; + unmock_hostname_resolver(); } static void diff --git a/src/test/test_config.c b/src/test/test_config.c index 1c6c913078..cbb84e4dcf 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -45,6 +45,7 @@ #include "app/config/statefile.h" #include "test/test_helpers.h" +#include "test/resolve_test_helpers.h" #include "feature/dirclient/dir_server_st.h" #include "core/or/port_cfg_st.h" @@ -4068,6 +4069,8 @@ test_config_parse_port_config__ports__ports_given(void *data) slout = smartlist_new(); + mock_hostname_resolver(); + // Test error when encounters an invalid Port specification config_port_invalid = mock_config_line("DNSPort", ""); ret = parse_port_config(NULL, config_port_invalid, "DNS", 0, NULL, @@ -4764,6 +4767,7 @@ test_config_parse_port_config__ports__ports_given(void *data) #endif /* defined(_WIN32) */ done: + unmock_hostname_resolver(); if (slout) SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf)); smartlist_free(slout); diff --git a/src/test/test_hs_config.c b/src/test/test_hs_config.c index 2b3afbb6e9..71e1529216 100644 --- a/src/test/test_hs_config.c +++ b/src/test/test_hs_config.c @@ -12,6 +12,7 @@ #include "test/test.h" #include "test/test_helpers.h" #include "test/log_test_helpers.h" +#include "test/resolve_test_helpers.h" #include "app/config/config.h" #include "feature/hs/hs_common.h" @@ -272,6 +273,7 @@ test_valid_service_v2(void *arg) int ret; (void) arg; + mock_hostname_resolver(); /* Valid complex configuration. Basic client authorization. */ { @@ -314,7 +316,7 @@ test_valid_service_v2(void *arg) } done: - ; + unmock_hostname_resolver(); } static void @@ -392,6 +394,7 @@ test_valid_service_v3(void *arg) int ret; (void) arg; + mock_hostname_resolver(); /* Valid complex configuration. */ { @@ -448,7 +451,7 @@ test_valid_service_v3(void *arg) } done: - ; + unmock_hostname_resolver(); } static void @@ -623,4 +626,3 @@ struct testcase_t hs_config_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_options.c b/src/test/test_options.c index 2d45ecd189..d8757491fa 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -14,6 +14,7 @@ #include "feature/nodelist/routerset.h" #include "core/mainloop/mainloop.h" #include "test/log_test_helpers.h" +#include "test/resolve_test_helpers.h" #include "lib/sandbox/sandbox.h" #include "lib/memarea/memarea.h" @@ -241,6 +242,7 @@ test_options_validate(void *arg) (void)arg; setup_log_callback(); sandbox_disable_getaddrinfo_cache(); + mock_hostname_resolver(); WANT_ERR("ExtORPort 500000", "Invalid ExtORPort", PH_VALIDATE); @@ -282,6 +284,7 @@ test_options_validate(void *arg) close_temp_logs(); clear_log_messages(); + unmock_hostname_resolver(); return; } -- cgit v1.2.3-54-g00ecf From 081bd37315a57616144a8e6272a2ea796ace989e Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 8 Oct 2019 18:59:27 +0300 Subject: Fix flapping of test_service_intro_point() unittest. --- changes/bug31995 | 3 +++ src/test/test_hs_service.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changes/bug31995 (limited to 'changes') diff --git a/changes/bug31995 b/changes/bug31995 new file mode 100644 index 0000000000..c7ddd437a6 --- /dev/null +++ b/changes/bug31995 @@ -0,0 +1,3 @@ + o Minor bugfixes (testing): + - Avoid intermittent test failures due to a test that had relied on + inconsistent timing sources. Fixes bug 31995; bugfix on 0.3.1.3-alpha. diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c index c5854f0ff8..8993ce3fe2 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -674,9 +674,11 @@ test_service_intro_point(void *arg) (void) arg; + update_approx_time(1481621834); + /* Test simple creation of an object. */ { - time_t now = time(NULL); + time_t now = approx_time(); ip = helper_create_service_ip(); tt_assert(ip); /* Make sure the authentication keypair is not zeroes. */ -- cgit v1.2.3-54-g00ecf From f50de3a91872014f03856cf4c889f029ec5a1892 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 10 Sep 2019 14:40:40 -0400 Subject: hs-v3: Do not remove intro point if circuit exists When considering introduction point of a service's descriptor, do not remove an intro point that has an established or pending circuit. Fixes #31652 Signed-off-by: David Goulet --- changes/bug31652 | 5 +++ src/feature/hs/hs_service.c | 87 +++++++++++++++++++++++++++++++++------------ src/test/test_hs_service.c | 1 + 3 files changed, 70 insertions(+), 23 deletions(-) create mode 100644 changes/bug31652 (limited to 'changes') diff --git a/changes/bug31652 b/changes/bug31652 new file mode 100644 index 0000000000..c4eca7994a --- /dev/null +++ b/changes/bug31652 @@ -0,0 +1,5 @@ + o Minor bugfixes (onion services): + - When we clean up intro circuits for a v3 onion service, don't remove + circuits that have an established or pending circuit even if ran out of + retries. This way, we don't cleanup the circuit of the last retry. Fixes + bug 31652; bugfix on 0.3.2.1-alpha. diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index f81987f69f..18c38ebc0a 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -2333,15 +2333,70 @@ intro_point_should_expire(const hs_service_intro_point_t *ip, return 1; } -/* Go over the given set of intro points for each service and remove any - * invalid ones. The conditions for removal are: +/* Return true iff we should remove the intro point ip from its service. * - * - The node doesn't exists anymore (not in consensus) - * OR - * - The intro point maximum circuit retry count has been reached and no - * circuit can be found associated with it. - * OR - * - The intro point has expired and we should pick a new one. + * We remove an intro point from the service descriptor list if one of + * these criteria is met: + * - It has expired (either in INTRO2 count or in time). + * - No node was found (fell off the consensus). + * - We are over the maximum amount of retries. + * + * If an established or pending circuit is found for the given ip object, this + * return false indicating it should not be removed. */ +static bool +should_remove_intro_point(hs_service_intro_point_t *ip, time_t now) +{ + bool ret = false; + + tor_assert(ip); + + /* Any one of the following needs to be True to furfill the criteria to + * remove an intro point. */ + bool has_no_retries = (ip->circuit_retries > + MAX_INTRO_POINT_CIRCUIT_RETRIES); + bool has_no_node = (get_node_from_intro_point(ip) == NULL); + bool has_expired = intro_point_should_expire(ip, now); + + /* If the node fell off the consensus or the IP has expired, we have to + * remove it now. */ + if (has_no_node || has_expired) { + ret = true; + goto end; + } + + /* Pass this point, even though we might be over the retry limit, we check + * if a circuit (established or pending) exists. In that case, we should not + * remove it because it might simply be valid and opened at the previous + * scheduled event for the last retry. */ + + /* Did we established already? */ + if (ip->circuit_established) { + goto end; + } + /* Do we simply have an existing circuit regardless of its state? */ + if (hs_circ_service_get_intro_circ(ip)) { + goto end; + } + + /* Getting here means we have _no_ circuits so then return if we have any + * remaining retries. */ + ret = has_no_retries; + + end: + /* Meaningful log in case we are about to remove the IP. */ + if (ret) { + log_info(LD_REND, "Intro point %s%s (retried: %u times). " + "Removing it.", + describe_intro_point(ip), + has_expired ? " has expired" : + (has_no_node) ? " fell off the consensus" : "", + ip->circuit_retries); + } + return ret; +} + +/* Go over the given set of intro points for each service and remove any + * invalid ones. * * If an intro point is removed, the circuit (if any) is immediately close. * If a circuit can't be found, the intro point is kept if it hasn't reached @@ -2366,21 +2421,7 @@ cleanup_intro_points(hs_service_t *service, time_t now) * valid and remove any of them that aren't. */ DIGEST256MAP_FOREACH_MODIFY(desc->intro_points.map, key, hs_service_intro_point_t *, ip) { - const node_t *node = get_node_from_intro_point(ip); - int has_expired = intro_point_should_expire(ip, now); - - /* We cleanup an intro point if it has expired or if we do not know the - * node_t anymore (removed from our latest consensus) or if we've - * reached the maximum number of retry with a non existing circuit. */ - if (has_expired || node == NULL || - ip->circuit_retries > MAX_INTRO_POINT_CIRCUIT_RETRIES) { - log_info(LD_REND, "Intro point %s%s (retried: %u times). " - "Removing it.", - describe_intro_point(ip), - has_expired ? " has expired" : - (node == NULL) ? " fell off the consensus" : "", - ip->circuit_retries); - + if (should_remove_intro_point(ip, now)) { /* We've retried too many times, remember it as a failed intro point * so we don't pick it up again for INTRO_CIRC_RETRY_PERIOD sec. */ if (ip->circuit_retries > MAX_INTRO_POINT_CIRCUIT_RETRIES) { diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c index c5854f0ff8..a2594ed6af 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -1300,6 +1300,7 @@ test_service_event(void *arg) OP_EQ, 1); /* Remove the IP object at once for the next test. */ ip->circuit_retries = MAX_INTRO_POINT_CIRCUIT_RETRIES + 1; + ip->circuit_established = 0; run_housekeeping_event(now); tt_int_op(digest256map_size(service->desc_current->intro_points.map), OP_EQ, 0); -- cgit v1.2.3-54-g00ecf From b356b3907a6424d9e1a14722e9729529862a698f Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 2 Oct 2019 13:19:51 -0400 Subject: hs-v3: Fix implicit ssize_t to size_t conversion Found by Coverity. Fixes #31682 Signed-off-by: David Goulet --- changes/ticket31682 | 3 +++ src/feature/hs/hs_cell.c | 26 +++++++++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 changes/ticket31682 (limited to 'changes') diff --git a/changes/ticket31682 b/changes/ticket31682 new file mode 100644 index 0000000000..9777dec1f3 --- /dev/null +++ b/changes/ticket31682 @@ -0,0 +1,3 @@ + o Minor bugfixes (hidden service v3, coverity): + - Fix an implicit conversion from ssize_t to size_t discovered by Coverity. + Fixes bug 31682; bugfix on 0.4.2.1-alpha. diff --git a/src/feature/hs/hs_cell.c b/src/feature/hs/hs_cell.c index 547dda3e16..3147b898bc 100644 --- a/src/feature/hs/hs_cell.c +++ b/src/feature/hs/hs_cell.c @@ -495,11 +495,12 @@ build_establish_intro_dos_param(trn_cell_extension_dos_t *dos_ext, /* Build the DoS defense cell extension and put it in the given extensions * object. This can't fail. */ -static void +static int build_establish_intro_dos_extension(const hs_service_config_t *service_config, trn_cell_extension_t *extensions) { - ssize_t ret, dos_ext_encoded_len; + ssize_t ret; + size_t dos_ext_encoded_len; uint8_t *field_array; trn_cell_extension_field_t *field; trn_cell_extension_dos_t *dos_ext; @@ -526,7 +527,11 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config, service_config->intro_dos_burst_per_sec); /* Set the field with the encoded DoS extension. */ - dos_ext_encoded_len = trn_cell_extension_dos_encoded_len(dos_ext); + ret = trn_cell_extension_dos_encoded_len(dos_ext); + if (BUG(ret <= 0)) { + return -1; + } + dos_ext_encoded_len = ret; /* Set length field and the field array size length. */ trn_cell_extension_field_set_field_len(field, dos_ext_encoded_len); trn_cell_extension_field_setlen_field(field, dos_ext_encoded_len); @@ -534,7 +539,10 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config, field_array = trn_cell_extension_field_getarray_field(field); ret = trn_cell_extension_dos_encode(field_array, trn_cell_extension_field_getlen_field(field), dos_ext); - tor_assert(ret == dos_ext_encoded_len); + if (BUG(ret <= 0)) { + return -1; + } + tor_assert(ret == (ssize_t) dos_ext_encoded_len); /* Finally, encode field into the cell extension. */ trn_cell_extension_add_fields(extensions, field); @@ -546,6 +554,8 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config, /* Cleanup. DoS extension has been encoded at this point. */ trn_cell_extension_dos_free(dos_ext); + + return 0; } /* ========== */ @@ -558,6 +568,7 @@ STATIC trn_cell_extension_t * build_establish_intro_extensions(const hs_service_config_t *service_config, const hs_service_intro_point_t *ip) { + int ret; trn_cell_extension_t *extensions; tor_assert(service_config); @@ -571,9 +582,14 @@ build_establish_intro_extensions(const hs_service_config_t *service_config, if (service_config->has_dos_defense_enabled && ip->support_intro2_dos_defense) { /* This function takes care to increment the number of extensions. */ - build_establish_intro_dos_extension(service_config, extensions); + ret = build_establish_intro_dos_extension(service_config, extensions); + if (ret < 0) { + /* Return no extensions on error. */ + goto end; + } } + end: return extensions; } -- cgit v1.2.3-54-g00ecf From 09e6c0f7c7b91a73c73df197e45072a96240ea8d Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 15 Oct 2019 08:54:11 -0400 Subject: hs-v3: Fix possible memory leak in error code path Found by coverity CID 1454769. There were a second possible leak that is also fixed in this commit. Fixes #32063 Signed-off-by: David Goulet --- changes/ticket32063 | 3 +++ src/feature/hs/hs_cell.c | 13 +++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 changes/ticket32063 (limited to 'changes') diff --git a/changes/ticket32063 b/changes/ticket32063 new file mode 100644 index 0000000000..2c0246917c --- /dev/null +++ b/changes/ticket32063 @@ -0,0 +1,3 @@ + o Minor bugfixes (hs-v3, memory leak): + - Fix memory leak in unlikely error code path when encoding HS DoS establish + intro extension cell. Fixes bug 32063; bugfix on 0.4.2.1-alpha. diff --git a/src/feature/hs/hs_cell.c b/src/feature/hs/hs_cell.c index d691a1b007..df59f73c1b 100644 --- a/src/feature/hs/hs_cell.c +++ b/src/feature/hs/hs_cell.c @@ -503,8 +503,8 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config, ssize_t ret; size_t dos_ext_encoded_len; uint8_t *field_array; - trn_cell_extension_field_t *field; - trn_cell_extension_dos_t *dos_ext; + trn_cell_extension_field_t *field = NULL; + trn_cell_extension_dos_t *dos_ext = NULL; tor_assert(service_config); tor_assert(extensions); @@ -530,7 +530,7 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config, /* Set the field with the encoded DoS extension. */ ret = trn_cell_extension_dos_encoded_len(dos_ext); if (BUG(ret <= 0)) { - return -1; + goto err; } dos_ext_encoded_len = ret; /* Set length field and the field array size length. */ @@ -541,7 +541,7 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config, ret = trn_cell_extension_dos_encode(field_array, trn_cell_extension_field_getlen_field(field), dos_ext); if (BUG(ret <= 0)) { - return -1; + goto err; } tor_assert(ret == (ssize_t) dos_ext_encoded_len); @@ -557,6 +557,11 @@ build_establish_intro_dos_extension(const hs_service_config_t *service_config, trn_cell_extension_dos_free(dos_ext); return 0; + + err: + trn_cell_extension_field_free(field); + trn_cell_extension_dos_free(dos_ext); + return -1; } /* ========== */ -- cgit v1.2.3-54-g00ecf From 9915b8f0bc3e6a1b6c8413fbb87c41137ea89104 Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Thu, 17 Oct 2019 16:39:05 +0200 Subject: Handle errors from execve() in the Unix process backend more gracefully. This patch removes a call to tor_assert_unreached() after execve() failed. This assertion leads to the child process emitting a stack trace on its standard output, which makes the error harder for the user to demystify, since they think it is an internal error in Tor instead of "just" being a "no such file or directory" error. The process will now instead output "Error from child process: X" where X is the stringified version of the errno value. See: https://bugs.torproject.org/31810 --- changes/bug31810 | 4 ++++ src/lib/process/process_unix.c | 9 +-------- 2 files changed, 5 insertions(+), 8 deletions(-) create mode 100644 changes/bug31810 (limited to 'changes') diff --git a/changes/bug31810 b/changes/bug31810 new file mode 100644 index 0000000000..628d12f09b --- /dev/null +++ b/changes/bug31810 @@ -0,0 +1,4 @@ + o Minor bugfixes (process management): + - Remove assertion in the Unix process backend. This assertion would trigger + when a new process is spawned where the executable is not found leading to + a stack trace from the child process. Fixes bug 31810; bugfix on 0.4.0.1-alpha. diff --git a/src/lib/process/process_unix.c b/src/lib/process/process_unix.c index 790ab897e9..b102afff44 100644 --- a/src/lib/process/process_unix.c +++ b/src/lib/process/process_unix.c @@ -253,22 +253,15 @@ process_unix_exec(process_t *process) process_environment_t *env = process_get_environment(process); /* Call the requested program. */ - retval = execve(argv[0], argv, env->unixoid_environment_block); + execve(argv[0], argv, env->unixoid_environment_block); /* If we made it here it is because execve failed :-( */ - if (-1 == retval) - fprintf(stderr, "Call to execve() failed: %s", strerror(errno)); - tor_free(argv); process_environment_free(env); - tor_assert_unreached(); - error: - /* LCOV_EXCL_START */ fprintf(stderr, "Error from child process: %s", strerror(errno)); _exit(1); - /* LCOV_EXCL_STOP */ } /* We are in the parent process. */ -- cgit v1.2.3-54-g00ecf From 85b4a5c27659a7d162c2e476e1e0dfbeefd73095 Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Thu, 17 Oct 2019 16:39:05 +0200 Subject: Handle errors from execve() in the Unix process backend more gracefully. This patch removes a call to tor_assert_unreached() after execve() failed. This assertion leads to the child process emitting a stack trace on its standard output, which makes the error harder for the user to demystify, since they think it is an internal error in Tor instead of "just" being a "no such file or directory" error. The process will now instead output "Error from child process: X" where X is the stringified version of the errno value. See: https://bugs.torproject.org/31810 --- changes/bug31810 | 4 ++++ src/lib/process/process_unix.c | 9 +-------- 2 files changed, 5 insertions(+), 8 deletions(-) create mode 100644 changes/bug31810 (limited to 'changes') diff --git a/changes/bug31810 b/changes/bug31810 new file mode 100644 index 0000000000..628d12f09b --- /dev/null +++ b/changes/bug31810 @@ -0,0 +1,4 @@ + o Minor bugfixes (process management): + - Remove assertion in the Unix process backend. This assertion would trigger + when a new process is spawned where the executable is not found leading to + a stack trace from the child process. Fixes bug 31810; bugfix on 0.4.0.1-alpha. diff --git a/src/lib/process/process_unix.c b/src/lib/process/process_unix.c index 332b432c54..8191bdc1f0 100644 --- a/src/lib/process/process_unix.c +++ b/src/lib/process/process_unix.c @@ -253,22 +253,15 @@ process_unix_exec(process_t *process) process_environment_t *env = process_get_environment(process); /* Call the requested program. */ - retval = execve(argv[0], argv, env->unixoid_environment_block); + execve(argv[0], argv, env->unixoid_environment_block); /* If we made it here it is because execve failed :-( */ - if (-1 == retval) - fprintf(stderr, "Call to execve() failed: %s", strerror(errno)); - tor_free(argv); process_environment_free(env); - tor_assert_unreached(); - error: - /* LCOV_EXCL_START */ fprintf(stderr, "Error from child process: %s", strerror(errno)); _exit(1); - /* LCOV_EXCL_STOP */ } /* We are in the parent process. */ -- cgit v1.2.3-54-g00ecf From 389b37246eb6310401bfc3bcb80ee2fb8dcac56b Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Tue, 24 Sep 2019 16:42:00 +0200 Subject: Remove overly strict assertions in transports.c. This patch removes an overly strict tor_assert() and an ignorable BUG() expression. Both of these would trigger if a PT was unable to configure itself during startup. The easy way to trigger this is to configure an obfs4 bridge where you make the obfs4 process try to bind on a port number under 1024. See: https://bugs.torproject.org/31091 --- changes/ticket31091 | 3 +++ src/feature/client/transports.c | 6 ++---- 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 changes/ticket31091 (limited to 'changes') diff --git a/changes/ticket31091 b/changes/ticket31091 new file mode 100644 index 0000000000..3cb9a2c37b --- /dev/null +++ b/changes/ticket31091 @@ -0,0 +1,3 @@ + o Minor bugfixes (pluggable transports): + - Remove overly strict assertions that triggers when a pluggable transport + is spawned in an unsuccessful manner. Fixes bug 31091; bugfix on 0.4.0.1-alpha. diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c index e7ff3bf34a..f34d4af480 100644 --- a/src/feature/client/transports.c +++ b/src/feature/client/transports.c @@ -1826,15 +1826,13 @@ managed_proxy_stdout_callback(process_t *process, managed_proxy_t *mp = process_get_data(process); - if (BUG(mp == NULL)) + if (mp == NULL) return; handle_proxy_line(line, mp); - if (proxy_configuration_finished(mp)) { + if (proxy_configuration_finished(mp)) handle_finished_proxy(mp); - tor_assert(mp->conf_state == PT_PROTO_COMPLETED); - } } /** Callback function that is called when our PT process have data on its -- cgit v1.2.3-54-g00ecf From b3fc3b609bb222ecbd1dd8a28993f3b19dc8bfd4 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 18 Oct 2019 17:26:09 +1000 Subject: changes: file for 32124. --- changes/bug32124 | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 changes/bug32124 (limited to 'changes') diff --git a/changes/bug32124 b/changes/bug32124 new file mode 100644 index 0000000000..164b33c7e3 --- /dev/null +++ b/changes/bug32124 @@ -0,0 +1,7 @@ + o Minor bugfixes (build system): + - Stop failing when jemalloc is requested, but tcmalloc is not found. + Fixes bug 32124; bugfix on 0.3.5.1-alpha. + - Interpret --disable-module-dirauth=no correctly. + Fixes bug 32124; bugfix on 0.3.4.1-alpha. + - Interpret --with-tcmalloc=no correctly. + Fixes bug 32124; bugfix on 0.2.0.20-rc. -- cgit v1.2.3-54-g00ecf From a7ccd9a997bc85c0e03926b7d24f7e05a4a51d39 Mon Sep 17 00:00:00 2001 From: Roger Dingledine Date: Mon, 21 Oct 2019 04:14:42 -0400 Subject: respect accountingmax during soft hibernation Relays now respect their AccountingMax bandwidth again. When relays entered "soft" hibernation (which typically starts when we've hit 90% of our AccountingMax), we had stopped checking whether we should enter hard hibernation. Soft hibernation refuses new connections and new circuits, but the existing circuits can continue, meaning that relays could have exceeded their configured AccountingMax. This commit rolls back some of the cpu-saving fixes, where we tried to avoid calling so many of our events while we're off the network. That's because PERIODIC_EVENT_FLAG_NEED_NET checks net_is_disabled(), which returns true even if we're only in soft hibernation. Fixes bug 32108; bugfix on 0.4.0.1-alpha. --- changes/bug32108 | 8 ++++++++ src/core/mainloop/mainloop.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 changes/bug32108 (limited to 'changes') diff --git a/changes/bug32108 b/changes/bug32108 new file mode 100644 index 0000000000..2806fa3e5d --- /dev/null +++ b/changes/bug32108 @@ -0,0 +1,8 @@ + o Major bugfixes (relay): + - Relays now respect their AccountingMax bandwidth again. When relays + entered "soft" hibernation (which typically starts when we've hit + 90% of our AccountingMax), we had stopped checking whether we should + enter hard hibernation. Soft hibernation refuses new connections and + new circuits, but the existing circuits can continue, meaning that + relays could have exceeded their configured AccountingMax. Fixes + bug 32108; bugfix on 0.4.0.1-alpha. diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c index 18e87fa87a..193df61d01 100644 --- a/src/core/mainloop/mainloop.c +++ b/src/core/mainloop/mainloop.c @@ -1397,7 +1397,7 @@ STATIC periodic_event_item_t periodic_events[] = { /* This is a legacy catch-all callback that runs once per second if * we are online and active. */ CALLBACK(second_elapsed, NET_PARTICIPANT, - FL(NEED_NET)|FL(RUN_ON_DISABLE)), + FL(RUN_ON_DISABLE)), /* XXXX Do we have a reason to do this on a callback? Does it do any good at * all? For now, if we're dormant, we can let our listeners decay. */ -- cgit v1.2.3-54-g00ecf From 4233fb7014b0ef5a6830f36608e1779299e07cd8 Mon Sep 17 00:00:00 2001 From: Roger Dingledine Date: Wed, 16 Oct 2019 06:13:14 -0400 Subject: clarify in man page: we count by powers of two Make clear in the man page, in both the bandwidth section and the accountingmax section, that Tor counts in powers of two, not powers of ten: 1 GByte is 1024*1024*1024 bytes, not one billion bytes. Resolves ticket 32106. --- changes/bug32106 | 5 +++++ doc/tor.1.txt | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 changes/bug32106 (limited to 'changes') diff --git a/changes/bug32106 b/changes/bug32106 new file mode 100644 index 0000000000..c6e8e95860 --- /dev/null +++ b/changes/bug32106 @@ -0,0 +1,5 @@ + o Minor features (documentation): + - Make clear in the man page, in both the bandwidth section and the + accountingmax section, that Tor counts in powers of two, not + powers of ten: 1 GByte is 1024*1024*1024 bytes, not one billion + bytes. Resolves ticket 32106. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 6b81e19ba1..be0a1ed928 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -210,11 +210,15 @@ GENERAL OPTIONS + Note that this option, and other bandwidth-limiting options, apply to TCP data only: They do not count TCP headers or DNS traffic. + + + + Tor uses powers of two, not powers of ten, so 1 GByte is + 1024*1024*1024 bytes as opposed to 1 billion bytes. + + With this option, and in other options that take arguments in bytes, KBytes, and so on, other formats are also supported. Notably, "KBytes" can also be written as "kilobytes" or "kb"; "MBytes" can be written as "megabytes" or "MB"; "kbits" can be written as "kilobits"; and so forth. + Case doesn't matter. Tor also accepts "byte" and "bit" in the singular. The prefixes "tera" and "T" are also recognized. If no units are given, we default to bytes. @@ -2292,9 +2296,9 @@ is non-zero): using a given calculation rule (see: AccountingStart, AccountingRule). Useful if you need to stay under a specific bandwidth. By default, the number used for calculation is the max of either the bytes sent or - received. For example, with AccountingMax set to 1 GByte, a server - could send 900 MBytes and receive 800 MBytes and continue running. - It will only hibernate once one of the two reaches 1 GByte. This can + received. For example, with AccountingMax set to 1 TByte, a server + could send 900 GBytes and receive 800 GBytes and continue running. + It will only hibernate once one of the two reaches 1 TByte. This can be changed to use the sum of the both bytes received and sent by setting the AccountingRule option to "sum" (total bandwidth in/out). When the number of bytes remaining gets low, Tor will stop accepting new connections @@ -2305,7 +2309,12 @@ is non-zero): enabling hibernation is preferable to setting a low bandwidth, since it provides users with a collection of fast servers that are up some of the time, which is more useful than a set of slow servers that are - always "available". + always "available". + + + + Note that (as also described in the Bandwidth section) Tor uses + powers of two, not powers of ten: 1 GByte is 1024*1024*1024, not + one billion. Be careful: some internet service providers might count + GBytes differently. [[AccountingRule]] **AccountingRule** **sum**|**max**|**in**|**out**:: How we determine when our AccountingMax has been reached (when we -- cgit v1.2.3-54-g00ecf From f3c0a0b9fe2791571dd483ac28a73fc4776169a8 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 29 Aug 2019 11:43:43 -0400 Subject: Authorities reject relays running unsupported Tor release series. Our minimum version is now 0.2.9.5-alpha. Series 0.3.0, 0.3.1, 0.3.2, 0.3.3, and 0.3.4 are now rejected. Also, extract this version-checking code into a new function, so we can test it. Closes ticket 31549. Also reject 0.3.5.0 through 0.3.5.6-rc as unstable. --- changes/ticket31549 | 4 +++ src/feature/dirauth/process_descs.c | 59 +++++++++++++++++++++++++++---------- 2 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 changes/ticket31549 (limited to 'changes') diff --git a/changes/ticket31549 b/changes/ticket31549 new file mode 100644 index 0000000000..2c27aca4fb --- /dev/null +++ b/changes/ticket31549 @@ -0,0 +1,4 @@ + o Minor features (authority): + - Directory authorities now reject relays running all currently + deprecated release series. The currently supported release series + are: 0.2.9, 0.3.5, 0.4.0, 0.4.1, and 0.4.2. Closes ticket 31549. diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c index 21b8e239ec..c5fda80c05 100644 --- a/src/feature/dirauth/process_descs.c +++ b/src/feature/dirauth/process_descs.c @@ -310,6 +310,47 @@ dirserv_would_reject_router(const routerstatus_t *rs) return (res & FP_REJECT) != 0; } +/** + * Check whether the platform string in platform describes a platform + * that, as a directory authority, we want to reject. If it does, return + * true, and set *msg (if present) to a rejection message. Otherwise + * return false. + */ +static bool +dirserv_rejects_tor_version(const char *platform, + const char **msg) +{ + if (!platform) + return false; + + static const char please_upgrade_string[] = + "Tor version is insecure or unsupported. Please upgrade!"; + + /* Versions before Tor 0.2.9 are unsupported. Versions between 0.2.9.0 and + * 0.2.9.4 suffer from bug #20499, where relays don't keep their consensus + * up to date */ + if (!tor_version_as_new_as(platform,"0.2.9.5-alpha")) { + if (msg) + *msg = please_upgrade_string; + return true; + } + + /* Series between Tor 0.3.0 and 0.3.4 inclusive are unsupported, and some + * have bug #27841, which makes them broken as intro points. Reject them. + * + * Also reject unstable versions of 0.3.5, since (as of this writing) + * they are almost none of the network. */ + if (tor_version_as_new_as(platform,"0.3.0.0-alpha-dev") && + !tor_version_as_new_as(platform,"0.3.5.7")) { + if (msg) { + *msg = please_upgrade_string; + } + return true; + } + + return false; +} + /** Helper: As dirserv_router_get_status, but takes the router fingerprint * (hex, no spaces), nickname, address (used for logging only), IP address, OR * port and platform (logging only) as arguments. @@ -342,22 +383,8 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname, } } - /* Versions before Tor 0.2.4.18-rc are too old to support, and are - * missing some important security fixes too. Disable them. */ - if (platform && !tor_version_as_new_as(platform,"0.2.4.18-rc")) { - if (msg) - *msg = "Tor version is insecure or unsupported. Please upgrade!"; - return FP_REJECT; - } - - /* Tor 0.2.9.x where x<5 suffers from bug #20499, where relays don't - * keep their consensus up to date so they make bad guards. - * The simple fix is to just drop them from the network. */ - if (platform && - tor_version_as_new_as(platform,"0.2.9.0-alpha") && - !tor_version_as_new_as(platform,"0.2.9.5-alpha")) { - if (msg) - *msg = "Tor version contains bug 20499. Please upgrade!"; + /* Check whether the version is obsolete, broken, insecure, etc... */ + if (platform && dirserv_rejects_tor_version(platform, msg)) { return FP_REJECT; } -- cgit v1.2.3-54-g00ecf From 09468cc58b52132af1232e2cd3925c273382bba6 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 24 Oct 2019 11:08:25 -0400 Subject: dir: Look if circuit is closed in connection_dir_is_anonymous() Before inspecting the p_chan, we must check if the circuit is marked for close because if it is the case, the channels are nullified from the circuit. Several valid cases can mark the circuit for close of the directory connection. Fixes #31958 Signed-off-by: David Goulet --- changes/ticket31958 | 5 +++++ src/feature/dircommon/directory.c | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 changes/ticket31958 (limited to 'changes') diff --git a/changes/ticket31958 b/changes/ticket31958 new file mode 100644 index 0000000000..8206064dfe --- /dev/null +++ b/changes/ticket31958 @@ -0,0 +1,5 @@ + o Minor bugfixes (directory): + - When checking if a directory connection is anonymous, test if the circuit + was marked for close before looking at its channel. This avoids a BUG() + stacktrace in case it was previously closed. Fixes bug 31958; bugfix on + 0.4.2.1-alpha. diff --git a/src/feature/dircommon/directory.c b/src/feature/dircommon/directory.c index b3db0aa108..1ac35dd8b5 100644 --- a/src/feature/dircommon/directory.c +++ b/src/feature/dircommon/directory.c @@ -225,7 +225,17 @@ connection_dir_is_anonymous(const dir_connection_t *dir_conn) return false; } - /* Get the previous channel to learn if it is a client or relay link. */ + /* It is possible that the circuit was closed because one of the channel was + * closed or a DESTROY cell was received. Either way, this connection can + * not continue so return that it is not anonymous since we can not know for + * sure if it is. */ + if (circ->marked_for_close) { + return false; + } + + /* Get the previous channel to learn if it is a client or relay link. We + * BUG() because if the circuit is not mark for close, we ought to have a + * p_chan else we have a code flow issue. */ if (BUG(CONST_TO_OR_CIRCUIT(circ)->p_chan == NULL)) { log_info(LD_DIR, "Rejected HSDir request: no p_chan"); return false; -- cgit v1.2.3-54-g00ecf From 2a349006b9c1feba0a29ede4838cf8f5fdc0b2e5 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 29 Oct 2019 21:13:56 +0100 Subject: force pkg-config to only use --prefix when cross-compiling The current pkg-config setup has no sense of whether it is cross-compiling, so it will detect things on the build system that are not present or are wrong for the host system. This forces the cross-compiling build to only look for pkg-config .pc files in --prefix. A version of this has been the setup for many years with the Android builds. Fixes #32191 Signed-off-by: Hans-Christoph Steiner --- changes/ticket32191 | 3 +++ configure.ac | 10 ++++++++++ 2 files changed, 13 insertions(+) create mode 100644 changes/ticket32191 (limited to 'changes') diff --git a/changes/ticket32191 b/changes/ticket32191 new file mode 100644 index 0000000000..65e919fe03 --- /dev/null +++ b/changes/ticket32191 @@ -0,0 +1,3 @@ + o Minor features (build system): + - force pkg-config to only use --prefix when cross-compiling. + Closes ticket 32191. diff --git a/configure.ac b/configure.ac index 0e9bfe1f6b..ece831d5bd 100644 --- a/configure.ac +++ b/configure.ac @@ -37,6 +37,16 @@ else pkg_config_user_action="check the PKG_CONFIG_PATH environment variable" fi +if test "x$PKG_CONFIG_PATH" = "x" && test "x$prefix" != "xNONE" && test "$host" != "$build"; then + export PKG_CONFIG_PATH=$prefix/lib/pkgconfig + AC_MSG_NOTICE([set PKG_CONFIG_PATH=$PKG_CONFIG_PATH to support cross-compiling]) + if test -f "$PKG_CONFIG_PATH/libevent.pc"; then + echo "checking for $PKG_CONFIG_PATH/libevent.pc... yes" + else + AC_MSG_ERROR([$PKG_CONFIG_PATH/libevent.pc not found!]) + fi +fi + AC_ARG_ENABLE(openbsd-malloc, AS_HELP_STRING(--enable-openbsd-malloc, [use malloc code from OpenBSD. Linux only. Deprecated: see --with-malloc])) AC_ARG_ENABLE(static-openssl, -- cgit v1.2.3-54-g00ecf From 804d7c9bfc916c430dfd353f742257e4ae7b9c38 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 5 Nov 2019 15:48:01 +1000 Subject: configure: Remove a check that will always fail And update the changes file to be more specific. Part of 32191. --- changes/ticket32191 | 4 ++-- configure.ac | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'changes') diff --git a/changes/ticket32191 b/changes/ticket32191 index 65e919fe03..6988328115 100644 --- a/changes/ticket32191 +++ b/changes/ticket32191 @@ -1,3 +1,3 @@ o Minor features (build system): - - force pkg-config to only use --prefix when cross-compiling. - Closes ticket 32191. + - Make pkg-config use --prefix when cross-compiling, if PKG_CONFIG_PATH + is not set. Closes ticket 32191. diff --git a/configure.ac b/configure.ac index ece831d5bd..caa2d2f7c4 100644 --- a/configure.ac +++ b/configure.ac @@ -40,11 +40,6 @@ fi if test "x$PKG_CONFIG_PATH" = "x" && test "x$prefix" != "xNONE" && test "$host" != "$build"; then export PKG_CONFIG_PATH=$prefix/lib/pkgconfig AC_MSG_NOTICE([set PKG_CONFIG_PATH=$PKG_CONFIG_PATH to support cross-compiling]) - if test -f "$PKG_CONFIG_PATH/libevent.pc"; then - echo "checking for $PKG_CONFIG_PATH/libevent.pc... yes" - else - AC_MSG_ERROR([$PKG_CONFIG_PATH/libevent.pc not found!]) - fi fi AC_ARG_ENABLE(openbsd-malloc, -- cgit v1.2.3-54-g00ecf From 10ef7a31cfa896fb8a4eddde92c4b7d1e7477ad6 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 6 Nov 2019 12:29:35 +1000 Subject: Makefile: Fix "make check-includes" for out-of-tree builds Previously, it would run on the build tree, which did not contain any sources. Fixes bug 31335; bugfix on 0.3.5.1-alpha. --- Makefile.am | 2 +- changes/bug31335 | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/bug31335 (limited to 'changes') diff --git a/Makefile.am b/Makefile.am index 485324fc79..03593df161 100644 --- a/Makefile.am +++ b/Makefile.am @@ -370,7 +370,7 @@ endif check-includes: if USEPYTHON - $(PYTHON) $(top_srcdir)/scripts/maint/practracker/includes.py + $(PYTHON) $(top_srcdir)/scripts/maint/practracker/includes.py $(top_srcdir) endif check-best-practices: diff --git a/changes/bug31335 b/changes/bug31335 new file mode 100644 index 0000000000..f633cf8b24 --- /dev/null +++ b/changes/bug31335 @@ -0,0 +1,3 @@ + o Minor bugfixes (code quality): + - Fix "make check-includes" so it runs correctly on out-of-tree builds. + Fixes bug 31335; bugfix on 0.3.5.1-alpha. -- cgit v1.2.3-54-g00ecf From 57baea701f8852b94d8ebc3fd8e70ccc998f5036 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 6 Nov 2019 15:40:39 +1000 Subject: shellcheck: Start checking most scripts for errors This check was accidentally disabled by a bad find command. Fixes bug 32402; bugfix on 0.4.2.1-alpha. Obviously correct changes to already reviewed code. --- changes/bug32402 | 3 +++ scripts/maint/checkShellScripts.sh | 6 +----- 2 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 changes/bug32402 (limited to 'changes') diff --git a/changes/bug32402 b/changes/bug32402 new file mode 100644 index 0000000000..0654389be3 --- /dev/null +++ b/changes/bug32402 @@ -0,0 +1,3 @@ + o Minor bugfixes (shellcheck): + - Start checking most scripts for shellcheck errors again. + Fixes bug 32402; bugfix on 0.4.2.1-alpha. diff --git a/scripts/maint/checkShellScripts.sh b/scripts/maint/checkShellScripts.sh index 318f0fb577..4c872c7ee0 100755 --- a/scripts/maint/checkShellScripts.sh +++ b/scripts/maint/checkShellScripts.sh @@ -35,12 +35,8 @@ if [ ! -d "$TOPLEVEL/src" ]; then fi # Check *.sh scripts, but ignore the ones that we can't fix -find "$TOPLEVEL" \ +find "$TOPLEVEL/contrib" "$TOPLEVEL/doc" "$TOPLEVEL/scripts" "$TOPLEVEL/src" \ -name "*.sh" \ - -path "$TOPLEVEL/contrib/*" \ - -path "$TOPLEVEL/doc/*" \ - -path "$TOPLEVEL/scripts/*" \ - -path "$TOPLEVEL/src/*" \ -not -path "$TOPLEVEL/src/ext/*" \ -not -path "$TOPLEVEL/src/rust/registry/*" \ -exec shellcheck {} + -- cgit v1.2.3-54-g00ecf From 7f23d47f723edeea206d5438af3d109dbb4ac835 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 6 Nov 2019 15:52:18 +1000 Subject: shellcheck: Fix issues in the git-*.sh scripts Fixes bug 32402; bugfix on 0.4.2.1-alpha. Obviously correct changes to already reviewed code. --- changes/bug32402_git_scripts | 3 +++ scripts/git/git-merge-forward.sh | 2 +- scripts/git/git-pull-all.sh | 2 +- scripts/git/git-push-all.sh | 21 +++++++++++---------- 4 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 changes/bug32402_git_scripts (limited to 'changes') diff --git a/changes/bug32402_git_scripts b/changes/bug32402_git_scripts new file mode 100644 index 0000000000..2b10a8998a --- /dev/null +++ b/changes/bug32402_git_scripts @@ -0,0 +1,3 @@ + o Minor bugfixes (shellcheck): + - Fix minor shellcheck errors in the git-*.sh scripts. + Fixes bug 32402; bugfix on 0.4.2.1-alpha. diff --git a/scripts/git/git-merge-forward.sh b/scripts/git/git-merge-forward.sh index e481b40975..bdd0da5b75 100755 --- a/scripts/git/git-merge-forward.sh +++ b/scripts/git/git-merge-forward.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -SCRIPT_NAME=`basename $0` +SCRIPT_NAME=$(basename "$0") function usage() { diff --git a/scripts/git/git-pull-all.sh b/scripts/git/git-pull-all.sh index 0d6daf432d..dc16066388 100755 --- a/scripts/git/git-pull-all.sh +++ b/scripts/git/git-pull-all.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -SCRIPT_NAME=`basename $0` +SCRIPT_NAME=$(basename "$0") function usage() { diff --git a/scripts/git/git-push-all.sh b/scripts/git/git-push-all.sh index a388f01564..7c43fe24d8 100755 --- a/scripts/git/git-push-all.sh +++ b/scripts/git/git-push-all.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -SCRIPT_NAME=`basename $0` +SCRIPT_NAME=$(basename "$0") function usage() { @@ -237,7 +237,7 @@ if [ "$PUSH_SAME" -eq 0 ] && [ "$TEST_BRANCH_PREFIX" ]; then fi done if [ "$SKIP_UPSTREAM" ]; then - printf "Skipping unchanged: %s remote: %s\n" \ + printf "Skipping unchanged: %s remote: %s\\n" \ "$b" "$SKIP_UPSTREAM" else if [ "$NEW_PUSH_BRANCHES" ]; then @@ -261,18 +261,19 @@ if [ "$PUSH_DELAY" -le 0 ]; then $GIT_PUSH "$@" "$UPSTREAM_REMOTE" $PUSH_BRANCHES else # Push the branches in optimal CI order, with a delay between each push - PUSH_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\n" | sort -V) - MASTER_BRANCH=$(echo "$PUSH_BRANCHES" | tr " " "\n" | grep master) + PUSH_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | sort -V) + MASTER_BRANCH=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep master) if [ -z "$TEST_BRANCH_PREFIX" ]; then - MAINT_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\n" | grep maint) - RELEASE_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\n" | grep release | \ - tr "\n" " ") - printf "Pushing with %ss delays, so CI runs in this order:\n%s\n%s\n%s\n" \ + MAINT_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep maint) + RELEASE_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep release | \ + tr "\\n" " ") + printf \ + "Pushing with %ss delays, so CI runs in this order:\\n%s\\n%s\\n%s\\n" \ "$PUSH_DELAY" "$MASTER_BRANCH" "$MAINT_BRANCHES" "$RELEASE_BRANCHES" else # Actually test branches based on maint branches - MAINT_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\n" | grep -v master) - printf "Pushing with %ss delays, so CI runs in this order:\n%s\n%s\n" \ + MAINT_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep -v master) + printf "Pushing with %ss delays, so CI runs in this order:\\n%s\\n%s\\n" \ "$PUSH_DELAY" "$MASTER_BRANCH" "$MAINT_BRANCHES" # No release branches RELEASE_BRANCHES= -- cgit v1.2.3-54-g00ecf From 2ee04fc309b8f4fb3c34271587ab47addaff32ae Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 11 Nov 2019 11:59:50 +1000 Subject: config: Log the option name when skipping an obsolete option This is a basic fix for 0.4.2 only. The fix for 0.4.3 and later is in 32404. Fixes bug 32295; bugfix on 0.4.2.1-alpha. --- changes/bug32295 | 3 +++ src/lib/confmgt/type_defs.c | 39 ++++++++++++++++++++++++++------------- src/lib/confmgt/typedvar.c | 11 ++++++----- src/lib/confmgt/typedvar.h | 2 +- src/lib/confmgt/var_type_def_st.h | 5 ++++- 5 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 changes/bug32295 (limited to 'changes') diff --git a/changes/bug32295 b/changes/bug32295 new file mode 100644 index 0000000000..e5e5a4399d --- /dev/null +++ b/changes/bug32295 @@ -0,0 +1,3 @@ + o Minor bugfixes (configuration): + - Log the option name when skipping an obsolete option. + Fixes bug 32295; bugfix on 0.4.2.1-alpha. diff --git a/src/lib/confmgt/type_defs.c b/src/lib/confmgt/type_defs.c index ed930fb02a..5066e12265 100644 --- a/src/lib/confmgt/type_defs.c +++ b/src/lib/confmgt/type_defs.c @@ -52,10 +52,11 @@ static int string_parse(void *target, const char *value, char **errmsg, - const void *params) + const void *params, const char *key) { (void)params; (void)errmsg; + (void)key; char **p = (char**)target; *p = tor_strdup(value); return 0; @@ -106,8 +107,10 @@ static const int_parse_params_t INT_PARSE_POSINT = { }; static int -int_parse(void *target, const char *value, char **errmsg, const void *params) +int_parse(void *target, const char *value, char **errmsg, const void *params, + const char *key) { + (void)key; const int_parse_params_t *pp; if (params) { pp = params; @@ -169,10 +172,11 @@ static const var_type_fns_t int_fns = { static int uint64_parse(void *target, const char *value, char **errmsg, - const void *params) + const void *params, const char *key) { (void)params; (void)errmsg; + (void)key; uint64_t *p = target; int ok=0; *p = tor_parse_uint64(value, 10, 0, UINT64_MAX, &ok, NULL); @@ -219,8 +223,9 @@ static const var_type_fns_t uint64_fns = { static int units_parse_u64(void *target, const char *value, char **errmsg, - const void *params) + const void *params, const char *key) { + (void)key; const unit_table_t *table = params; tor_assert(table); uint64_t *v = (uint64_t*)target; @@ -235,8 +240,9 @@ units_parse_u64(void *target, const char *value, char **errmsg, static int units_parse_int(void *target, const char *value, char **errmsg, - const void *params) + const void *params, const char *key) { + (void)key; const unit_table_t *table = params; tor_assert(table); int *v = (int*)target; @@ -283,10 +289,11 @@ static const var_type_fns_t interval_fns = { static int double_parse(void *target, const char *value, char **errmsg, - const void *params) + const void *params, const char *key) { (void)params; (void)errmsg; + (void)key; double *v = (double*)target; char *endptr=NULL; errno = 0; @@ -347,8 +354,9 @@ typedef struct enumeration_table_t { static int enum_parse(void *target, const char *value, char **errmsg, - const void *params) + const void *params, const char *key) { + (void)key; const enumeration_table_t *table = params; int *p = (int *)target; for (; table->name; ++table) { @@ -422,9 +430,10 @@ static const var_type_fns_t enum_fns = { static int time_parse(void *target, const char *value, char **errmsg, - const void *params) + const void *params, const char *key) { (void) params; + (void) key; time_t *p = target; if (parse_iso_time(value, p) < 0) { tor_asprintf(errmsg, "Invalid time %s", escaped(value)); @@ -466,10 +475,11 @@ static const var_type_fns_t time_fns = { static int csv_parse(void *target, const char *value, char **errmsg, - const void *params) + const void *params, const char *key) { (void)params; (void)errmsg; + (void)key; smartlist_t **sl = (smartlist_t**)target; *sl = smartlist_new(); smartlist_split_string(*sl, value, ",", @@ -515,7 +525,7 @@ static const var_type_fns_t csv_fns = { static int legacy_csv_interval_parse(void *target, const char *value, char **errmsg, - const void *params) + const void *params, const char *key) { (void)params; /* We used to have entire smartlists here. But now that all of our @@ -529,7 +539,7 @@ legacy_csv_interval_parse(void *target, const char *value, char **errmsg, val = tmp; } - int rv = units_parse_int(target, val, errmsg, &time_units); + int rv = units_parse_int(target, val, errmsg, &time_units, key); tor_free(tmp); return rv; } @@ -693,14 +703,17 @@ static const var_type_fns_t linelist_s_fns = { static int ignore_parse(void *target, const char *value, char **errmsg, - const void *params) + const void *params, const char *key) { (void)target; (void)value; (void)errmsg; (void)params; // XXXX move this to a higher level, once such a level exists. - log_warn(LD_GENERAL, "Skipping obsolete configuration option."); + log_warn(LD_GENERAL, "Skipping obsolete configuration option%s%s%s", + key && *key ? " \"" : "", + key && *key ? key : "", + key && *key ? "\"." : "."); return 0; } diff --git a/src/lib/confmgt/typedvar.c b/src/lib/confmgt/typedvar.c index 219a2d15bc..ce11a69379 100644 --- a/src/lib/confmgt/typedvar.c +++ b/src/lib/confmgt/typedvar.c @@ -33,7 +33,8 @@ /** * Try to parse a string in value that encodes an object of the type - * defined by def. + * defined by def. If not NULL, key is the name of the option, + * which may be used for logging. * * On success, adjust the lvalue pointed to by target to hold that * value, and return 0. On failure, set *errmsg to a newly allocated @@ -41,7 +42,7 @@ **/ int typed_var_assign(void *target, const char *value, char **errmsg, - const var_type_def_t *def) + const var_type_def_t *def, const char *key) { if (BUG(!def)) return -1; // LCOV_EXCL_LINE @@ -49,7 +50,7 @@ typed_var_assign(void *target, const char *value, char **errmsg, typed_var_free(target, def); tor_assert(def->fns->parse); - return def->fns->parse(target, value, errmsg, def->params); + return def->fns->parse(target, value, errmsg, def->params, key); } /** @@ -75,7 +76,7 @@ typed_var_kvassign(void *target, const config_line_t *line, return def->fns->kv_parse(target, line, errmsg, def->params); } - return typed_var_assign(target, line->value, errmsg, def); + return typed_var_assign(target, line->value, errmsg, def, line->key); } /** @@ -158,7 +159,7 @@ typed_var_copy(void *dest, const void *src, const var_type_def_t *def) return 0; } char *err = NULL; - int rv = typed_var_assign(dest, enc, &err, def); + int rv = typed_var_assign(dest, enc, &err, def, NULL); if (BUG(rv < 0)) { // LCOV_EXCL_START log_warn(LD_BUG, "Encoded value %s was not parseable as a %s: %s", diff --git a/src/lib/confmgt/typedvar.h b/src/lib/confmgt/typedvar.h index 22f2e3c58e..4382613833 100644 --- a/src/lib/confmgt/typedvar.h +++ b/src/lib/confmgt/typedvar.h @@ -21,7 +21,7 @@ typedef struct var_type_fns_t var_type_fns_t; typedef struct var_type_def_t var_type_def_t; int typed_var_assign(void *target, const char *value, char **errmsg, - const var_type_def_t *def); + const var_type_def_t *def, const char *key); void typed_var_free(void *target, const var_type_def_t *def); char *typed_var_encode(const void *value, const var_type_def_t *def); int typed_var_copy(void *dest, const void *src, const var_type_def_t *def); diff --git a/src/lib/confmgt/var_type_def_st.h b/src/lib/confmgt/var_type_def_st.h index 2bf3d37cae..aa9ded39e9 100644 --- a/src/lib/confmgt/var_type_def_st.h +++ b/src/lib/confmgt/var_type_def_st.h @@ -52,9 +52,12 @@ struct var_type_fns_t { * type. On success, adjust the lvalue pointed to by target to hold * that value, and return 0. On failure, set *errmsg to a newly * allocated string holding an error message, and return -1. + * + * If not NULL, key is the name of the option, which may be used for + * logging. **/ int (*parse)(void *target, const char *value, char **errmsg, - const void *params); + const void *params, const char *key); /** * Try to parse a single line from the head ofline that encodes * an object of this type. On success and failure, behave as in the parse() -- cgit v1.2.3-54-g00ecf From f86d508d49dd36fede7091635044603741fdd353 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 6 Dec 2019 10:51:05 +1000 Subject: changes: file for 32629 --- changes/ticket32629 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changes/ticket32629 (limited to 'changes') 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. -- cgit v1.2.3-54-g00ecf From 1b619a627ca1ee11d1680dc56e90e9fc1af2ddb5 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 16 Dec 2019 15:14:13 -0500 Subject: Use CHECK_PRINTF() for printf-like functions in util_bug.h --- changes/ticket32765 | 4 ++++ src/lib/log/util_bug.h | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 changes/ticket32765 (limited to 'changes') diff --git a/changes/ticket32765 b/changes/ticket32765 new file mode 100644 index 0000000000..a9663a5df3 --- /dev/null +++ b/changes/ticket32765 @@ -0,0 +1,4 @@ + o Minor bugfixes (correctness checks): + - Use GCC/Clang's printf-checking feature to make sure that + tor_assertf() arguments are correctly typed. Fixes bug 32765; + bugfix on 0.4.1.1-alpha. diff --git a/src/lib/log/util_bug.h b/src/lib/log/util_bug.h index 546ae1e3ef..993a4e3abd 100644 --- a/src/lib/log/util_bug.h +++ b/src/lib/log/util_bug.h @@ -242,10 +242,12 @@ void tor_assertion_failed_(const char *fname, unsigned int line, const char *func, const char *expr, - const char *fmt, ...); + const char *fmt, ...) + CHECK_PRINTF(5,6); void tor_bug_occurred_(const char *fname, unsigned int line, const char *func, const char *expr, - int once, const char *fmt, ...); + int once, const char *fmt, ...) + CHECK_PRINTF(6,7); void tor_abort_(void) ATTR_NORETURN; -- cgit v1.2.3-54-g00ecf From b4977d1aa9366cdb1475664bcf1486fbfdf5a166 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 16 Dec 2019 15:31:23 -0500 Subject: Fix formatting in tor_assertf() message in struct_check_magic(). Closes 32771; bugfix on 0.4.2.1-alpha. --- changes/bug32771 | 4 ++++ src/lib/confmgt/structvar.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 changes/bug32771 (limited to 'changes') diff --git a/changes/bug32771 b/changes/bug32771 new file mode 100644 index 0000000000..606bcf4be4 --- /dev/null +++ b/changes/bug32771 @@ -0,0 +1,4 @@ + o Minor bugfixes (logging, crash): + - Avoid a possible crash when trying to log a (fatal) assertion failure + about mismatched magic numbers in configuration objects. Fixes bug 32771; + bugfix on 0.4.2.1-alpha. diff --git a/src/lib/confmgt/structvar.c b/src/lib/confmgt/structvar.c index de678d18c8..7a3b8c7df2 100644 --- a/src/lib/confmgt/structvar.c +++ b/src/lib/confmgt/structvar.c @@ -53,8 +53,8 @@ struct_check_magic(const void *object, const struct_magic_decl_t *decl) const uint32_t *ptr = STRUCT_VAR_P(object, decl->magic_offset); tor_assertf(*ptr == decl->magic_val, "Bad magic number on purported %s object. " - "Expected %"PRIu32"x but got "PRIu32"x.", - decl->magic_val, *ptr); + "Expected %"PRIu32"x but got %"PRIu32"x.", + decl->typename, decl->magic_val, *ptr); } /** -- cgit v1.2.3-54-g00ecf From b9d81282e0dbfdae795b38c26879716d7860bcf9 Mon Sep 17 00:00:00 2001 From: Peter Gerber Date: Sun, 5 Jan 2020 15:48:54 +0100 Subject: Fix sandbox crash during reload of logging configuration Allow calls to dup() which was introduced in commit a22fbab986. From a security perspective, I don't think this should impact the security of the sandbox significantly. As far as I can tell, there is nothing an adversary can do with a duplicated FD that can't be done with the original. --- changes/bug32877 | 4 ++++ src/lib/sandbox/sandbox.c | 1 + 2 files changed, 5 insertions(+) create mode 100644 changes/bug32877 (limited to 'changes') diff --git a/changes/bug32877 b/changes/bug32877 new file mode 100644 index 0000000000..96fe1af708 --- /dev/null +++ b/changes/bug32877 @@ -0,0 +1,4 @@ +o Minor bugfixes (linux seccomp sandbox): + - Fix crash when reloading logging configuration while the + experimental sandbox is enabled. Fixes bug 29150; bugfix + on 0.4.1.7. Patch by Peter Gerber. diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index faaf463f29..7e6354d880 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -143,6 +143,7 @@ static int filter_nopar_gen[] = { SCMP_SYS(clock_gettime), SCMP_SYS(close), SCMP_SYS(clone), + SCMP_SYS(dup), SCMP_SYS(epoll_create), SCMP_SYS(epoll_wait), #ifdef __NR_epoll_pwait -- cgit v1.2.3-54-g00ecf From f5461a4bdf343a0572b0594fa33af37ce1be9d8f Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 6 Jan 2020 08:08:48 -0500 Subject: update changes file to pass "make check-changes" --- changes/bug32841 | 4 ++++ changes/bug32877 | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 changes/bug32841 delete mode 100644 changes/bug32877 (limited to 'changes') diff --git a/changes/bug32841 b/changes/bug32841 new file mode 100644 index 0000000000..48568f6a61 --- /dev/null +++ b/changes/bug32841 @@ -0,0 +1,4 @@ + o Minor bugfixes (linux seccomp sandbox): + - Fix crash when reloading logging configuration while the + experimental sandbox is enabled. Fixes bug 32841; bugfix + on 0.4.1.7. Patch by Peter Gerber. diff --git a/changes/bug32877 b/changes/bug32877 deleted file mode 100644 index 96fe1af708..0000000000 --- a/changes/bug32877 +++ /dev/null @@ -1,4 +0,0 @@ -o Minor bugfixes (linux seccomp sandbox): - - Fix crash when reloading logging configuration while the - experimental sandbox is enabled. Fixes bug 29150; bugfix - on 0.4.1.7. Patch by Peter Gerber. -- cgit v1.2.3-54-g00ecf From 54eec5342d45e9add5b9a8fee0167267c38f63f9 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 6 Jan 2020 08:45:29 -0500 Subject: Initialize publish/subscribe code when running as an NT service. Fixes bug 32778; bugfix on 0.4.1.1-alpha. --- changes/bug32778 | 3 +++ src/app/main/main.c | 4 ++-- src/app/main/main.h | 3 +++ src/app/main/ntmain.c | 7 +++++++ 4 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 changes/bug32778 (limited to 'changes') diff --git a/changes/bug32778 b/changes/bug32778 new file mode 100644 index 0000000000..ccb6104692 --- /dev/null +++ b/changes/bug32778 @@ -0,0 +1,3 @@ + o Minor bugfixes (windows service): + - Initialize publish/subscribe system when running as a windows service. + Fixes bug 32778; bugfix on 0.4.1.1-alpha. diff --git a/src/app/main/main.c b/src/app/main/main.c index 6e325f0b10..f3772f86e4 100644 --- a/src/app/main/main.c +++ b/src/app/main/main.c @@ -1236,7 +1236,7 @@ run_tor_main_loop(void) } /** Install the publish/subscribe relationships for all the subsystems. */ -static void +void pubsub_install(void) { pubsub_builder_t *builder = pubsub_builder_new(); @@ -1248,7 +1248,7 @@ pubsub_install(void) /** Connect the mainloop to its publish/subscribe message delivery events if * appropriate, and configure the global channels appropriately. */ -static void +void pubsub_connect(void) { if (get_options()->command == CMD_RUN_TOR) { diff --git a/src/app/main/main.h b/src/app/main/main.h index 9dfaf4b8ef..76574a9071 100644 --- a/src/app/main/main.h +++ b/src/app/main/main.h @@ -25,4 +25,7 @@ int tor_init(int argc, char **argv); int run_tor_main_loop(void); +void pubsub_install(void); +void pubsub_connect(void); + #endif /* !defined(TOR_MAIN_H) */ diff --git a/src/app/main/ntmain.c b/src/app/main/ntmain.c index f00b712702..c5a8122030 100644 --- a/src/app/main/ntmain.c +++ b/src/app/main/ntmain.c @@ -283,7 +283,9 @@ nt_service_body(int argc, char **argv) return; } + pubsub_install(); r = tor_init(backup_argc, backup_argv); + if (r) { /* Failed to start the Tor service */ r = NT_SERVICE_ERROR_TORINIT_FAILED; @@ -294,6 +296,8 @@ nt_service_body(int argc, char **argv) return; } + pubsub_connect(); + /* Set the service's status to SERVICE_RUNNING and start the main * event loop */ service_status.dwCurrentState = SERVICE_RUNNING; @@ -322,9 +326,12 @@ nt_service_main(void) errmsg = format_win32_error(result); printf("Service error %d : %s\n", (int) result, errmsg); tor_free(errmsg); + + pubsub_install(); if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { if (tor_init(backup_argc, backup_argv)) return; + pubsub_connect(); switch (get_options()->command) { case CMD_RUN_TOR: run_tor_main_loop(); -- cgit v1.2.3-54-g00ecf From 6b1592b56439ddbb9e47444f77de2d03429cc0ff Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 13 Jan 2020 16:17:51 -0500 Subject: test_practracker.sh: never disable practracker When practracker is disabled, its output will be empty. We don't want that happening during our tests. Fixes bug 32705; bugfix on 0.4.2.1-alpha, when test_practracker.sh was introduced. --- changes/ticket32705_disable | 4 ++++ scripts/maint/practracker/test_practracker.sh | 1 + 2 files changed, 5 insertions(+) create mode 100644 changes/ticket32705_disable (limited to 'changes') diff --git a/changes/ticket32705_disable b/changes/ticket32705_disable new file mode 100644 index 0000000000..1da643175f --- /dev/null +++ b/changes/ticket32705_disable @@ -0,0 +1,4 @@ + o Minor bugfixes (testing): + - When TOR_DISABLE_PRACTRACKER is set, do not apply it to the + test_practracker.sh script. Doing so caused a test failure. + Fixes bug 32705; bugfix on 0.4.2.1-alpha. diff --git a/scripts/maint/practracker/test_practracker.sh b/scripts/maint/practracker/test_practracker.sh index 9b107e071d..207a5ceded 100755 --- a/scripts/maint/practracker/test_practracker.sh +++ b/scripts/maint/practracker/test_practracker.sh @@ -1,6 +1,7 @@ #!/bin/sh umask 077 +unset TOR_DISABLE_PRACTRACKER TMPDIR="" clean () { -- cgit v1.2.3-54-g00ecf From 7e111d0eaa05d5099d101e82afa1709438fe994e Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 14 Jan 2020 17:32:11 +1000 Subject: practracker: print a notice to stderr when disabled When TOR_DISABLE_PRACTRACKER is set, print a message to stderr when skipping practracker checks. Part of 32705. --- changes/ticket32705_disable | 3 +++ scripts/maint/practracker/practracker.py | 2 ++ 2 files changed, 5 insertions(+) (limited to 'changes') diff --git a/changes/ticket32705_disable b/changes/ticket32705_disable index 1da643175f..6d5b0779ab 100644 --- a/changes/ticket32705_disable +++ b/changes/ticket32705_disable @@ -2,3 +2,6 @@ - When TOR_DISABLE_PRACTRACKER is set, do not apply it to the test_practracker.sh script. Doing so caused a test failure. Fixes bug 32705; bugfix on 0.4.2.1-alpha. + - When TOR_DISABLE_PRACTRACKER is set, log a notice to stderr + when skipping practracker checks. + Fixes bug 32705; bugfix on 0.4.2.1-alpha. diff --git a/scripts/maint/practracker/practracker.py b/scripts/maint/practracker/practracker.py index f6aac9d15e..71741265f6 100755 --- a/scripts/maint/practracker/practracker.py +++ b/scripts/maint/practracker/practracker.py @@ -297,5 +297,7 @@ variable. if __name__ == '__main__': if os.environ.get("TOR_DISABLE_PRACTRACKER"): + print("TOR_DISABLE_PRACTRACKER is set, skipping practracker tests.", + file=sys.stderr) sys.exit(0) main(sys.argv) -- cgit v1.2.3-54-g00ecf From 7bd671811ec38e8126ffc17cb922f2397c572cda Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 30 Jan 2020 09:29:07 -0500 Subject: Rewrite control_event_signal() to use signal_table. When we added the ACTIVE and DORMANT virtual signals, we taught the signal command to handle them, but we didn't teach SIGNAL event to report them. To solve this problem and prevent it from recurring, this patch revises the implementation of control_event_signal() to use the same signal_table that handle_control_signal() uses. This way, the two controller commands can't become out of sync. Fixes bug 33104; bugfix on 0.4.0.1-alpha. --- changes/bug33104 | 4 ++++ src/feature/control/control.c | 4 ++++ src/feature/control/control_events.c | 32 ++++++++++---------------------- 3 files changed, 18 insertions(+), 22 deletions(-) create mode 100644 changes/bug33104 (limited to 'changes') diff --git a/changes/bug33104 b/changes/bug33104 new file mode 100644 index 0000000000..b5478df108 --- /dev/null +++ b/changes/bug33104 @@ -0,0 +1,4 @@ + o Minor bugfixes (controller): + - When receiving "ACTIVE" or "DORMANT" signals on the control port, + report them as SIGNAL events. Fixes bug 33104; bugfix on + 0.4.0.1-alpha. diff --git a/src/feature/control/control.c b/src/feature/control/control.c index 436bf423cf..71b864751f 100644 --- a/src/feature/control/control.c +++ b/src/feature/control/control.c @@ -158,6 +158,10 @@ control_ports_write_to_file(void) } const struct signal_name_t signal_table[] = { + /* NOTE: this table is used for handling SIGNAL commands and generating + * SIGNAL events. Order is significant: if there are two entries for the + * same numeric signal, the first one is the canonical name generated + * for the events. */ { SIGHUP, "RELOAD" }, { SIGHUP, "HUP" }, { SIGINT, "SHUTDOWN" }, diff --git a/src/feature/control/control_events.c b/src/feature/control/control_events.c index 9e0966ca54..1089b608b7 100644 --- a/src/feature/control/control_events.c +++ b/src/feature/control/control_events.c @@ -1552,29 +1552,17 @@ control_event_signal(uintptr_t signal_num) if (!control_event_is_interesting(EVENT_GOT_SIGNAL)) return 0; - switch (signal_num) { - case SIGHUP: - signal_string = "RELOAD"; + for (unsigned i = 0; signal_table[i].signal_name != NULL; ++i) { + if ((int)signal_num == signal_table[i].sig) { + signal_string = signal_table[i].signal_name; break; - case SIGUSR1: - signal_string = "DUMP"; - break; - case SIGUSR2: - signal_string = "DEBUG"; - break; - case SIGNEWNYM: - signal_string = "NEWNYM"; - break; - case SIGCLEARDNSCACHE: - signal_string = "CLEARDNSCACHE"; - break; - case SIGHEARTBEAT: - signal_string = "HEARTBEAT"; - break; - default: - log_warn(LD_BUG, "Unrecognized signal %lu in control_event_signal", - (unsigned long)signal_num); - return -1; + } + } + + if (signal_string == NULL) { + log_warn(LD_BUG, "Unrecognized signal %lu in control_event_signal", + (unsigned long)signal_num); + return -1; } send_control_event(EVENT_GOT_SIGNAL, "650 SIGNAL %s\r\n", -- cgit v1.2.3-54-g00ecf From 2a1f8ea2e78486966c71762ebc3286f2b3e531ff Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 30 Jan 2020 09:43:34 -0500 Subject: Do not set "once" when calling tor_bug_occurred_ from BUG(). The "once" flag makes tor_bug_occurred_() say that future instances of the warning will be suppressed -- but that's not something that BUG() does. Fixes bug 33095; bugfix on 0.4.1.1-alpha. --- changes/bug33095_041 | 5 +++++ src/lib/log/util_bug.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changes/bug33095_041 (limited to 'changes') diff --git a/changes/bug33095_041 b/changes/bug33095_041 new file mode 100644 index 0000000000..7d1f04e279 --- /dev/null +++ b/changes/bug33095_041 @@ -0,0 +1,5 @@ + o Minor bugfixes (logging, bug reporting): + - When logging a bug, do not say "Future instances of this warning + will be silenced" unless we are actually going to do + so. Previously we would say this whenever a BUG() check failed in + the code. Fixes bug 33095; bugfix on 0.4.1.1-alpha. diff --git a/src/lib/log/util_bug.h b/src/lib/log/util_bug.h index 546ae1e3ef..f67c1e995f 100644 --- a/src/lib/log/util_bug.h +++ b/src/lib/log/util_bug.h @@ -196,7 +196,7 @@ STMT_END #define BUG(cond) \ (ASSERT_PREDICT_UNLIKELY_(cond) ? \ - (tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",1,NULL),1) \ + (tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",0,NULL),1) \ : 0) #endif /* defined(ALL_BUGS_ARE_FATAL) || ... */ -- cgit v1.2.3-54-g00ecf From 6d9113d2f65b6e3142efdaa91a5b4761cd197be8 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 28 Jan 2020 09:39:09 -0500 Subject: dirauth: Resume sending 503 directory error code Authorities were never sending back 503 error code because by design they should be able to always answer directory requests regardless of bandwidth capacity. However, that recently backfired because of a large number of requests from unknown source using the DirPort that are _not_ getting their 503 code which overloaded the DirPort leading to the authority to be unable to answer to its fellow authorities. This is not a complete solution to the problem but it will help ease off the load on the authority side by sending back 503 codes *unless* the connection is from a known relay or an authority. Fixes #33029 Signed-off-by: David Goulet --- changes/ticket33029 | 5 +++++ src/core/mainloop/connection.c | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 changes/ticket33029 (limited to 'changes') diff --git a/changes/ticket33029 b/changes/ticket33029 new file mode 100644 index 0000000000..c32ee4ad84 --- /dev/null +++ b/changes/ticket33029 @@ -0,0 +1,5 @@ + o Major bugfixes (directory authority): + - Directory authorities will now send a 503 (not enough bandwidth) code to + clients when under bandwidth pressure. Known relays and other authorities + will always be answered regardless of the bandwidth situation. Fixes bug + 33029; bugfix on 0.1.2.5-alpha. diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c index a157c0f3fb..50cd3810a4 100644 --- a/src/core/mainloop/connection.c +++ b/src/core/mainloop/connection.c @@ -3211,8 +3211,21 @@ connection_dir_is_global_write_low(const connection_t *conn, size_t attempt) size_t smaller_bucket = MIN(token_bucket_rw_get_write(&global_bucket), token_bucket_rw_get_write(&global_relayed_bucket)); - if (authdir_mode(get_options())) - return false; /* there's always room to answer v2 if we're an auth dir */ + + /* Special case for authorities (directory only). */ + if (authdir_mode_v3(get_options())) { + /* Are we configured to possibly reject requests under load? */ + if (!get_options()->AuthDirRejectRequestsUnderLoad) { + /* Answer request no matter what. */ + return false; + } + /* Always answer requests from a known relay which includes the other + * authorities. The following looks up the addresses for relays that we + * have their descriptor _and_ any configured trusted directories. */ + if (nodelist_probably_contains_address(&conn->addr)) { + return false; + } + } if (!connection_is_rate_limited(conn)) return false; /* local conns don't get limited */ -- cgit v1.2.3-54-g00ecf From c8242e4c0ae838121ed00d5a38cf0dae052e9d13 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 12 Feb 2020 12:47:15 +1000 Subject: err/log: Stop closing stderr and stdout during shutdown Closing these file descriptors can hide sanitiser logs. Fixes bug 33087; bugfix on 0.4.1.6. --- changes/bug33087 | 4 ++++ src/lib/err/torerr.c | 31 ++----------------------------- src/lib/err/torerr.h | 1 - src/lib/err/torerr_sys.c | 5 +---- src/lib/log/log.c | 36 +++--------------------------------- src/lib/log/log.h | 1 - src/lib/log/util_bug.c | 4 +--- 7 files changed, 11 insertions(+), 71 deletions(-) create mode 100644 changes/bug33087 (limited to 'changes') diff --git a/changes/bug33087 b/changes/bug33087 new file mode 100644 index 0000000000..7acf72a835 --- /dev/null +++ b/changes/bug33087 @@ -0,0 +1,4 @@ + o Minor bugfixes (logging): + - Stop closing stderr and stdout during shutdown. Closing these file + descriptors can hide sanitiser logs. + Fixes bug 33087; bugfix on 0.4.1.6. diff --git a/src/lib/err/torerr.c b/src/lib/err/torerr.c index b7e32a3e20..5095c28ba9 100644 --- a/src/lib/err/torerr.c +++ b/src/lib/err/torerr.c @@ -150,32 +150,6 @@ tor_log_reset_sigsafe_err_fds(void) tor_log_set_sigsafe_err_fds(fds, 1); } -/** - * Close the list of fds that get errors from inside a signal handler or - * other emergency condition. These fds are shared with the logging code: - * closing them flushes the log buffers, and prevents any further logging. - * - * This function closes stderr, so it should only be called immediately before - * process shutdown. - */ -void -tor_log_close_sigsafe_err_fds(void) -{ - int n_fds, i; - const int *fds = NULL; - - n_fds = tor_log_get_sigsafe_err_fds(&fds); - for (i = 0; i < n_fds; ++i) { - /* tor_log_close_sigsafe_err_fds_on_error() is called on error and on - * shutdown, so we can't log or take any useful action if close() - * fails. */ - (void)close(fds[i]); - } - - /* Don't even try logging, we've closed all the log fds. */ - tor_log_set_sigsafe_err_fds(NULL, 0); -} - /** * Set the granularity (in ms) to use when reporting fatal errors outside * the logging system. @@ -217,13 +191,12 @@ tor_raw_assertion_failed_msg_(const char *file, int line, const char *expr, /** * Call the abort() function to kill the current process with a fatal - * error. But first, close the raw error file descriptors, so error messages - * are written before process termination. + * error. This is a separate function, so that log users don't have to include + * the header for abort(). **/ void tor_raw_abort_(void) { - tor_log_close_sigsafe_err_fds(); abort(); } diff --git a/src/lib/err/torerr.h b/src/lib/err/torerr.h index 0e839cb1ba..a1822d9c9a 100644 --- a/src/lib/err/torerr.h +++ b/src/lib/err/torerr.h @@ -40,7 +40,6 @@ void tor_log_err_sigsafe(const char *m, ...); int tor_log_get_sigsafe_err_fds(const int **out); void tor_log_set_sigsafe_err_fds(const int *fds, int n); void tor_log_reset_sigsafe_err_fds(void); -void tor_log_close_sigsafe_err_fds(void); void tor_log_sigsafe_err_set_granularity(int ms); void tor_raw_abort_(void) ATTR_NORETURN; diff --git a/src/lib/err/torerr_sys.c b/src/lib/err/torerr_sys.c index a14c46f945..6a51a45a4d 100644 --- a/src/lib/err/torerr_sys.c +++ b/src/lib/err/torerr_sys.c @@ -27,11 +27,8 @@ subsys_torerr_initialize(void) static void subsys_torerr_shutdown(void) { - /* Stop handling signals with backtraces, then close the logs. */ + /* Stop handling signals with backtraces. */ clean_up_backtrace_handler(); - /* We can't log any log messages after this point: we've closed all the log - * fds, including stdio. */ - tor_log_close_sigsafe_err_fds(); } const subsys_fns_t sys_torerr = { diff --git a/src/lib/log/log.c b/src/lib/log/log.c index ec7c2fa24e..69624e9cac 100644 --- a/src/lib/log/log.c +++ b/src/lib/log/log.c @@ -668,12 +668,8 @@ tor_log_update_sigsafe_err_fds(void) /* log_fds and err_fds contain matching entries: log_fds are the fds used by * the log module, and err_fds are the fds used by the err module. - * For stdio logs, the log_fd and err_fd values are identical, - * and the err module closes the fd on shutdown. - * For file logs, the err_fd is a dup() of the log_fd, - * and the log and err modules both close their respective fds on shutdown. - * (Once all fds representing a file are closed, the underlying file is - * closed.) + * For stdio logs, the log_fd and err_fd values are identical. + * For file logs, the err_fd is a dup() of the log_fd. */ int log_fds[TOR_SIGSAFE_LOG_MAX_FDS]; int err_fds[TOR_SIGSAFE_LOG_MAX_FDS]; @@ -704,12 +700,10 @@ tor_log_update_sigsafe_err_fds(void) log_fds[n_fds] = lf->fd; if (lf->needs_close) { /* File log fds are duplicated, because close_log() closes the log - * module's fd, and tor_log_close_sigsafe_err_fds() closes the err * module's fd. Both refer to the same file. */ err_fds[n_fds] = dup(lf->fd); } else { - /* stdio log fds are not closed by the log module. - * tor_log_close_sigsafe_err_fds() closes stdio logs. */ + /* stdio log fds are not closed by the log module. */ err_fds[n_fds] = lf->fd; } n_fds++; @@ -838,30 +832,6 @@ logs_free_all(void) * log mutex. */ } -/** Close signal-safe log files. - * Closing the log files makes the process and OS flush log buffers. - * - * This function is safe to call from a signal handler. It should only be - * called when shutting down the log or err modules. It is currenly called - * by the err module, when terminating the process on an abnormal condition. - */ -void -logs_close_sigsafe(void) -{ - logfile_t *victim, *next; - /* We can't LOCK_LOGS() in a signal handler, because it may call - * signal-unsafe functions. And we can't deallocate memory, either. */ - next = logfiles; - logfiles = NULL; - while (next) { - victim = next; - next = next->next; - if (victim->needs_close) { - close_log_sigsafe(victim); - } - } -} - /** Remove and free the log entry victim from the linked-list * logfiles (it is probably present, but it might not be due to thread * racing issues). After this function is called, the caller shouldn't diff --git a/src/lib/log/log.h b/src/lib/log/log.h index 4291418eb6..c4a27782c3 100644 --- a/src/lib/log/log.h +++ b/src/lib/log/log.h @@ -173,7 +173,6 @@ void logs_set_domain_logging(int enabled); int get_min_log_level(void); void switch_logs_debug(void); void logs_free_all(void); -void logs_close_sigsafe(void); void add_temp_log(int min_severity); void close_temp_logs(void); void rollback_log_changes(void); diff --git a/src/lib/log/util_bug.c b/src/lib/log/util_bug.c index 0e99be35a4..640fe050e6 100644 --- a/src/lib/log/util_bug.c +++ b/src/lib/log/util_bug.c @@ -163,8 +163,7 @@ tor_bug_occurred_(const char *fname, unsigned int line, /** * Call the tor_raw_abort_() function to close raw logs, then kill the current - * process with a fatal error. But first, close the file-based log file - * descriptors, so error messages are written before process termination. + * process with a fatal error. * * (This is a separate function so that we declare it in util_bug.h without * including torerr.h in all the users of util_bug.h) @@ -172,7 +171,6 @@ tor_bug_occurred_(const char *fname, unsigned int line, void tor_abort_(void) { - logs_close_sigsafe(); tor_raw_abort_(); } -- cgit v1.2.3-54-g00ecf From 80e3dc47272c9ba423d40ce367fb99d39c3150ec Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 12 Feb 2020 14:17:19 -0500 Subject: Use more memory poisoning and better asserts around ewma code Attempt to diagnose 32464; fixes 33290. --- changes/ticket33290 | 4 ++++ src/core/or/circuitmux.c | 8 ++++++-- src/core/or/circuitmux_ewma.c | 11 ++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 changes/ticket33290 (limited to 'changes') diff --git a/changes/ticket33290 b/changes/ticket33290 new file mode 100644 index 0000000000..882764020e --- /dev/null +++ b/changes/ticket33290 @@ -0,0 +1,4 @@ + o Minor features (diagnostic): + - Improve assertions and add some memory-poisoning code to try to track + down possible causes of a rare crash (32564) in the EWMA code. + Closes ticket 33290. diff --git a/src/core/or/circuitmux.c b/src/core/or/circuitmux.c index b2628bec3f..72f6ba662b 100644 --- a/src/core/or/circuitmux.c +++ b/src/core/or/circuitmux.c @@ -79,6 +79,8 @@ #include "core/or/destroy_cell_queue_st.h" #include "core/or/or_circuit_st.h" +#include "lib/crypt_ops/crypto_util.h" + /* * Private typedefs for circuitmux.c */ @@ -973,7 +975,10 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ)) /* Now remove it from the map */ HT_REMOVE(chanid_circid_muxinfo_map, cmux->chanid_circid_map, hashent); - /* Free the hash entry */ + /* Wipe and free the hash entry */ + // This isn't sensitive, but we want to be sure to know if we're accessing + // this accidentally. + memwipe(hashent, 0xef, sizeof(hashent)); tor_free(hashent); } } @@ -1334,4 +1339,3 @@ circuitmux_compare_muxes, (circuitmux_t *cmux_1, circuitmux_t *cmux_2)) return 0; } } - diff --git a/src/core/or/circuitmux_ewma.c b/src/core/or/circuitmux_ewma.c index 3f83c3fd5a..606b755e28 100644 --- a/src/core/or/circuitmux_ewma.c +++ b/src/core/or/circuitmux_ewma.c @@ -147,7 +147,9 @@ TO_EWMA_POL_DATA(circuitmux_policy_data_t *pol) { if (!pol) return NULL; else { - tor_assert(pol->magic == EWMA_POL_DATA_MAGIC); + tor_assertf(pol->magic == EWMA_POL_DATA_MAGIC, + "Mismatch: %"PRIu32" != %"PRIu32, + pol->magic, EWMA_POL_DATA_MAGIC); return DOWNCAST(ewma_policy_data_t, pol); } } @@ -162,7 +164,9 @@ TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *pol) { if (!pol) return NULL; else { - tor_assert(pol->magic == EWMA_POL_CIRC_DATA_MAGIC); + tor_assertf(pol->magic == EWMA_POL_CIRC_DATA_MAGIC, + "Mismatch: %"PRIu32" != %"PRIu32, + pol->magic, EWMA_POL_CIRC_DATA_MAGIC); return DOWNCAST(ewma_policy_circ_data_t, pol); } } @@ -295,6 +299,7 @@ ewma_free_cmux_data(circuitmux_t *cmux, pol = TO_EWMA_POL_DATA(pol_data); smartlist_free(pol->active_circuit_pqueue); + pol->base_.magic = 0xDEAD901C; tor_free(pol); } @@ -361,7 +366,7 @@ ewma_free_circ_data(circuitmux_t *cmux, if (!pol_circ_data) return; cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data); - + cdata->base_.magic = 0xDEADC14C; tor_free(cdata); } -- cgit v1.2.3-54-g00ecf From 78bcfc1280b322ba57a10a116457616eeb742ab6 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 14 Mar 2020 14:44:33 -0400 Subject: circpad_setup_machine_on_circ(): exit early on error. This function does a nonfatal assertion to make sure that a machine is not registered twice, but Tobias Pulls found a case where it happens. Instead, make the function exit early so that it doesn't cause a remotely triggered memory leak. Fixes bug 33619; bugfix on 0.4.0.1-alpha. This is also tracked as TROVE-2020-004. --- changes/ticket33619 | 5 +++++ src/core/or/circuitpadding.c | 9 ++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 changes/ticket33619 (limited to 'changes') diff --git a/changes/ticket33619 b/changes/ticket33619 new file mode 100644 index 0000000000..3c52858b35 --- /dev/null +++ b/changes/ticket33619 @@ -0,0 +1,5 @@ + o Major bugfixes (circuit padding, memory leaks): + - Avoid a remotely triggered memory leak in the case that a circuit + padding machine is somehow negotiated twice on the same circuit. Fixes + bug 33619; bugfix on 0.4.0.1-alpha. Found by Tobias Pulls. This is + also tracked as TROVE-2020-004. diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c index a62cdcf9e6..72b770113c 100644 --- a/src/core/or/circuitpadding.c +++ b/src/core/or/circuitpadding.c @@ -2381,9 +2381,12 @@ circpad_setup_machine_on_circ(circuit_t *on_circ, return; } - tor_assert_nonfatal(on_circ->padding_machine[machine->machine_index] - == NULL); - tor_assert_nonfatal(on_circ->padding_info[machine->machine_index] == NULL); + IF_BUG_ONCE(on_circ->padding_machine[machine->machine_index] != NULL) { + return; + } + IF_BUG_ONCE(on_circ->padding_info[machine->machine_index] != NULL) { + return; + } /* Log message */ if (CIRCUIT_IS_ORIGIN(on_circ)) { -- cgit v1.2.3-54-g00ecf From ee3e987898a1e656950aabf8bf0a99aed1450a98 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 17 Mar 2020 10:14:57 -0400 Subject: sendme: Emit version 1 by default Closes #33623 Signed-off-by: David Goulet --- changes/ticket33623 | 2 ++ src/core/or/sendme.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 changes/ticket33623 (limited to 'changes') diff --git a/changes/ticket33623 b/changes/ticket33623 new file mode 100644 index 0000000000..528af3ca02 --- /dev/null +++ b/changes/ticket33623 @@ -0,0 +1,2 @@ + o Minor feature (sendme, flow control): + - Default on sending SENDME version 1 cells. Closes ticket 33623. diff --git a/src/core/or/sendme.h b/src/core/or/sendme.h index 20477103fd..9d757ee435 100644 --- a/src/core/or/sendme.h +++ b/src/core/or/sendme.h @@ -48,7 +48,7 @@ void sendme_record_sending_cell_digest(circuit_t *circ, crypt_path_t *cpath); #define SENDME_MAX_SUPPORTED_VERSION 1 /* The cell version constants for when emitting a cell. */ -#define SENDME_EMIT_MIN_VERSION_DEFAULT 0 +#define SENDME_EMIT_MIN_VERSION_DEFAULT 1 #define SENDME_EMIT_MIN_VERSION_MIN 0 #define SENDME_EMIT_MIN_VERSION_MAX UINT8_MAX -- cgit v1.2.3-54-g00ecf From d7e166bd95411d3f5caa573e0293356bff78c481 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 30 Apr 2020 22:56:31 -0400 Subject: Fix a GCC 10.0.1 compilation warning. Fixes 34077 for 0.4.1; bugfix on 0.4.0.3-alpha. (Specifically, GCC first gives this warning for 9eeff921ae7b786d960ea4286d5bba56) --- changes/bug34077 | 3 +++ src/feature/dirauth/shared_random_state.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 changes/bug34077 (limited to 'changes') diff --git a/changes/bug34077 b/changes/bug34077 new file mode 100644 index 0000000000..29458bd9de --- /dev/null +++ b/changes/bug34077 @@ -0,0 +1,3 @@ + o Minor bugfixes (compiler warnings): + - Fix compilation warnings with GCC 10.0.1. Fixes bug 34077; bugfix on + 0.4.0.3-alpha. diff --git a/src/feature/dirauth/shared_random_state.c b/src/feature/dirauth/shared_random_state.c index b669e3836e..58c203e204 100644 --- a/src/feature/dirauth/shared_random_state.c +++ b/src/feature/dirauth/shared_random_state.c @@ -1057,8 +1057,9 @@ sr_state_set_valid_after(time_t valid_after) sr_phase_t sr_state_get_phase(void) { - void *ptr; + void *ptr=NULL; state_query(SR_STATE_ACTION_GET, SR_STATE_OBJ_PHASE, NULL, &ptr); + tor_assert(ptr); return *(sr_phase_t *) ptr; } -- cgit v1.2.3-54-g00ecf